Open main menu

Extension:TivoliAccessManagerAuthPlugin

MediaWiki extensions manual
OOjs UI icon advanced.svg
Tivoli Access Manager (TAM) Authentication
Release status: stable
Implementation User identity
Description Authenticate users against Tivoli Access Manager
Author(s) Chris Reigrut, Key Bank / Key Equipment Finance
Latest version 1.0.2 (2014-07-09)
MediaWiki 1.11 - 1.19
License No license specified
Download see below
Translate the TivoliAccessManagerAuthPlugin extension if it is available at translatewiki.net
Check usage and version matrix.

This AuthPlugin automatically logs in users using information passed from Tivoli Access Manager (TAM). Additionally, it will set their groups to the groups passed from TAM as well.

CreditsEdit

Adapted from work by Rusty (Extension:AutomaticREMOTE USER) which was adapted from work by Otheus (Auto Login via REMOTE USER)

InstallationEdit

LocalSettings.phpEdit

Add these two lines to the bottom of your LocalSettings.php

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

CodeEdit

Save the following as TAM/TAMAuthPlugin.php in your extensions directory

<?php
/******************************************************************************
 * Work by Chris Reigrut, Key Equipment Finance / Key Bank
 *
 *
 * Tivoli Access Manager (TAM) passes us two HTTP headers, iv-user and iv-groups,
 * which gives us the currently logged in user, and any groups that user belongs
 * to.  We only care about groups that are prefixed with wik.  Right now there 
 * are three access levels:  wikAdministrator, wikUser, and none.
 *
 * Adapted from work by Rusty (http:/*www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER)
 * which was adapted from work by Otheus (http:/*meta.wikimedia.org/wiki/User:Otheus/Auto_Login_via_REMOTE_USER)
 *
 * Add these two lines to the bottom of your LocalSettings.php
 * require_once('extensions/TAM/TAMAuthPlugin.php');
 * $wgAuth = new TAMAuthPlugin();
 *
 * The constructor of TAMAuthPlugin registers a hook to do the automatic
 * login.  Storing the TAMAuthPlugin 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.
 *
 * You probably want to edit the initUser function to set the users real name
 * and email address properly for your configuration.
 ******************************************************************************/
$wgExtensionCredits['other'][] = array(
        'name' => 'Tivoli Access Manager AuthPlugin',
        'author' => 'Chris Reigrut',
        'version' => '1.0.2',
        'url' => 'http://www.mediawiki.org/wiki/Extension:TivoliAccessManagerAuthPlugin',
        'description' => 'Authenticate users through Tivoli Access Manager information'
);

// Don't let anonymous people do things...
$wgGroupPermissions['*']['createaccount'] = false;
$wgGroupPermissions['*']['read'] = false;
$wgGroupPermissions['*']['edit'] = false;

// The Auth_remoteuser class is an AuthPlugin so make sure we have this
// included.
require_once ('AuthPlugin.php');

/**
 * This hook is registered by the Auth_remoteuser constructor.  It will be
 * called on every page load.  It serves the function of automatically logging
 * in the user.  The Auth_remoteuser class is an AuthPlugin and handles the
 * actual authentication, user creation, etc.
 *
 * Details:
 * 1. Check to see if the user has a session and is not anonymous.  If this is
 *    true we can just return.
 * 2. If the user doesn't have a session, we create a login form with our own
 *    fake request and ask the form to authenticate the user.  If the user does
 *    not exist authenticateUserData will attempt to create one.  The login form
 *    uses our Auth_remoteuser class as an AuthPlugin.
 *
 * Note: If cookies are disabled, an infinite loop /might/ occur?
 */
function TAMAutoLoginHook() {
	global $wgUser, $wgRequest;
	wfDebug("TAMAutoLoginHook()");
	

	// For a few special pages, don't do anything.
	$title = $wgRequest->getVal('title');
	if (($title == Title :: makeName(NS_SPECIAL, 'Userlogout')) || ($title == Title :: makeName(NS_SPECIAL, 'Userlogin'))) {
		return;
	}

	// Get username from TAM header
	$headers = getTamHeaders();
	$username = $headers['iv-user'];
	
	// See if there is a current login for this session
	$user = User :: newFromSession();
	if (!$user->isAnon()) {
		// If the current session user is a different user than TAM sent us,
		// log out the previous user and proceed to log this one in
		// Courtesy of Brian Roller
		if (strcasecmp($user->mName,$username) != 0) {
			$user->logout();
		} else {
			return; // Current user is the TAM user, so do nothing
		}
	}

	// Copied from includes/SpecialUserlogin.php
	if (!isset ($wgCommandLineMode) && !isset ($_COOKIE[session_name()])) {
		wfSetupSession();
	}

	// Submit a fake login form to authenticate the user.
	$params = new FauxRequest(array (
		'wpName' => $username,
		'wpPassword' => 'mustnotbeempty',
		'wpLoginToken' => $wgRequest->getVal('wpLoginToken'),
		'wpDomain' => '',
		'wpRemember' => ''
	));

	// Authenticate user data will automatically create new users.
	$loginForm = new LoginForm($params);
	$result = $loginForm->authenticateUserData();
	if ($result != LoginForm :: SUCCESS) {
		error_log('Unexpected REMOTE_USER authentication failure.');
		return;
	}

	$wgUser->setCookies();
	return; // User has been logged in.
}

class TAMAuthPlugin extends AuthPlugin {

