Ucamwebauth.php v0.3

From RavenWiki
Jump to navigationJump to search
<?php
/*
 * ucamwebauth.php v0.3
 * Tom De Mulder (tdm27), 2007-04-27 
 * Mediawiki extension to work with UcamWebAuth
 * Doesn't require changes to Mediawiki source code
 * Developed/tested against Mediawiki 1.9.3
 * 
 * v0.3: userpage link needs to be lowercase
 * v0.2: the entire site *has* to be protected by Raven 
 */

// Stop people creating accounts
$wgGroupPermissions['*']['createaccount']   = false;
require_once('AuthPlugin.php');

function SetupUcamWebAuth()
{
        global $wgHooks;
        global $wgAuth;

        $wgHooks['AutoAuthenticate'][] = 'AutoAuth';
        $wgHooks['PersonalUrls'][] = 'KillLogout'; 
        $wgAuth = new UcamWebAuth();
}

// Loosely based on the Shibboleth extension, but with lowercase CRSIDs.
function AutoAuth(&$user)
{
        global $wgAuth;
        global $wgHooks;

        // For versions of mediawiki which enjoy calling AutoAuth with null users
        if ($user === null) {
                $user = User::newFromSession();
        }

        // If they user's already logged in, we don't have to do anything.
        if($user->isLoggedIn())
                return;

        // Is the user already in the database?
	// Dirty hack to get past the fact that CRSIDs are lowercase
	// Code lifted from User::idFromName
 	$dbr =& wfGetDB( DB_SLAVE );
       	$s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $_SERVER['REMOTE_USER'] ), __METHOD__ );
	$camuserid = $s->user_id;
        if ($camuserid != null)
        {
                $user = User::newFromId($camuserid);
                $wgAuth->updateUser($user); //Make sure password is nologin
                $user->SetupSession();
                $user->setCookies();
                return;
        }

        $user->setName($_SERVER['REMOTE_USER']);

        /* 
	 * The loginform is some black magic, which we create and use without the user
	 * ever seeing an actual form. Mediawiki's obscure like that.
         */
        require_once('SpecialUserlogin.php');

        // Silly Mediawiki hack
        global $wgLang;
        global $wgContLang;
        global $wgRequest;
        if(!isset($wgLang))
        {
                $wgLang = $wgContLang;
                $wgLangUnset = true;
        }

        //Temporarily kill The AutoAuth Hook to prevent recursion
        foreach ($wgHooks['AutoAuthenticate'] as $key => $value)
        {
                if($value == 'AutoAuth')
                    $wgHooks['AutoAuthenticate'][$key] = 'BringBackAA';
        }
         
        $lf = new LoginForm($wgRequest);

        // Return the hook (may not be necessary in Mediawiki v1.9+)
        BringBackAA();

        // Clean up the earlier silly hack
        if($wgLangUnset == true)
        {
                unset($wgLang);
                unset($wgLangUnset);
        }

        // Now *do* the black magic
        $lf->mRemember = false;
        $lf->initUser($user);

	// Finish and clean up
        $user->saveSettings();
        $user->setupSession();
        $user->setCookies();
}

// Puts the auto-auth hook back into the hooks array 
// May not be necessary in Mediawiki v1.9+
function BringBackAA()
{
        global $wgHooks;

        foreach ($wgHooks['AutoAuthenticate'] as $key => $value)
        {
            if($value == 'BringBackAA')
                $wgHooks['AutoAuthenticate'][$key] = 'AutoAuth';
        }
}

// Kill logout link. Taken from Shibboleth extension.
// Currently just unsets it - in the long term (Shibboleth) we may want a logout link.
function KillLogout(&$personal_urls, $title)
{
        $personal_urls['logout'] = null;
}


// The following code (inc. comments) is lifted straight from AuthPlugin
// Changes were made where necessary. I'm leaving the comments in for now.
class UcamWebAuth extends AuthPlugin {
	/**
	 * Check whether there exists a uSer account with the given name.
	 * The name will be normalized to MediaWiki's requirements, so
	 * you might need to munge it (for instance, for lowercase initial
	 * letters).
	 *
	 * @param $username String: username.
	 * @return bool
	 * @public
	 */
	function userExists( $username ) {
		$username = $_SERVER['REMOTE_USER']; // Makes no sense. Sorry.
		return true;
	}

	/**
	 * Check if a username+password pair is a valid login.
	 * The name will be normalized to MediaWiki's requirements, so
	 * you might need to munge it (for instance, for lowercase initial
	 * letters).
	 *
	 * @param $username String: username.
	 * @param $password String: user password.
	 * @return bool
	 * @public
	 */
	function authenticate( $username, $password ) {
		return true;
	}

	/**
	 * Modify options in the login template.
	 *
	 * @param $template UserLoginTemplate object.
	 * @public
	 */
	function modifyUITemplate( &$template ) {
		# Override this!
		$template->set( 'usedomain', false );
	}

	/**
	 * Set the domain this plugin is supposed to use when authenticating.
	 *
	 * @param $domain String: authentication domain.
	 * @public
	 */
	function setDomain( $domain ) {
		$this->domain = $domain;
	}

	/**
	 * Check to see if the specific domain is a valid domain.
	 *
	 * @param $domain String: authentication domain.
	 * @return bool
	 * @public
	 */
	function validDomain( $domain ) {
		# Override this!
		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 ) {
		# Override this and do something
		return true;
	}


	/**
	 * Return true if 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.
	 *
	 * If you don't automatically create accounts, you must still create
	 * accounts in some way. It's not possible to authenticate without
	 * a local account.
	 *
	 * This is just a question, and shouldn't perform any actions.
	 *
	 * @return bool
	 * @public
	 */
	function autoCreate() {
		return true;
	}

	/**
	 * Can users change their passwords?
	 *
	 * @return bool
	 */
	function allowPasswordChange() {
		return true;
	}

	/**
	 * Set the given password in the authentication database.
	 * As a special case, the password may be set to null to request
	 * locking the password to an unusable value, with the expectation
	 * that it will be set later through a mail reset or other method.
	 *
	 * Return true if successful.
	 *
	 * @param $user User object.
	 * @param $password String: password.
	 * @return bool
	 * @public
	 */
	function setPassword( $user, $password ) {
		return true;
	}

	/**
	 * Update user information in the external authentication database.
	 * Return true if successful.
	 *
	 * @param $user User object.
	 * @return bool
	 * @public
	 */
	function updateExternalDB( $user ) {
		return true;
	}

	/**
	 * Check to see if external accounts can be created.
	 * Return true if external accounts can be created.
	 * @return bool
	 * @public
	 */
	function canCreateAccounts() {
		return false;
	}

	/**
	 * Add a user to the external authentication database.
	 * Return true if successful.
	 *
	 * @param User $user
	 * @param string $password
	 * @return bool
	 * @public
	 */
	function addUser( $user, $password ) {
		return true;
	}


	/**
	 * Return true to prevent logins that don't authenticate here from being
	 * checked against the local database's password fields.
	 *
	 * This is just a question, and shouldn't perform any actions.
	 *
	 * @return bool
	 * @public
	 */
	function strict() {
		return false;
	}

	/**
	 * 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.
	 *
	 * The User object is passed by reference so it can be modified; don't
	 * forget the & on your function declaration.
	 *
	 * @param $user User object.
	 * @public
	 */
	function initUser( &$user ) {
		# Override this to do something.
	}

	/**
	 * If you want to munge the case of an account name before the final
	 * check, now is your chance.
	 */
	function getCanonicalName( $username ) {
		return strtolower($username);
	}
}

?>