Commit bbe9a7c8 authored by cicalese's avatar cicalese
Browse files

Update for MW 1.27

Use new authentication framework, extension registration

Bug: T110464
Change-Id: I20f5b984b99d6610d1d399db4166e05963a526cc
parent 53366199
<?php
/*
* Copyright (c) 2015 The MITRE Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
abstract class PluggableAuth {
/**
* Implements UserLoadFromSession hook.
* See https://www.mediawiki.org/wiki/Manual:Hooks/UserLoadFromSession
*
* @since 1.0
*
* @param User $user
* @param &$result
*/
public static function userLoadFromSession( User $user = null,
&$result = null ) {
// http://stackoverflow.com/questions/520237/how-do-i-expire-a-php-session-after-30-minutes
if ( !isset( $GLOBALS['PluggableAuth_Timeout'] ) ) {
$GLOBALS['PluggableAuth_Timeout'] = 1800;
}
if ( $GLOBALS['PluggableAuth_Timeout'] > 0 ) {
if ( session_id() == '' ) {
wfSetupSession();
}
$time = time();
if ( isset( $_SESSION['LAST_ACTIVITY'] ) &&
( $time - $_SESSION['LAST_ACTIVITY'] >
$GLOBALS['PluggableAuth_Timeout'] ) ) {
$session_variable = wfWikiID() . "_userid";
if ( array_key_exists( $session_variable, $_SESSION ) ) {
$user->mId = $_SESSION[$session_variable];
if ( $user->loadFromId() ) {
self::logout( $user );
} else{
session_unset();
session_destroy();
}
} else {
session_unset();
session_destroy();
}
wfDebug( "Session timed out." . PHP_EOL );
}
$_SESSION['LAST_ACTIVITY'] = $time;
if ( !isset( $_SESSION['CREATED'] ) ) {
$_SESSION['CREATED'] = $time;
} elseif ( $time - $_SESSION['CREATED'] >
$GLOBALS['PluggableAuth_Timeout'] ) {
session_regenerate_id( true );
$_SESSION['CREATED'] = $time;
wfDebug( "Session regenerated." . PHP_EOL );
}
}
if ( session_id() == '' ) {
wfSetupSession();
}
$session_variable = wfWikiID() . "_userid";
if ( array_key_exists( $session_variable, $_SESSION ) ) {
$user->mId = $_SESSION[$session_variable];
if ( $user->loadFromId() ) {
$result = true;
return false;
}
}
if ( isset( $GLOBALS['PluggableAuth_AutoLogin'] ) &&
$GLOBALS['PluggableAuth_AutoLogin'] ) {
$session_variable = wfWikiID() . "_returnto";
if ( ( !array_key_exists( $session_variable, $_SESSION ) ||
$_SESSION[$session_variable] === null ) &&
array_key_exists( 'title', $_REQUEST ) ) {
$_SESSION[$session_variable] = $_REQUEST['title'];
}
$result = self::login( $user );
}
return false;
}
/**
* Implements UserLogout hook.
* See https://www.mediawiki.org/wiki/Manual:Hooks/UserLogout
*
* @since 1.0
*
* @param User $user
*/
public static function logout( User &$user ) {
if ( session_id() == '' ) {
wfSetupSession();
}
$session_variable = wfWikiID() . "_userid";
if ( array_key_exists( $session_variable, $_SESSION ) ) {
unset( $_SESSION[$session_variable] );
}
$instance = self::getInstance();
if ( !$instance ) {
return true;
}
$instance->deauthenticate( $user );
session_regenerate_id( true );
session_destroy();
unset( $_SESSION );
return true;
}
/**
* Implements PersonalUrls hook.
* See https://www.mediawiki.org/wiki/Manual:Hooks/PersonalUrls
*
* @since 1.0
*
* @param array &$personal_urls
* @param Title $title
* @param SkinTemplate $skin
*/
public static function modifyLoginURLs( array &$personal_urls,
Title $title = null, SkinTemplate $skin = null ) {
$urls = array(
'createaccount',
'anonlogin'
);
foreach ( $urls as $u ) {
if ( array_key_exists( $u, $personal_urls ) ) {
unset( $personal_urls[$u] );
}
}
if ( isset( $GLOBALS['PluggableAuth_AutoLogin'] ) &&
$GLOBALS['PluggableAuth_AutoLogin'] ) {
unset( $personal_urls['login'] );
unset( $personal_urls['logout'] );
}
return true;
}
/**
* Implements SpecialPage_initList hook.
* See https://www.mediawiki.org/wiki/Manual:Hooks/SpecialPage_initList
*
* @since 1.0
*
* @param array &$specialPagesList
*/
public static function modifyLoginSpecialPages(
array &$specialPagesList = null ) {
$specialpages = array(
'CreateAccount'
);
foreach ( $specialpages as $p ) {
if ( array_key_exists( $p, $specialPagesList ) ) {
unset( $specialPagesList[$p] );
}
}
if ( isset( $GLOBALS['PluggableAuth_AutoLogin'] ) &&
$GLOBALS['PluggableAuth_AutoLogin'] ) {
unset( $specialPagesList['Userlogin'] );
unset( $specialPagesList['Userlogout'] );
}
return true;
}
/**
* Called from PluggableAuthLogin
*
* @since 1.0
*
* @param User $user
*/
public static function login( $user ) {
$instance = self::getInstance();
if ( $instance ) {
if ( $instance->authenticate( $id, $username, $realname, $email ) ) {
if ( is_null( $id ) ) {
$user->loadDefaults( $username );
$user->mName = $username;
$user->mRealName = $realname;
$user->mEmail = $email;
$user->mEmailAuthenticated = wfTimestamp();
$user->mTouched = wfTimestamp();
$new_user = true;
wfDebug( "Authenticated new user: " . $username . PHP_EOL );
} else {
$user->mId = $id;
$user->loadFromId();
$new_user = false;
wfDebug( "Authenticated existing user: " . $user->mName . PHP_EOL );
}
$user->setCookies();
} else {
wfDebug( "Authentication failure." . PHP_EOL );
return false;
}
} else {
return false;
}
$authorized = true;
Hooks::run( 'PluggableAuthUserAuthorization', array( $user,
&$authorized ) );
$returnto = null;
$params = null;
if ( $authorized ) {
if ( $new_user ) {
$user->addToDatabase();
$instance->saveExtraAttributes( $user->mId );
wfDebug( "Added new user: " . $username . PHP_EOL );
} else {
self::updateUser( $user, $realname, $email );
wfDebug( "Updated existing user: " . $user->mName . PHP_EOL );
}
if ( session_id() == '' ) {
wfSetupSession();
}
$session_variable = wfWikiID() . "_userid";
$_SESSION[$session_variable] = $user->mId;
$session_variable = wfWikiID() . "_returnto";
if ( array_key_exists( $session_variable, $_SESSION ) ) {
$returnto = $_SESSION[$session_variable];
unset( $_SESSION[$session_variable] );
}
Hooks::run( 'UserLoginComplete', array( &$user, &$injected_html ) );
} else {
$returnto = 'Special:PluggableAuthNotAuthorized';
$params = array( 'name' => $user->mName );
}
session_regenerate_id( true );
self::redirect( $returnto, $params );
return $authorized;
}
/**
* @since 1.0
*
* @param $page
* @param $params
*/
public static function redirect( $page, $params = null ) {
$title = Title::newFromText( $page );
if ( is_null( $title ) ) {
$title = Title::newMainPage();
}
$url = $title->getFullURL();
if ( is_array( $params ) && count( $params ) > 0 ) {
$first = true;
foreach ( $params as $key => $value ) {
if ( $first ) {
$first = false;
$url .= '?';
} else {
$url .= '&';
}
$url .= $key . '=' . $value;
}
}
if ( Hooks::run( 'PluggableAuthRedirect', array( &$url ) ) ) {
$GLOBALS['wgOut']->redirect( $url );
}
}
/**
* @since 1.0
*
* @param &$id
* @param &$username
* @param &$realname
* @param &$email
*/
abstract public function authenticate( &$id, &$username, &$realname,
&$email );
/**
* @since 1.0
*
* @param User &$user
*/
abstract public function deauthenticate( User &$user );
/**
* @since 1.0
*
* @param $id
*/
abstract public function saveExtraAttributes( $id );
private static function getInstance() {
if ( isset( $GLOBALS['PluggableAuth_Class'] ) &&
class_exists( $GLOBALS['PluggableAuth_Class'] ) &&
is_subclass_of( $GLOBALS['PluggableAuth_Class'],
'PluggableAuth' ) ) {
return new $GLOBALS['PluggableAuth_Class'];
}
wfDebug( "Could not get authentication plugin instance." . PHP_EOL );
return false;
}
private static function updateUser( $user, $realname, $email ) {
if ( $user->mRealName != $realname || $user->mEmail != $email ) {
$rights = $user->getRights();
if ( in_array( "editmyprivateinfo", $rights ) ) {
wfDebug( "updateUser(): User has editmyprivateinfo right." . PHP_EOL );
wfDebug( "updateUser(): Did not save updated real name and email address." . PHP_EOL );
} else {
wfDebug( "updateUser(): User does not have editmyprivateinfo right." . PHP_EOL );
$user->mRealName = $realname;
$user->mEmail = $email;
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'user',
array( // SET
'user_real_name' => $realname,
'user_email' => $email
), array( // WHERE
'user_id' => $user->mId
), __METHOD__
);
wfDebug( "updateUser(): Saved updated real name and email address." . PHP_EOL );
}
} else {
wfDebug( "updateUser(): Real name and email address did not change." . PHP_EOL );
}
}
}
<?php
/**
* This is a backwards-compatibility shim, generated by:
* https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php
*
* Beginning with MediaWiki 1.23, translation strings are stored in json files,
* and the EXTENSION.i18n.php file only exists to provide compatibility with
* older releases of MediaWiki. For more information about this migration, see:
* https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format
*
* This shim maintains compatibility back to MediaWiki 1.17.
*/
$messages = array();
if ( !function_exists( 'wfJsonI18nShim8eb632f15ba7cbf0' ) ) {
function wfJsonI18nShim8eb632f15ba7cbf0( $cache, $code, &$cachedData ) {
$codeSequence = array_merge( array( $code ), $cachedData['fallbackSequence'] );
foreach ( $codeSequence as $csCode ) {
$fileName = dirname( __FILE__ ) . "/i18n/$csCode.json";
if ( is_readable( $fileName ) ) {
$data = FormatJson::decode( file_get_contents( $fileName ), true );
foreach ( array_keys( $data ) as $key ) {
if ( $key === '' || $key[0] === '@' ) {
unset( $data[$key] );
}
}
$cachedData['messages'] = array_merge( $data, $cachedData['messages'] );
}
$cachedData['deps'][] = new FileDependency( $fileName );
}
return true;
}
$GLOBALS['wgHooks']['LocalisationCacheRecache'][] = 'wfJsonI18nShim8eb632f15ba7cbf0';
}
<?php
/*
* Copyright (c) 2015 The MITRE Corporation
* Copyright (c) 2015-2016 The MITRE Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -22,42 +22,50 @@
* DEALINGS IN THE SOFTWARE.
*/
if ( !defined( 'MEDIAWIKI' ) ) {
die( '<b>Error:</b> This file is part of a MediaWiki extension and cannot be run standalone.' );
}
abstract class PluggableAuth {
/**
* @since 1.0
*
* @param &$id
* @param &$username
* @param &$realname
* @param &$email
*/
abstract public function authenticate( &$id, &$username, &$realname,
&$email );
/**
* @since 1.0
*
* @param User &$user
*/
abstract public function deauthenticate( User &$user );
$GLOBALS['wgExtensionCredits']['other'][] = array (
'path' => __FILE__,
'name' => 'PluggableAuth',
'version' => '1.2',
'author' => array(
'[https://www.mediawiki.org/wiki/User:Cindy.cicalese Cindy Cicalese]'
),
'descriptionmsg' => 'pluggableauth-desc',
'url' => 'https://www.mediawiki.org/wiki/Extension:PluggableAuth',
);
$GLOBALS['wgAutoloadClasses']['PluggableAuth'] =
__DIR__ . '/PluggableAuth.class.php';
$GLOBALS['wgMessagesDirs']['PluggableAuth'] = __DIR__ . '/i18n';
$GLOBALS['wgExtensionMessagesFiles']['PluggableAuth'] =
__DIR__ . '/PluggableAuth.i18n.php';
$GLOBALS['wgHooks']['UserLoadFromSession'][] =
'PluggableAuth::userLoadFromSession';
$GLOBALS['wgHooks']['UserLogout'][] = 'PluggableAuth::logout';
$GLOBALS['wgHooks']['PersonalUrls'][] = 'PluggableAuth::modifyLoginURLs';
$GLOBALS['wgHooks']['SpecialPage_initList'][] =
'PluggableAuth::modifyLoginSpecialPages';
$GLOBALS['wgSpecialPages']['Userlogin'] = 'PluggableAuthLogin';
$GLOBALS['wgAutoloadClasses']['PluggableAuthLogin'] =
__DIR__ . '/PluggableAuthLogin.class.php';
$GLOBALS['wgSpecialPages']['PluggableAuthNotAuthorized'] =
'PluggableAuthNotAuthorized';
$GLOBALS['wgAutoloadClasses']['PluggableAuthNotAuthorized'] =
__DIR__ . '/PluggableAuthNotAuthorized.class.php';
$GLOBALS['wgWhitelistRead'][] = "Special:PluggableAuthNotAuthorized";
/**
* @since 1.0
*
* @param $id
*/
abstract public function saveExtraAttributes( $id );
private static $instance = null;
/**
* @since 2.0
*/
public static function singleton() {
if ( !is_null( self::$instance ) ) {
return self::$instance;
} elseif ( isset( $GLOBALS['wgPluggableAuth_Class'] ) &&
class_exists( $GLOBALS['wgPluggableAuth_Class'] ) &&
is_subclass_of( $GLOBALS['wgPluggableAuth_Class'],
'PluggableAuth' ) ) {
self::$instance = new $GLOBALS['wgPluggableAuth_Class'];
return self::$instance;
}
wfDebug( 'Could not get authentication plugin instance.' );
return false;
}
}
<?php
/*
* Copyright (c) 2014 The MITRE Corporation
* Copyright (c) 2016 The MITRE Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -22,19 +22,16 @@
* DEALINGS IN THE SOFTWARE.
*/
class PluggableAuthNotAuthorized extends UnlistedSpecialPage {
use \MediaWiki\Auth\ButtonAuthenticationRequest;
class PluggableAuthBeginAuthenticationRequest extends ButtonAuthenticationRequest {
public function __construct() {
parent::__construct( 'PluggableAuthNotAuthorized' );
parent::__construct(
'pluggableauthlogin',
wfMessage('pluggableauth-loginbutton-label'),
wfMessage('pluggableauth-loginbutton-help'),
true);
}
public function execute( $param ) {
$name = htmlentities(
$this->getRequest()->getVal( 'name', '<missing name>' ),
ENT_QUOTES );
$this->getOutput()->
addHTML( wfMessage( 'pluggableauthnotauthorized', $name )->
text() );
}
}
<?php
/*
* Copyright (c) 2014 The MITRE Corporation
* Copyright (c) 2016 The MITRE Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -22,44 +22,25 @@
* DEALINGS IN THE SOFTWARE.
*/
class PluggableAuthLogin extends UnlistedSpecialPage {
use \MediaWiki\Auth\AuthenticationRequest;
use \MediaWiki\Auth\AuthManager;
public function __construct() {
parent::__construct( 'Userlogin' );
class PluggableAuthContinueAuthenticationRequest extends AuthenticationRequest {
public function getFieldInfo() {
return [];
}
public function execute( $param ) {
if ( session_id() == '' ) {
wfSetupSession();
}
$session_variable = wfWikiID() . "_returnto";
$user = $this->getContext()->getUser();
if ( $user->isLoggedIn() ) {
if ( !array_key_exists( $session_variable, $_SESSION ) ||
$_SESSION[$session_variable] === null ) {
$returnto = Title::newMainPage()->getPrefixedText();
} else {
$returnto = $_SESSION[$session_variable];
unset( $_SESSION[$session_variable] );
}
Hooks::run( 'UserLoginComplete', array( &$user, &$injected_html ) );
PluggableAuth::redirect( $returnto );
} else {
if ( !array_key_exists( $session_variable, $_SESSION ) ||
$_SESSION[$session_variable] === null ) {
$returnto = htmlentities(
$this->getRequest()->getVal( 'returnto', '' ),
ENT_QUOTES );
$title = Title::newFromText( $returnto );
if ( is_null( $title ) ) {
$title = Title::newMainPage();
}
$_SESSION[$session_variable] = $title->getPrefixedText();
}
$title = Title::newFromText( "Special:UserLogin" );
$_SERVER['REQUEST_URI'] = $title->getLocalURL();
PluggableAuth::login( $user );
public function loadFromSubmission( array $data ) {
$authManager = AuthManager::singleton();
$error = $authManager->getAuthenticationSessionData(
PluggableAuthLogin::ERROR_SESSION_KEY );
if ( is_null( $error ) ) {
$this->username = $authManager->getAuthenticationSessionData(
PluggableAuthLogin::USERNAME_SESSION_KEY );
$authManager->removeAuthenticationSessionData(
PluggableAuthLogin::USERNAME_SESSION_KEY );
}
return true;
}
}
<?php
/*
* Copyright (c) 2016 The MITRE Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER