Last active
October 9, 2015 13:04
-
-
Save Fannon/ab4c83668ec8de071fec to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Version 1.1.3 (Works out of box with MW 1.7 or above) | |
* - Works out with MW 1.15.1 (tested) | |
* | |
* Authentication Plugin for Siteminder | |
* Derived from ShibAuthPlugin.php | |
* Much of the commenting comes straight from AuthPlugin.php | |
* Had to add return statements to several routines because a | |
* return value is required from hook routines. | |
* | |
* Portions Copyright 2006, 2007 Regents of the University of California. | |
* Portions Copyright 2007 Steven Langenaken | |
* Released under the GNU General Public License | |
* | |
* Extension Maintainer: | |
* * Virgil Green <virgil.green AT bunge DOT com> | |
* Extension Developers: | |
* * Virgil Green - Converted from Shibbeleth to Siteminder | |
* | |
* This extension assumes that the only method for signing on will | |
* be SiteMinder. Local signon is not allowed. Since validation always | |
* occurs before any part of the wiki is displayed, there are no | |
* provisions made for selecting the style (local or Siteminder) and any | |
* function that would be used for validation or synchronizatin is | |
* set to simply return as though successful (or failure, if needed/appropriate). | |
* | |
* Suggested LocalSettings.php code | |
* ##Siteminder Authentication | |
* #Load SiteminderPlugin | |
* require_once('extensions/SiteminderAuthPlugin.php'); | |
* | |
* #Map data from Siteminder to local user data | |
* $siteminder_map_info = "true"; | |
* | |
* #Ssssh.... quiet down errors | |
* $olderror = error_reporting(E_ALL ^ E_NOTICE); | |
* | |
* #Map Siteminder variables to extension variable | |
* # In this example, Siteminder is setting http headers named | |
* # full_name, user_name, and email when then appear in the $_SERVER array | |
* # in any of the other data collections that expose the headers to code. | |
* $siteminder_real_name = $_SERVER['HTTP_FULL_NAME']; | |
* $siteminder_user_name = ucfirst(strtolower($_SERVER['HTTP_USER_NAME'])); | |
* $siteminder_email = $_SERVER['HTTP_EMAIL']; | |
* | |
* #Siteminder logoff URL (uncomment and set proper URL if you want a logout link) | |
* #This is expected to be an abslute URL, including the protocol | |
* #$siteminder_logout = "<URL to Siteminder logout page>"; | |
* | |
* #Turn error reporting back on | |
* error_reporting($olderror); | |
* | |
* #Activate Siteminder Plugin | |
* SetupSiteminderAuth(); | |
* | |
*/ | |
require_once("$IP/includes/AuthPlugin.php"); | |
class SiteminderAuthPlugin extends AuthPlugin { | |
var $existingUser = false; | |
/** | |
* 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 string $username | |
* @return bool | |
* @access public | |
*/ | |
function userExists($username) { | |
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 string $username | |
* @param string $password | |
* @return bool | |
* @access public | |
*/ | |
function authenticate($username, $password) { | |
global $siteminder_user_name; | |
return $username == $siteminder_user_name; | |
} | |
/** | |
* Modify options in the login template. | |
* | |
* @param UserLoginTemplate $template | |
* @access public | |
*/ | |
function modifyUITemplate(&$template, &$type) { | |
return; | |
} | |
/** | |
* Set the domain this plugin is supposed to use when authenticating. | |
* | |
* @param string $domain | |
* @access public | |
*/ | |
function setDomain($domain) { | |
return; | |
} | |
/** | |
* Check to see if the specific domain is a valid domain. | |
* | |
* @param string $domain | |
* @return bool | |
* @access 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 | |
* @access public | |
*/ | |
function updateUser(&$user) { | |
global $siteminder_map_info; | |
global $siteminder_email; | |
global $siteminder_real_name; | |
if ($siteminder_map_info) { | |
if ($siteminder_email != null) | |
$user->setEmail($siteminder_email); | |
if ($siteminder_real_name != null) | |
$user->setRealName($siteminder_real_name); | |
} | |
//For security, set password to a non-existant hash. | |
if ($user->mPassword != "nologin") { | |
$user->mPassword = "nologin"; | |
$user->saveSettings(); | |
} | |
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 | |
* @access public | |
*/ | |
function autoCreate() { | |
return true; | |
} | |
/** | |
* Can users change their passwords? | |
* | |
* @return bool | |
*/ | |
function allowPasswordChange() { | |
global $siteminder_pretend; | |
return $siteminder_pretend; | |
} | |
/** | |
* Set the given password in the authentication database. | |
* Return true if successful. | |
* | |
* @param string $password | |
* @return bool | |
* @access public | |
*/ | |
function setPassword($user, $password) { | |
global $siteminder_pretend; | |
return $siteminder_pretend; | |
} | |
/** | |
* Update user information in the external authentication database. | |
* Return true if successful. | |
* | |
* @param User $user | |
* @return bool | |
* @access 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 | |
* @access 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 | |
* @access public | |
*/ | |
function addUser($user, $password, $email = '', $realname = '') { | |
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 | |
* @access 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. | |
* | |
* The User object is passed by reference so it can be modified; don't | |
* forget the & on your function declaration. | |
* | |
* @param User $user | |
* @access public | |
*/ | |
function initUser(&$user, $autocreate = false) { | |
$this->updateUser($user); | |
} | |
/** | |
* If you want to munge the case of an account name before the final | |
* check, now is your chance. | |
*/ | |
function getCanonicalName($username) { | |
return $username; | |
} | |
} | |
function SiteminderGetAuthHook() { | |
global $wgVersion; | |
if (strcmp($wgVersion, "1.13") >= 0) { | |
return 'UserLoadAfterLoadFromSession'; | |
} else { | |
return 'AutoAuthenticate'; | |
} | |
} | |
/* | |
* End of AuthPlugin Code, beginning of hook code and auth functions | |
*/ | |
function SetupSiteMinderAuth() { | |
global $siteminder_user_name; | |
global $wgHooks; | |
global $wgAuth; | |
if ($siteminder_user_name != null) { | |
$wgHooks[SiteminderGetAuthHook()][] = "Siteminder" . SiteminderGetAuthHook(); | |
/* Hook for magical authN */ | |
$wgHooks['PersonalUrls'][] = 'SiteminderSSOActive'; | |
/* Disallow logout link */ | |
$wgAuth = new SiteminderAuthPlugin(); | |
} | |
} | |
/* Kill or replace logout link */ | |
function SiteminderSSOActive(&$personal_urls, $title) { | |
global $siteminder_logout; | |
global $siteminder_real_name; | |
global $siteminder_map_info; | |
if ($siteminder_logout == null) | |
# $personal_urls['logout'] = null; | |
unset($personal_urls['logout']); | |
else | |
$personal_urls['logout']['href'] = $siteminder_logout; | |
if ($siteminder_real_name && $siteminder_map_info) | |
$personal_urls['userpage']['text'] = $siteminder_real_name; | |
return true; | |
} | |
function SiteminderAuthAuthenticate(&$user) { | |
SiteminderShibUserLoadFromSession($user, true); | |
} | |
/* Tries to be magical about when to log in users and when not to. */ | |
function SiteminderUserLoadAfterLoadFromSession($user) { | |
global $wgContLang; | |
global $wgAuth; | |
global $siteminder_user_name; | |
global $wgHooks; | |
global $siteminder_map_info; | |
global $siteminder_pretend; | |
global $IP; | |
SiteminderKillAA(); | |
// $context = $this->getContext(); | |
// $request = $context->getRequest(); | |
//For versions of mediawiki which enjoy calling AutoAuth with null users | |
if ($user === null) { | |
$user = User::loadFromSession(); | |
} | |
//They already with us? If so, nix this function, we're good. | |
if ($user->isLoggedIn()) { | |
BringBackAA(); | |
return true; | |
} | |
//Is the user already in the database? | |
$localId = User::idFromName($siteminder_user_name); | |
/* if ( $localId != null ) { | |
$user = User::newFromId( $localId ); | |
$user->setID( $localId ); | |
$user->loadFromId(); | |
$user->setCookies(); | |
$wgAuth->updateUser( $user ); | |
wfSetupSession(); | |
return true; | |
} | |
*/ | |
//print_r($user->getRequest()); | |
if (User::idFromName($siteminder_user_name) != null) { | |
$user = User::newFromName($siteminder_user_name); | |
$smi = $siteminder_map_info; | |
$siteminder_map_info = false; | |
$user->load(); | |
$wgAuth->existingUser = true; | |
$wgAuth->updateUser($user); //Make sure password is nologin | |
$siteminder_map_info = $smi; | |
//$user->SetupSession(); | |
wfSetupSession(); | |
$user->setCookies(); | |
// $user->invalidateCache(); // invalidating Cache has no effect (GEA) | |
/* print_r($user->getRequest()); /* uncomment for debugging (GEA) */ | |
// Calculate 302 redirect URL | |
$redirecturl = $target->getFullUrl(Title::newMainPage()); | |
// Get returnto value | |
$returnto = $wgRequest->getVal("returnto"); // TODO: Get this through $context | |
if ($returnto) { | |
$target = Title::newFromText($returnto); | |
if ($target) { | |
$redirecturl = $target->getFullUrl(); | |
} | |
} | |
// Provide a 302 Redirect | |
// Otherwise the user will have to refresh one time manually | |
// in order to view the wiki in a logged in state | |
header('Location: ' . $redirecturl); | |
return true; | |
} | |
//Place the hook back (Not strictly necessarily MW Ver >= 1.9) | |
BringBackAA(); | |
//Okay, kick this up a notch then... | |
$user->setName($wgContLang->ucfirst($siteminder_user_name)); | |
/* | |
* Since we only get called when someone should be logged in, if they | |
* aren't let's make that happen. Oddly enough the way MW does all | |
* this is simply to use a loginForm class that pretty much does | |
* most of what you need. Creating a loginform is a very very small | |
* part of this object. | |
*/ | |
require_once("$IP/includes/specials/SpecialUserlogin.php"); | |
//This section contains a silly hack for MW | |
global $wgLang; | |
global $wgContLang; | |
global $wgRequest; | |
$wgLangUnset = false; | |
if (!isset($wgLang)) { | |
$wgLang = $wgContLang; | |
$wgLangUnset = true; | |
} | |
SiteminderKillAA(); | |
// --> ext: hh[2014-07-18] | |
// --> make property mRemember accessible by using ReflectionClass: | |
$loginFormClass = new ReflectionClass("LoginForm"); | |
$property = $loginFormClass->getProperty("mRemember"); | |
$property->setAccessible(true); | |
// <-- ext: hh[2014-07-18] | |
//This creates our form that'll do black magic | |
$lf = new LoginForm($wgRequest); | |
//Place the hook back (Not strictly necessarily MW Ver >= 1.9) | |
BringBackAA(); | |
//And now we clean up our hack | |
if ($wgLangUnset == true) { | |
unset($wgLang); | |
unset($wgLangUnset); | |
} | |
//The mediawiki developers entirely broke use of this the | |
//straightforward way in 1.9, so now we just lie... | |
$siteminder_pretend = true; | |
//Now we _do_ the black magic | |
// hh: $lf->mRemember = false; | |
// replaced by the following line -> | |
$property->setValue($lf, false); | |
// analyze class User: | |
// -> remove after debugging | |
/*$userClass = new ReflectionClass("User"); | |
$methods = $userClass->getMethods(); | |
foreach($methods as $m) { | |
print $m->name; | |
$m->isPrivate() ? print "Private " : print ""; | |
$m->isPublic() ? print "Public " : print ""; | |
$params = $m->getParameters(); | |
foreach($params as $p) { | |
print $p->getName(); | |
} | |
print "</br>\r\n"; | |
}*/ | |
// <- remove after debugging | |
// <- | |
$user->loadDefaults($siteminder_user_name); | |
$lf->initUser($user); | |
//Stop pretending now | |
$siteminder_pretend = false; | |
//Finish it off | |
$user->saveSettings(); | |
// hh: guess the method setupSession should be SetupSession, wrong guess... | |
// uncomment following line, check what happens then | |
//$user->setupSession(); | |
wfSetupSession(); | |
$user->setCookies(); | |
return true; | |
} | |
function SiteminderKillAA() { | |
global $wgHooks; | |
global $wgAuth; | |
//Temporarily kill The AutoAuth Hook to prevent recursion | |
foreach ($wgHooks[SiteminderGetAuthHook()] as $key => $value) { | |
if ($value == "Siteminder" . SiteminderGetAuthHook()) | |
$wgHooks[SiteminderGetAuthHook()][$key] = 'BringBackAA'; | |
} | |
} | |
/* Puts the auto-auth hook back into the hooks array */ | |
function BringBackAA() { | |
global $wgHooks; | |
global $wgAuth; | |
foreach ($wgHooks[SiteminderGetAuthHook()] as $key => $value) { | |
if ($value == 'BringBackAA') | |
$wgHooks[SiteminderGetAuthHook()][$key] = "Siteminder" . SiteminderGetAuthHook(); | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment