[ROSLOGIN] [WIKI] Add a "RosLogin" MediaWiki extension based on the SessionManager framework introduced in MediaWiki 1.27.

Much simpler than the unmaintained AuthDrupal extension and - unlike that - needs no additional component on the CMS side.
This commit is contained in:
Colin Finck 2018-04-30 17:47:11 +02:00
parent 280f50e251
commit 9ebc516a7a
5 changed files with 218 additions and 0 deletions

View File

@ -153,6 +153,11 @@ $wgExtraNamespaces[101] = "Techwiki_talk";
$wgEnableMWSuggest = true;
$wgNamespaceToBeSearchedDefault[100] = true;
# Use RosLogin to handle MediaWiki users
$wgGroupPermissions['*']['createaccount'] = false;
$wgGroupPermissions['*']['editmyprivateinfo'] = false;
wfLoadExtension( 'RosLogin' );
# Use reCAPTCHA to protect against spam
wfLoadExtensions([ 'ConfirmEdit', 'ConfirmEdit/ReCaptchaNoCaptcha' ]);
$wgCaptchaClass = 'ReCaptchaNoCaptcha';

View File

@ -0,0 +1,22 @@
<?php
/*
* PROJECT: RosLogin - A simple Self-Service and Single-Sign-On around an LDAP user directory
* LICENSE: AGPL-3.0-or-later (https://spdx.org/licenses/AGPL-3.0-or-later)
* PURPOSE: Hooks for MediaWiki
* COPYRIGHT: Copyright 2018 Colin Finck (colin@reactos.org)
*/
class RosLoginHooks
{
public static function onSpecialPage_initList(&$specialPages) {
$specialPages['Userlogin'] = "SpecialRosLogin";
return true;
}
public static function onUserLogout(&$user) {
global $wgOut;
$redirect = array_key_exists("returnto", $_GET) ? "/wiki/index.php?title=" . $_GET["returnto"] : "/wiki";
$wgOut->redirect("/roslogin/?a=logout&redirect=" . rawurlencode($redirect));
return true;
}
}

View File

