Extension:AutomaticCAS USER

From MediaWiki.org
Jump to: navigation, search

Other languages:
English • ‎español • ‎日本語 • ‎polski
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+
License GNU General Public License 2.0 or later
Download see below

Translate the AutomaticCAS USER extension if it is available at translatewiki.net

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
}

?>