Extension:QISSingleSignOn

From MediaWiki.org

Jump to: navigation, search

           

Manual on MediaWiki Extensions
List of MediaWiki Extensions
Crystal Clear action run.png
QISSingleSignOn

Release status: stable

Implementation  User identity
Description Single Sign On from HISQIS-Portal
Author(s)  Hendrik BrummermannTalk
Last Version  0.4
MediaWiki  1.6 or newer
License CC-BY / GPL
Download see below

check usage (experimental)

[edit] Purpose

Coordinates user authentication with an HISQIS portal (HISQIS is a software used by many German universities to offer campus services).


<?php2
 
// Change Log
// ==========
// 0.4    2008-09-12: support for MediaWiki 1.13 [[de:Benutzer:Hendrik Brummermann]]
// 0.3    2006-05-14: support for AutoAuth-hook on MW 1.6 (fixes returnto-problem and removes the redirect page)
// 0.2    2006-05-07: added support for _ridlist [[de:Benutzer:Hendrik Brummermann]]
// 0.1.3  2005-08-29: added to Special:Version   [[de:Benutzer:Hendrik Brummermann]]
// 0.1.2  2005-08-13: urldecode username token   [[de:Benutzer:Hendrik Brummermann]]
// 0.1.1  2005-05-20: Fixed timeout check        [[de:Benutzer:Hendrik Brummermann]]
// 0.1    2005-05-18: First version              [[de:Benutzer:Hendrik Brummermann]]
 
/**
 * This plugin allows MediaWiki to be part of a single sign on environment.
 *
 *
 * Installation
 * ============
 * - Copy QISSingleSignOn.php (this file) into the extension folder
 * - Add this to your LocalSettings.php:
 *   require_once($IP."/extensions/QISSingleSignOn.php");
 *   $wgAuthQISSingleSignOnSharedSecret = 'kahC1oo3pieg6FaekEhou1aipEivae4fe'; // replace with random characters
 *   $wgAuthQISSingleSignOnService = 'wiki';
 *   $wgAuth = new QISSingleSignOn();
 *
 *
 * Linking the authentication server and MediaWiki
 * ===============================================
 *
 *     MediaWiki 1.6
 *     =============
 *  Create a link to http://example.com/mediawiki/index.php/Main_Page?qisssotoken=
 *  1.0/1115814654/wik/schmidt/d1bf93299de1b68e6d382c893bf1215f (one line). In this
 *  example Main_Page is the name of the page you want to link to and qissotoken
 *  is the authentication token described below.
 *
 *     MediaWiki 1.3 - 1.5
 *     ===================
 *  The authentication server has to create a token for MediaWiki and
 *  transmit it as "password":
 *
 *  action="/mediawiki/index.php?title=Spezial:Userlogin&action=submit&returnto=Main_Page"
 *  wpLoginattempt=Anmelden
 *  wpName=username
 *  wpPassword=1.0/1115814654/wik/schmidt/d1bf93299de1b68e6d382c893bf1215f
 *
 *  You must put this variables into a hidden form because MediaWiki will
 *  only accept POST-requests. This form can be triggered automatically
 *  by JavaScript:
 *  <body onload="document.forms[0].submit();">
 *
 *
 * Details On The Required Token
 * =============================
 *
 * The token look lines this (without spaces):
 *
 *   1.0   / 1115814654 /   wiki     / schmidt / d1bf93299de1b68e6d382c893bf1215f
 * version /   time     / service    /  user   /            hash 
 *
 * The second parameter is is the token creation time measured in the
 * number of seconds since the Unix Epoch (0:00:00 January 1, 1970 GMT).
 * The third token is the name of the destination service as configured in
 * the $wgAuthQISSingleSignOnService option in your LocalSettings.php.
 * The forth token is the user name.
 *
 * A shared secret is added to theses parameters and the md5 hash is
 * calculated. This hash is used to verify the the token has not been
 * manipulated or forged. The shared secret is only known to the
 * authentication server and your MediaWiki installation
 * ($wgAuthQISSingleSignOnSharedSecret in LocalSettings.php).
 * Without the knowledge of the shared secret it is impossible to
 * calculate the correct hash.
 *
 * Please note that the separation of user and hash is not the 4th slash
 * but the last one. (The user name may contain '/'-chars).
 */
 
