Extension:AutomaticCAS USER

From MediaWiki.org
Jump to: navigation, search
MediaWiki extensions manual
Crystal Clear action run.png
Automatic CAS Authentication

Release status: beta

Implementation User identity
Description Automatically logs users using CAS Server. Also, a Single sign out is configurable.
Author(s) Ramon Perez, iEcolab
Latest version 1.0
MediaWiki 1.9 or later
License GPLv2
Download see below

Translate the AutomaticCAS USER extension if possible

Check usage and version matrix; code metrics

Automatic CAS Authentication extension automatically logs users using the CAS Server. It is possible to do a single sign out configuration.


Save the file as /extensions/Auth_cas/Auth_cas.php
Download phpCAS library and save in /extensions/Auth_cas. So, you can download a package with all files in iEcolab


Then place the following two lines in your LocalSettings.php file:

require_once('extensions/Auth_cas/Auth_cas.php');
$wgAuth = new Auth_cas();

Note: Using this extension sets $wgMinimalPasswordLength to zero

Code[edit | edit source]

<?php
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Copyright 2010 Ramon Perez
//
// In 2009, the copyright holders determined that the original publishing of this code
// under GPLv3 was legally and logistically in error, and re-licensed it under GPLv2.
//
// See http://www.mediawiki.org/wiki/Extension:AutomaticCAS_USER
//
// Adapted by Rusty (REMOTE_USER) to do a CAS Authentication for USER. 
//
// Add these lines to your LocalSettings.php
// /* This is required for Auth_cas operation
// require_once('extensions/Auth_cas.php');
// $wgAuth = new Auth_cas();
//
// The constructor of Auth_cas registers a hook to do the automatic
// login.  Storing the Auth_cas object in $wgAuth tells mediawiki to use
// that object as the AuthPlugin.  This way the login attempts by the hook will
// be handled by us.
//
 
//Extension credits that show up on Special:Version
$wgExtensionCredits['other'][] = array(
	'name' => 'Authenticate with CAS Server',
	'version' => '1.0',
	'author' => array('Ramón Pérez'),
	'url' => 'http://www.mediawiki.org/wiki/Extension:AutomaticCAS_USER',
'description' => 'Authenticate for user with a CAS Server.',
	);
 
 
// Setup hooks
global $wgHooks;
$wgHooks["UserLogoutComplete"][] = "casLogout";
 
//--------------------------------------------------------------------------
// Configuration Variables
//--------------------------------------------------------------------------
 
$CASAuth = array(
	"phpCAS"         => "$IP/extensions/CASAuth", // Path to phpCAS directory.
"Server"         => "login.example.es",        // Address to CAS server.
"Port"           => 443,                          // Port to CAS server. Default: 443.
"Url"            => "",              // Subdir to CAS authentication.
"Version"        => "2.0",                        // CAS version, should be either 1.0 or 2.0.
"PwdSecret"      => "a letters", // A random string that is used when generating the MediaWiki password for this user. YOU SHOULD EDIT THIS TO A VRY RANDOM STRING! YOU SHOULD ALSO KEEP THIS A SECRET!
"logoutCAS"		=> array("server1", "server2"),
	);
 
//this is necessary to catch the logout request from CAS Server
 
include_once($CASAuth["phpCAS"]."/CAS.php");
 
phpCAS::setDebug();
phpCAS::client($CASAuth["Version"], $CASAuth["Server"], $CASAuth["Port"], $CASAuth["Url"]);
phpCAS::setNoCasServerValidation();
 
if ($_REQUEST['service']) :
phpCAS::setFixedServiceURL(urlencode($_REQUEST['service']));
endif;
 
phpCAS::handleLogoutRequests(true, $CASAuth["logoutCAS"]);
 
//Check if the user is authenticate
phpCAS::CheckAuthentication();
 
// The Auth_cas class is an AuthPlugin so make sure we have this
// included.
require_once('AuthPlugin.php');
 