	function TAMAuthPlugin() {
		// Register our hook function.  This hook will be executed on every page
		// load.  Its purpose is to automatically log the user in, if necessary.
		if (function_exists('getallheaders')) {
			//$headers = getTamHeaders();
			//if (strlen($headers['iv-user'])) {
				global $wgExtensionFunctions;
				if (!isset ($wgExtensionFunctions)) {
					$wgExtensionFunctions = array ();
				} else {
					if (!is_array($wgExtensionFunctions)) {
						$wgExtensionFunctions = array (
							$wgExtensionFunctions
						);
					}
				}
				array_push($wgExtensionFunctions, 'TAMAutoLoginHook');
			//}
		}
		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 iv-user.
	 * The name will be normalized to MediaWiki's requirements, so
	 * lower it and the iv-user before checking.
	 *
	 * @param $username String: username.
	 * @param $password String: user password.
	 * @return bool
	 * @public
	 */
	function authenticate($username, $password) {
		$headers = getTamHeaders();
		return isset ($headers['iv-user']) && (strtolower($username) == strtolower($headers['iv-user']));
	}

	/**
	 * Check to see if the specific domain is a valid domain.
	 *
	 * @param $domain String: authentication domain.
	 * @return bool
	 * @public
	 */
	function validDomain($domain) {
		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, set their groups and fill in default preferences.
	 *
	 * @param $user User object.
	 * @public
	 */
	function initUser(& $user) {
		$user->setToken();
	
		# Add or remove groups to match the TAM settings
		$headers = getTamHeaders();
		$this->setGroups($user, $headers['iv-groups']);
		
		// Turn off the "remember me" cookies
		$user->setOption('rememberpassword', false);
		
		// Set up any desired user defaults
		$this->createUserSettings($user);
		
		$user->saveSettings();
	}

	/**
	 * When a user logs in, update their groups and preferences.
	 *
	 * @param User $user
	 * @public
	 */
	function updateUser(& $user) {
		$user->setToken();
	
		# Add or remove groups to match the TAM settings
		$headers = getTamHeaders();
		$this->setGroups($user, $headers['iv-groups']);
		
		// Turn off the "remember me" cookies
		$user->setOption('rememberpassword', false);
		
		// Set up any desired user defaults
		$this->updateUserSettings($user);
		
		$user->saveSettings();
		
		return true;
	}

	/**
	 * 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;
	}

	/**
	 * Make sure that the Wiki groups match the iv-groups.  Basically this means
	 * that we have to add any wiki groups that in iv-groups, and remove any wiki 
	 * groups that aren't 
	 */
	function setGroups(& $user, $tamGroupsString) {
		// wfDebug("setting groups {$tamGroupsString}\n");

		$userGroups = $user->getGroups();
		// wfDebug("user groups " . implode($userGroups) . "\n");

		$tamGroups = array ();

		// Add any new TAM groups to the wiki record
		foreach (explode(',', $tamGroupsString) as $tamGroupString) {
			if (strcasecmp(substr($tamGroupString, 1, 3), 'wik') == 0) {
				// This is a TAM Wiki group
				$tamGroup = substr($tamGroupString, 1, -1);
				// echo "checking to add {$tamGroup}\n";
				// Add it to the list of TAM Wiki Groups
				$tamGroups[] = $tamGroup;
				// If the user doesn't have this group, add it
				if (!in_array($tamGroup, $userGroups)) {
					// echo "adding group {$tamGroup}\n";
					$user->addGroup($tamGroup);
				}
			}
		}

		// Remove any old TAM groups from the wiki record
		foreach ($userGroups as $userGroup) {
			if (strcasecmp(substr($userGroup, 0, 3), 'wik') == 0) {
				// This is a TAM Wiki group
				// echo "checking to remove {$userGroup}\n";
				// If the user doesn't have this group, remove it
				if (!in_array($userGroup, $tamGroups)) {
					// echo "removing group {$userGroup}\n";
					$user->removeGroup($userGroup);
				}
			}
		}
	}

	/**
	 * 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 createUserSettings(& $user) {
		$user->mEmailAuthenticated = wfTimestampNow();
		
		//turn on e-mail notifications by default
		$user->setOption('enotifwatchlistpages', 1);
		$user->setOption('enotifusertalkpages', 1);
		#$user->setOption('enotifminoredits', 1);
		$user->setOption('enotifrevealaddr', 1);
		
		# User Enhanced Recent Changes
		$user->setOption('usenewrc', 1);
		
		# Add pages I create or edit to my watchlist
		$user->setOption('watchcreations', 1);
		#$user->setOption('watchdefault', 1);
		
		# Search Help by default
		$user->setOption('searchNs12', 1);
	}
	

	/**
	 * When updating a user account, optionally fill in preferences and such.
	 * For instance, you might update the email address or real name from the
	 * external user database.
	 *
	 * @param $user User object.
	 * @public
	 */
	function updateUserSettings(& $user) {
		// Set the user's email as authenticated
		$user->mEmailAuthenticated = wfTimestampNow();
			
		# Search Help by default
		//$user->setOption('searchNs12', 1);
	}
}

	function getTamHeaders() {
		$headers = getallheaders();
		return $headers;
	}
?>

CustomizationEdit

Edit the functions createUserSettings and updateUserSettings to set/update any customized user information or preferences.

Revision HistoryEdit

1.0.0 (2009-03-20)
Fixed bug caused by string sensitive compare on username

Sites using this extensionEdit

Please add your site (and a link if it is public) to the list! Thanks!

  • Key National Finance WiKey (internal intranet)