# This file is based upon a work CC-BY Hendrik Brummermann <nhb_web@nexgo.de>.
# As it must implement a GPLed interface, however, it becomes GPL:
# 
# 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, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html

 
require_once($IP."/includes/AuthPlugin.php");
 
/**
 * Authentication plugin using QISSingleSignOn.
 */
class QISSingleSignOn extends AuthPlugin {
        function userExists( $username ) {
                return true; // We cannot answer this question without the token
        }
 
        /**
         * Check the configuration options
         *
         * @access private
         */
        function checkConfiguration() {
                global $wgAuthQISSingleSignOnSharedSecret, $wgAuthQISSingleSignOnService; 
                if (!isset($wgAuthQISSingleSignOnSharedSecret)) {
                        wfDebugDieBacktrace('QISSingleSignOn: $wgAuthQISSingleSignOnSharedSecret undefined in LocalSettings.php.');
                }
                if (!isset($wgAuthQISSingleSignOnService)) {
                        wfDebugDieBacktrace('QISSingleSignOn: $wgAuthQISSingleSignOnService undefined in LocalSettings.php.');
                }
        }
 
        function authenticate( $username, $password ) {
		$user = $this->verifyToken($password);
		if ($user == null)  {
			// ungueltiges Token
			wfDebug('QISSingleSignOn: Ungueltiges Token');
			return false;
		}
 
		// Stimmt der angegebene username und die Benutzerinformation ueberein
                if ($user != $username) {
                        wfDebug('QISSingleSignOn: Invalid user name:'.htmlspecialchars($token));
                        return false; 
                }
		return true;
	}
 
	function verifyToken($token) {
                global $wgAuthQISSingleSignOnService, $wgAuthQISSingleSignOnSharedSecret;
 
                // check the configuration options in LocalSettings.php
                QISSingleSignOn::checkConfiguration();
 
                wfDebug('QISSingleSignOn: token:'.htmlspecialchars($token));
 
                // prepare token
                $tokens = explode('/', $token, 4);
                if ((count($tokens) != 4) or (strpos($tokens[3], '/') === false)) {
                        wfDebug('QISSingleSignOn: Token incomplete:'.htmlspecialchars($token));
                        return null; 
                }
 
                // find the _last_ '/' to split username and hash as the username may include '/'-chars.
                $temp_pos = strrpos($tokens[3], '/');
                $tokens[4] = substr($tokens[3], $temp_pos + 1);
                $tokens[3] = substr($tokens[3], 0, $temp_pos);
 
                // check version
                if ($tokens[0] != '1.0') {
                        wfDebug('QISSingleSignOn: Unknown version:'.htmlspecialchars($tokens));
                        return null; 
                }
 
                // check time
                $currentTime = microtime();
                $currentTime = substr($currentTime, strpos($currentTime, ' '));
                if (intval($tokens[1]) > intval($currentTime) + 60) {
                        wfDebug('QISSingleSignOn: Token was created in the future (Check your clocks):'.htmlspecialchars($token));
                        return null; 
                }
                if (intval($tokens[1]) + 60 < intval($currentTime)) {
                        wfDebug('QISSingleSignOn: Token expired:'.htmlspecialchars($token));
                        return null; 
                }
 
                // check service name
                if ($tokens[2] != $wgAuthQISSingleSignOnService) {
                        wfDebug('QISSingleSignOn: Wrong service:'.htmlspecialchars($token));
                        return null; 
                }
 
                // check username name (using Title::newFormText as in User::newFromName)
                $userinfo = explode('/', urldecode($tokens[3]));
 
                // Andere Methode wie bei tokens: find the _last_ '/' to split username and hash as the username may include '/'-chars.
 //               $temp_pos = strrpos($tokens[3], '/');
 //               $userinfo[1] = substr($tokens[3], $temp_pos + 1);
 //               $userinfo[0] = substr($tokens[3], 0, $temp_pos);
 
//				wfDebug('QISSingleSignOn: userinfo-0:'.$userinfo[0]."\n");
//				wfDebug('QISSingleSignOn: userinfo-1:'.$userinfo[1]."\n");
 
                $t = Title::newFromText($userinfo[0]);
		if ($t == null) {
			wfDebug('QISSingleSignOn: Invalid character in user name: '.htmlspecialchars($userinfo[0]));
			return null;
		}
                $user = $t->getText();
 
                // check hash
                $toHash = $tokens[0].'/'.$tokens[1].'/'.$tokens[2].'/'.$tokens[3].'/'.$wgAuthQISSingleSignOnSharedSecret;
                $hash =  md5($toHash);
                if ($hash != $tokens[4]) {
                        wfDebug('QISSingleSignOn: Hash verification failed:'.htmlspecialchars($token).' Should be: ' . $hash);
                        return null;
                }
 
		// copy _ridlist to session for WikiRights (if present)
                if (count($userinfo) > -1) {
                        session_start();
               		$_SESSION['_ridlist'] = $userinfo[1];
                }
 
                // welcome, you passed all tests.
                return $user;
        }
 