/**
* This hook is registered by the Auth_cas constructor.  It will be
* called on every page load.  It serves the function of automatically logging
* in the user.  The Auth_cas class is an AuthPlugin and handles the
* actual authentication, user creation, etc.
*
*/
function Auth_cas_user_hook() {
	global $wgUser;
	global $wgRequest;
	global $_REQUEST;
	global $wgAuthRemoteuserDomain;
 
	// For a few special pages, don't do anything.
	$title = $wgRequest->getVal('title');	
	if ($title == Title::makeName(NS_SPECIAL, 'Userlogout')) {
		wfDebugLog('CASAuth', 'Logout request');		
		return;
	}
 
	//If you want more method to login a user, comment this if.
	//When the requested page is UserLogin, we force to register in CAS Server.
	if 	($title == Title::makeName(NS_SPECIAL, 'Userlogin')){
		wfDebugLog('CASAuth', 'Login request');
 
		phpCAS::forceAuthentication(); //Will redirect to CAS server if not logged in
 
		wfDebugLog('CASAuth', 'User authenticate in CAS Server');
 
		$returnto = "Portada";  //Name of principal page
		$target = Title::newFromText($returnto);
		wfDebugLog('CASAuth', 'redirect to main page');		
		global $wgOut;
		$wgOut->redirect($target->getFullUrl());				
	}
 
 
	// Do nothing if session is valid	
	$user = User::newFromSession();
	if ((!$user->isAnon()) && (phpCAS::isSessionAuthenticated())) {
		wfDebugLog('CASAuth', 'User is not anonymous');		
		return;  // User is already logged in and not anonymous.
	}else{
		wfDebugLog('CASAuth', 'User is anonymous or he is not authenticated in CAS Server');		
		//if it is not anonymous, we have to logout the user, because logout in another application. Single sign out.
		if (!$user->isAnon()){
			wfDebugLog('CASAuth', 'Logout user, because');					
			global $wgUser;
			$wgUser->doLogout();			
			return;		
		}			
 
	}
 
	// Copied from includes/SpecialUserlogin.php
	if(!isset($wgCommandLineMode) && !isset($_COOKIE[session_name()])) {
		wfSetupSession();
	}
 
	wfDebugLog('CASAuth', 'Check if there is a user authenticate in CAS Server');
 
	if (phpCAS::isSessionAuthenticated()){
		//gets the data about user in CAS Server		
		$email = phpCAS::getUser();
 
		//Gets the extra attributes send by CAS Server
		$extra_attributes = phpCAS::getAttributes();
 
			// Submit a fake login form to authenticate the user.
			$params = new FauxRequest(array(
				'wpName' => $extra_attributes["login"],
				'wpPassword' => '',
				'wpDomain' => '',
				'wpRemember' => ''
				));
 
			$loginForm = new LoginForm($params);
			$result = $loginForm->authenticateUserData();
			switch ($result) {
				case LoginForm :: SUCCESS :
				$wgUser->setOption('rememberpassword', 1);
				$wgUser->setCookies();
				break;
				case LoginForm :: NO_NAME :
				$errormessage = 'NoName';
				break;
				case LoginForm :: ILLEGAL :
				$errormessage = 'Illegal';
				break;
				case LoginForm :: WRONG_PLUGIN_PASS :
				$errormessage = 'WrongPluginPass';
				break;
				case LoginForm :: NOT_EXISTS :
				$errormessage = 'NotExists';
				break;
				case LoginForm :: WRONG_PASS :
				$errormessage = 'WrongPass';
				break;
				case LoginForm :: EMPTY_PASS :
				$errormessage = 'EmptyPass';
				break;
				default:
				$errormessage = 'Unknown';
				break;
 
			}
 
			if ($result != LoginForm::SUCCESS) {
				error_log('Unexpected CAS user authentication failure. Login Error was: '.$errormessage);
			}
 
		return;
 
	}
 
}
 
class Auth_cas extends AuthPlugin {
 
	function Auth_cas() {
		// Register our hook function.  This hook will be executed on every page
		// load.  Its purpose is to automatically log the user in, if necessary.
		global $wgExtensionFunctions;
		if (!isset($wgExtensionFunctions)) {
			$wgExtensionFunctions = array();
		}
		else if (!is_array($wgExtensionFunctions)) {
			$wgExtensionFunctions = array( $wgExtensionFunctions );
		}
		array_push($wgExtensionFunctions, 'Auth_cas_user_hook');
		return;
	}
 