@ -0,0 +1,142 @@
<?php
/*
* PROJECT: RosLogin - A simple Self-Service and Single-Sign-On around an LDAP user directory
* LICENSE: AGPL-3.0-or-later (https://spdx.org/licenses/AGPL-3.0-or-later)
* PURPOSE: SessionProvider for MediaWiki
* COPYRIGHT: Copyright 2018 Colin Finck (colin@reactos.org)
*/
define("ROOT_PATH", "../");
require_once(ROOT_PATH . "roslogin/RosLogin.php");
use MediaWiki\Session\SessionBackend;
use MediaWiki\Session\SessionInfo;
use MediaWiki\Session\SessionProvider;
use MediaWiki\Session\UserInfo;
class RosLoginSessionProvider extends SessionProvider
{
private $_rl;
/**
* Gets the valid MediaWiki user name for the given RosLogin user name.
* MediaWiki user names need to begin with a capital letter and underscores must be converted to spaces.
* RosLogin's "forbidden_usernames" table must ensure that this does not lead to conflicting usernames.
*/
private function _getMediaWikiUsername($username)
{
$username_replacements = [
"_" => " ",
];
$username = ucfirst($username);
$username = strtr($username, $username_replacements);
return $username;
}
public function __construct()
{
$this->_rl = new RosLogin();
}
/**
* Return MediaWiki SessionInfo when a RosLogin user is logged in.
*/
public function provideSessionInfo(WebRequest $request)
{
// Check if the user is logged in through RosLogin Single-Sign-On.
$username = $this->_rl->isLoggedIn();
if ($username)
{
// Convert the username into a MediaWiki username and create a MediaWiki User object.
$wiki_username = $this->_getMediaWikiUsername($username);
$user = User::newFromName($wiki_username);
// This should never happen, otherwise our _getMediaWikiUsername function is buggy!
if (!$user)
die("Could not load a Username entry for <i>{$username}</i>");
// Return a session for the logged in user.
return new SessionInfo(
SessionInfo::MAX_PRIORITY, [
"provider" => $this,
"userInfo" => UserInfo::newFromUser($user, TRUE),
"forceHTTPS" => TRUE,
"metadata" => [
"username" => $username,
],
]
);
}
// Not logged into RosLogin Single-Sign-On, so return nothing.
return NULL;
}
/**
* Create the MediaWiki user if it does not exist yet and set or update E-Mail Address
* and Real Name based on the RosLogin data.
*/
public function refreshSessionInfo(SessionInfo $info, WebRequest $request, &$metadata)
{
// Get the MediaWiki user, create it if it does not exist.
$user = $info->getUserInfo()->getUser();
if (!$user->isLoggedIn())
{
$username = $user->getName();
$user = $user->createNew($username);
// This should never happen, otherwise our _getMediaWikiUsername function is buggy!
if (!$user)
die("Could not create a Username entry for <i>{$username}</i>");
}
// Get additional information about the account.
$userinfo = $this->_rl->getUserInformation($metadata["username"]);
$changed = FALSE;
// Update the E-Mail address and authentication timestamp if it changed.
if ($user->getEmail() != $userinfo["email"])
{
$user->setEmail($userinfo["email"]);
$user->setEmailAuthenticationTimestamp(wfTimestampNow());
$changed = TRUE;
}
// Update the real name if it changed.
if ($user->getRealName() != $userinfo["displayname"])
{
$user->setRealName($userinfo["displayname"]);
$changed = TRUE;
}
// Save any changed settings.
if ($changed)
$user->saveSettings();
return TRUE;
}
public function canChangeUser()
{
// Enable the "Log out" button.
return TRUE;
}
public function persistSession(SessionBackend $session, WebRequest $request)
{
// Dummy required function.
}
public function persistsSessionId()
{
// We let MediaWiki handle its Session IDs.
return FALSE;
}
public function unpersistSession(WebRequest $request)
{
// Dummy required function.
}
}

View File

@ -0,0 +1,22 @@
<?php
/*
* PROJECT: RosLogin - A simple Self-Service and Single-Sign-On around an LDAP user directory
* LICENSE: AGPL-3.0-or-later (https://spdx.org/licenses/AGPL-3.0-or-later)
* PURPOSE: MediaWiki replacement page for SpecialUserlogin that forwards to RosLogin
* COPYRIGHT: Copyright 2018 Colin Finck (colin@reactos.org)
*/
class SpecialRosLogin extends UnlistedSpecialPage
{
public function __construct()
{
parent::__construct("RosLogin");
}
public function execute($par)
{
$output = $this->getOutput();
$redirect = array_key_exists("returnto", $_GET) ? "/wiki/index.php?title=" . $_GET["returnto"] : "/wiki";
$output->redirect("/roslogin/?p=login&redirect=" . rawurlencode($redirect));
}
}

View File

@ -0,0 +1,27 @@
{
"name": "RosLogin",
"author": ["Colin Finck"],
"license-name": "AGPL-3.0-or-later",
"requires": {
"MediaWiki": ">= 1.30.0"
},
"AutoloadClasses": {
"RosLoginHooks": "RosLoginHooks.php",
"RosLoginSessionProvider": "RosLoginSessionProvider.php",
"SpecialRosLogin": "SpecialRosLogin.php"
},
"Hooks": {
"SpecialPage_initList": ["RosLoginHooks::onSpecialPage_initList"],
"UserLogout": ["RosLoginHooks::onUserLogout"]
},
"SessionProviders": {
"RosLoginSessionProvider": {
"class": "RosLoginSessionProvider",
"args": []
}
},
"SpecialPages": {
"RosLogin": "SpecialRosLogin"
},
"manifest_version": 2
}