        function autoCreate() {
                return true;
        }
 
        function strict() {
                return false;
        }
 
        function initUser( &$user ) {
                # Override this to do something.
                // TODO: email
                // TODO: groups, rights
        }
}
 
function myInitUser (&$user) {
		$u->addToDatabase();
		$u->setToken();
 
		return $u;
}
 
function QISSingleSignOnAutoAuthenticate(&$user) {
	global $wgRequest;
 
/*	if ( $user != null) {
		// user is authenticated (by another hook)
		return true;
	}
*/
	$token = $wgRequest->getVal("qisssotoken");
	if ( $token != null ) {
		$username = QISSingleSignOn::verifyToken($token);
		if ( $username != null) {
 
			$u = User::newFromName( $username );
			if ( 0 == $u->getID() ) {
				if ( QISSingleSignOn::autoCreate() && QISSingleSignOn::userExists( $username ) ) {
					$u->addToDatabase();
					$u->setToken();
				}
			}
			$user = $u;
			$u->setCookies();
		}
	}
	return true;
}
 
function QISSingleSignOnUserLoadFromSession($user, &$result) {
        global $wgRequest;
 
        $token = $wgRequest->getVal("qisssotoken");
        if ( $token != null ) {
                $username = QISSingleSignOn::verifyToken($token);
                if ( $username != null) {
                        $u = User::newFromName( $username );
                        if ( 0 == $u->getID() ) {
                                if ( QISSingleSignOn::autoCreate() && QISSingleSignOn::userExists( $username ) ) {
                                        $u->addToDatabase();
                                        $u->setToken();
                                }
                        }
			$localId = User::idFromName( $username );
			if ( !$localId ) {
				return true;
			} else {
				$user->setID( $localId );
				$user->loadFromId();
			}
			$result = true;
			$user->setCookies();
			wfSetupSession();
                }
        }
        return true;
}
 
function QISSingleSignOnUserLogout(&$user) {
	session_start();
	$_SESSION['_ridlist'] = null;
	return false;
}
 
$wgHooks['UserLogoutComplete'][] = 'QISSingleSignOnUserLogout';
$wgHooks['AutoAuthenticate'][] = 'QISSingleSignOnAutoAuthenticate';
$wgHooks['UserLoadFromSession'][] = 'QISSingleSignOnUserLoadFromSession';
 
 
$wgExtensionCredits['other'][] = array(
        'name' => 'QISSingleSignOn ',
        'version' => '0.4',
        'author' => 'Hendrik Brummermann',
        'url' => 'http://www.mediawiki.org/wiki/Extension:QISSingleSignOn',
        'description' => 'Single Sign On from HISQIS-Portal'
);
 
?>