	/**
	* Disallow password change.
	*
	* @return bool
	*/
function allowPasswordChange() {
	return false;
}
 
/**
* This should not be called because we do not allow password change.  Always
* fail by returning false.
*
* @param $user User object.
* @param $password String: password.
* @return bool
* @public
*/
function setPassword($user, $password) {
	return false;
}
 
/**
* We don't support this but we have to return true for preferences to save.
*
* @param $user User object.
* @return bool
* @public
*/
function updateExternalDB($user) {
	return true;
}
 
/**
* We can't create external accounts so return false.
*
* @return bool
* @public
*/
function canCreateAccounts() {
	return false;
}
 
/**
* We don't support adding users to whatever service provides REMOTE_USER, so
* fail by always returning false.
*
* @param User $user
* @param string $password
* @return bool
* @public
*/
function addUser($user, $password) {
	return false;
}
 
/**
* Pretend all users exist.  This is checked by authenticateUserData to
* determine if a user exists in our 'db'.  By returning true we tell it that
* it can create a local wiki user automatically.
*
* @param $username String: username.
* @return bool
* @public
*/
function userExists($username) {
	return true;
}
 
/**
* Check whether the given name matches REMOTE_USER.
* The name will be normalized to MediaWiki's requirements, so
* lower it and the REMOTE_USER before checking.
*
* @param $username String: username.
* @param $password String: user password.
* @return bool
* @public
*/
function authenticate($username, $password) {
 
	if (!phpCAS::isSessionAuthenticated()){
		phpCAS::forceAuthentication(); //Will redirect to CAS server if not logged in
		return false;
	}	
 
 
	return true;
}
 
/**
* Check to see if the specific domain is a valid domain.
*
* @param $domain String: authentication domain.
* @return bool
* @public
*/
function validDomain($domain) {
	return true;
}
 
/**
* When a user logs in, optionally fill in preferences and such.
* For instance, you might pull the email address or real name from the
* external user database.
*
* The User object is passed by reference so it can be modified; don't
* forget the & on your function declaration.
*
* @param User $user
* @public
*/
function updateUser(&$user) {
	// We only set this stuff when accounts are created.
	return true;
}
 
/**
* Return true because the wiki should create a new local account
* automatically when asked to login a user who doesn't exist locally but
* does in the external auth database.
*
* @return bool
* @public
*/
function autoCreate() {
	return true;
}
 
/**
* Return true to prevent logins that don't authenticate here from being
* checked against the local database's password fields.
*
* @return bool
* @public
*/
function strict() {
	return true;
}
 
/**
* When creating a user account, optionally fill in preferences and such.
* For instance, you might pull the email address or real name from the
* external user database.
*
* @param $user User object.
* @public
*/
function initUser(&$user) {
 
	//get parameters from cas server
	$email = phpCAS::getUser();
	$extra_attributes = phpCAS::getAttributes();
 
	$username = $extra_attributtes["login"];
	$user->setRealName($extra_attributes["name"]);
	$user->setEmail($email);
	$user->mEmailAuthenticated = wfTimestampNow();
	$user->setToken();
 
	//turn on e-mail notifications
	if (isset($wgAuthRemoteuserNotify) && $wgAuthRemoteuserNotify) {
		$user->setOption('enotifwatchlistpages', 1);
		$user->setOption('enotifusertalkpages', 1);
		$user->setOption('enotifminoredits', 1);
		$user->setOption('enotifrevealaddr', 1);
	}
 
	$user->saveSettings();
}
 
/**
* Modify options in the login template.  This shouldn't be very important
* because no one should really be bothering with the login page.
*
* @param $template UserLoginTemplate object.
* @public
*/
function modifyUITemplate(&$template) {
	//disable the mail new password box
	$template->set('useemail', false);
	//disable 'remember me' box
	$template->set('remember', false);
	$template->set('create', false);
	$template->set('domain', false);
	$template->set('usedomain', false);
}
 
/**
* Normalize user names to the MediaWiki standard to prevent duplicate
* accounts.
*
* @param $username String: username.
* @return string
* @public
*/
function getCanonicalName($username) {
	// lowercase the username
	$username = strtolower($username);
	// uppercase first letter to make MediaWiki happy
	$username = ucfirst($username);
	return $username;
}
}
 
// Function to logout in mediawiki and CAS Server
function casLogout() {
	global $CASAuth;
	global $wgUser, $wgRequest;
 
	// Logout from MediaWiki
	$wgUser->doLogout();
 
	// Get returnto value
	$returnto = $wgRequest->getVal("returnto");
	if ($returnto) {
		$target = Title::newFromText($returnto);
		if ($target) {
			$redirecturl = $target->getFullUrl();
		}
	}
 
	if (isset($redirecturl)) {
		phpCAS::logoutWithRedirectServiceAndUrl($redirecturl, $redirecturl);
	}
	else {
		phpCAS::logout();
	}
 
	return true; // We won't get here
}
 
 
 
?>