Anomie has uploaded a new change for review.
https://gerrit.wikimedia.org/r/58924
Change subject: Add Javascript login check against the central wiki
......................................................................
Add Javascript login check against the central wiki
The ability for CentralAuth to log the user in everywhere via a "push"
model is going away, as browsers tighten their security on third-party
cookies.
This changes things to a "pull" model instead. If the user is logged
out, a request is sent to the central wiki, which puts the necessary
data in memcache so we can set the necessary cookies as first-party
instead. To avoid doing this with every page view, it is instead done
just once and a cookie or localStorage token is set to remember this.
Change-Id: Ib6e9cce4fa4c5f1482c59bfac28087f558786efe
---
M CentralAuth.alias.php
M CentralAuth.i18n.php
M CentralAuth.php
M CentralAuthHooks.php
A modules/ext.centralauth.centrallogin.js
A specials/SpecialCentralLogin.php
6 files changed, 637 insertions(+), 1 deletion(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CentralAuth
refs/changes/24/58924/1
diff --git a/CentralAuth.alias.php b/CentralAuth.alias.php
index cabd821..0042ff6 100644
--- a/CentralAuth.alias.php
+++ b/CentralAuth.alias.php
@@ -12,6 +12,7 @@
$specialPageAliases['en'] = array(
'CentralAuth' => array( 'CentralAuth' ),
'AutoLogin' => array( 'AutoLogin' ),
+ 'CentralLogin' => array( 'CentralLogin' ),
'MergeAccount' => array( 'MergeAccount' ),
'GlobalGroupMembership' => array( 'GlobalUserRights',
'GlobalGroupMembership' ),
'GlobalGroupPermissions' => array( 'GlobalGroupPermissions' ),
@@ -784,4 +785,4 @@
/** Chinese (Hong Kong) (中文(香港)) */
$specialPageAliases['zh-hk'] = array(
'GlobalGroupMembership' => array( '全域用戶權限' ),
-);
\ No newline at end of file
+);
diff --git a/CentralAuth.i18n.php b/CentralAuth.i18n.php
index 41630a5..9088da8 100644
--- a/CentralAuth.i18n.php
+++ b/CentralAuth.i18n.php
@@ -303,6 +303,20 @@
When you [[Special:UserLogin|log in]], the central login system instructs your
browser to request this page from all linked domains, using image links.
You have requested this page without providing any authentication data, so it
does nothing.',
+ // Central login
+ 'centrallogin' => 'Central login',
+ 'centralauth-centrallogin-desc' => 'This special page is used
internally by MediaWiki.
+When you visit a linked domain while not logged in, the central login system
uses this page to determine whether you are logged in to the central domain.
+You have requested this page without providing any authentication data, so it
does nothing.',
+ 'centralauth-centrallogin-badparams' => 'Authentication parameters
specified were invalid',
+ 'centralauth-centrallogin-lostsession' => 'Session data was lost',
+ 'centralauth-centrallogin-badstate' => 'Invalid state "$1"',
+ 'centralauth-centrallogin-notposted' => 'Central login form must be
posted',
+ 'centralauth-centrallogin-badstate-central' => 'State "$1" is not valid
on the central wiki',
+ 'centralauth-centrallogin-badstate-local' => 'State "$1" is not valid
on the local wiki',
+ 'centralauth-centrallogin-badwiki' => 'The wiki "$1" is not valid for
central login',
+ 'centralauth-centrallogin-corsfail' => 'CORS origin check failed',
+
// Global group membership
'globalgroupmembership' => 'Membership in global groups',
@@ -779,6 +793,21 @@
'autologin' => '{{doc-special|AutoLogin|unlisted=1}}
See example: [[w:Special:Autologin]].',
'centralauth-autologin-desc' => 'This is the text shown on
[[Special:AutoLogin]] when this page is requested by a user, not by the
automatic global login system.',
+ 'centrallogin' => '{{doc-special|CentralLogin|unlisted=1}}
+See example: [[w:Special:CentralLogin]].',
+ 'centralauth-centrallogin-desc' => 'This is the text shown on
[[Special:CentralLogin]] when this page is requested by a user, not by the
automatic global login system.',
+ 'centralauth-centrallogin-badparams' => 'Error message when the
required authentication parameters are missing or invalid',
+ 'centralauth-centrallogin-lostsession' => 'Error message when the
session data is lost or overwritten',
+ 'centralauth-centrallogin-badstate' => 'Error message shown when an
invalid state is given for [[Special:CentralLogin]].
+* $1 - Name of the state',
+ 'centralauth-centrallogin-notposted' => 'Error message shown when
[[Special:CentralLogin]] is called in form mode with an HTTP method other than
POST',
+ 'centralauth-centrallogin-badstate-central' => 'Error message shown
when [[Special:CentralLogin]] is called on the central wiki with a state
intended for use on the local wiki.
+* $1 - Name of the state',
+ 'centralauth-centrallogin-badstate-local' => 'Error message shown when
[[Special:CentralLogin]] is called on the local wiki with a state intended for
use on the central wiki.
+* $1 - Name of the state',
+ 'centralauth-centrallogin-badwiki' => 'Error message shown when an
unacceptable wiki ID is given to [[Special:CentralLogin]].
+* $1 - The wiki ID',
+ 'centralauth-centrallogin-corsfail' => 'Error message shown when the
CORS origin check fails.',
'globalgroupmembership' => '{{doc-special|GlobalGroupMembership}}',
'globalgrouppermissions' => '{{doc-special|GlobalGroupPermissions}}
See example: [[w:Special:GlobalGroupPermissions]] and
[[w:Special:SpecialPages]]',
diff --git a/CentralAuth.php b/CentralAuth.php
index bfd06d9..eee1aeb 100644
--- a/CentralAuth.php
+++ b/CentralAuth.php
@@ -83,6 +83,11 @@
$wgCentralAuthCookiePrefix = 'centralauth_';
/**
+ * Wiki ID of the central domain.
+ */
+$wgCentralAuthCentralWiki = null;
+
+/**
* List of wiki IDs which should be called on login/logout to set third-party
* cookies for the global session state.
*
@@ -161,6 +166,7 @@
$wgAutoloadClasses['CentralAuthSuppressUserJob'] =
"$caBase/SuppressUserJob.php";
$wgAutoloadClasses['WikiSet'] = "$caBase/WikiSet.php";
$wgAutoloadClasses['SpecialAutoLogin'] =
"$caBase/specials/SpecialAutoLogin.php";
+$wgAutoloadClasses['SpecialCentralLogin'] =
"$caBase/specials/SpecialCentralLogin.php";
$wgAutoloadClasses['CentralAuthUserArray'] =
"$caBase/CentralAuthUserArray.php";
$wgAutoloadClasses['CentralAuthUserArrayFromResult'] =
"$caBase/CentralAuthUserArray.php";
$wgAutoloadClasses['SpecialGlobalGroupMembership'] =
"$caBase/specials/SpecialGlobalGroupMembership.php";
@@ -201,6 +207,8 @@
$wgHooks['MakeGlobalVariablesScript'][] =
'CentralAuthHooks::onMakeGlobalVariablesScript';
$wgHooks['SpecialPasswordResetOnSubmit'][] =
'CentralAuthHooks::onSpecialPasswordResetOnSubmit';
$wgHooks['OtherBlockLogLink'][] = 'CentralAuthHooks::getBlockLogLink';
+$wgHooks['BeforePageDisplay'][] = 'CentralAuthHooks::onBeforePageDisplay';
+$wgHooks['ResourceLoaderGetConfigVars'][] =
'CentralAuthHooks::onResourceLoaderGetConfigVars';
$wgHooks['ApiTokensGetTokenTypes'][] =
'ApiDeleteGlobalAccount::injectTokenFunction';
$wgHooks['ApiTokensGetTokenTypes'][] =
'ApiSetGlobalAccountStatus::injectTokenFunction';
@@ -232,6 +240,7 @@
$wgSpecialPages['CentralAuth'] = 'SpecialCentralAuth';
$wgSpecialPages['AutoLogin'] = 'SpecialAutoLogin';
+$wgSpecialPages['CentralLogin'] = 'SpecialCentralLogin';
$wgSpecialPages['MergeAccount'] = 'SpecialMergeAccount';
$wgSpecialPages['GlobalGroupMembership'] = 'SpecialGlobalGroupMembership';
$wgSpecialPages['GlobalGroupPermissions'] = 'SpecialGlobalGroupPermissions';
@@ -306,6 +315,10 @@
'centralauth-admin-delete-confirm',
),
) + $commonModuleInfo;
+$wgResourceModules['ext.centralauth.centrallogin'] = array(
+ 'scripts' => 'ext.centralauth.centrallogin.js',
+ 'position' => 'top',
+) + $commonModuleInfo;
$wgResourceModules['ext.centralauth.noflash'] = array(
'styles' => 'ext.centralauth.noflash.css',
diff --git a/CentralAuthHooks.php b/CentralAuthHooks.php
index 3733186..f555a03 100644
--- a/CentralAuthHooks.php
+++ b/CentralAuthHooks.php
@@ -766,6 +766,34 @@
}
/**
+ * @param &$out OutputPage
+ * @param &$skin Skin
+ * @return bool
+ */
+ static function onBeforePageDisplay( &$out, &$skin ) {
+ global $wgCentralAuthCentralWiki;
+ if ( wfWikiID() !== $wgCentralAuthCentralWiki &&
$out->getUser()->isAnon() ) {
+ $out->addModules( 'ext.centralauth.centrallogin' );
+ }
+ return true;
+ }
+
+ /**
+ * @param &$vars
+ * @return bool
+ */
+ static function onResourceLoaderGetConfigVars( &$vars ) {
+ global $wgUser, $wgCentralAuthCentralWiki;
+ if ( wfWikiID() !== $wgCentralAuthCentralWiki &&
$wgUser->isAnon() ) {
+ $vars['wgCentralAuthWikiID'] = wfWikiID();
+ $vars['wgCentralAuthCentralLoginEndpoint'] =
WikiMap::getForeignURL(
+ $wgCentralAuthCentralWiki,
'Special:CentralLogin/$1'
+ );
+ }
+ return true;
+ }
+
+ /**
* @param $auth
* @param $user User
* @param $params
diff --git a/modules/ext.centralauth.centrallogin.js
b/modules/ext.centralauth.centrallogin.js
new file mode 100644
index 0000000..557f5df
--- /dev/null
+++ b/modules/ext.centralauth.centrallogin.js
@@ -0,0 +1,131 @@
+( function ( mw, $, undefined ) {
+ // Are we already logged in?
+ if ( mw.config.get( 'wgUserName' ) !== null ) {
+ return;
+ }
+
+ // Do we already know we're logged out centrally?
+ if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Userlogin' ) {
+ if ( 'localStorage' in window && +localStorage.getItem(
'CentralAuthAnon' ) > new Date().getTime() ) {
+ return;
+ }
+
+ // Can't use $.cookie(), because we want to check this at the
top of
+ // the page and that isn't loaded until the bottom.
+ if ( /(^|; )CentralAuthAnon=1/.test( document.cookie ) ) {
+ return;
+ }
+ }
+
+ var centralEndpoint = mw.config.get(
'wgCentralAuthCentralLoginEndpoint' );
+ var localEndpoint = mw.config.get( 'wgArticlePath' ).replace( '$1',
'Special:CentralLogin/$1' );
+ var wikiId = mw.config.get( 'wgCentralAuthWikiID' );
+
+ if ( jQuery.support.cors ) {
+ // We can do AJAX calls using CORS.
+ function C1() {
+ $.ajax( {
+ url: centralEndpoint.replace( '$1', 'C1' ),
+ dataType: 'json',
+ type: 'POST',
+ data: { wikiid: wikiId },
+ xhrFields: {
+ withCredentials: true
+ },
+ success: function ( ret ) {
+ if ( ret.status === 'ok' ) {
+ if ( +ret.gu_id <= 0 ) {
+ var t = new Date();
+ t.setTime( t.getTime()
+ 86400000 );
+ if ( 'localStorage' in
window ) {
+
localStorage.setItem( 'CentralAuthAnon', t.getTime() );
+ } else {
+ document.cookie
= 'CentralAuthAnon=1; expires=' + t.toGMTString() + '; path=/';
+ }
+ } else {
+ if ( 'localStorage' in
window ) {
+
localStorage.removeItem( 'CentralAuthAnon' );
+ }
+ if ( /(^|;
)CentralAuthAnon=/.test( document.cookie ) ) {
+ document.cookie
= 'CentralAuthAnon=0; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/';
+ }
+ L1( ret.gu_id );
+ }
+ }
+ }
+ } );
+ }
+
+ function L1( gu_id ) {
+ $.ajax( {
+ url: localEndpoint.replace( '$1', 'L1' ),
+ dataType: 'json',
+ type: 'POST',
+ data: { gu_id: gu_id },
+ success: function ( ret ) {
+ if ( ret.status === 'ok' ) {
+ C2( ret.token );
+ }
+ }
+ } );
+ }
+
+ function C2( token ) {
+ $.ajax( {
+ url: centralEndpoint.replace( '$1', 'C2' ),
+ dataType: 'json',
+ type: 'POST',
+ data: { token: token, wikiid: wikiId },
+ xhrFields: {
+ withCredentials: true
+ },
+ success: function ( ret ) {
+ if ( ret.status === 'ok' ) {
+ L2();
+ }
+ }
+ } );
+ }
+
+ function L2() {
+ $.ajax( {
+ url: localEndpoint.replace( '$1', 'L2' ),
+ dataType: 'json',
+ type: 'POST',
+ data: {},
+ success: function ( ret ) {
+ if ( ret.status === 'ok' ) {
+ if ( mw.config.get(
'wgCanonicalSpecialPageName' ) === 'Userlogin' && history.length > 1 ) {
+ history.go( -1 );
+ } else {
+ location.reload( true );
+ }
+ }
+ }
+ } );
+ }
+
+ C1();
+ } else {
+ // We have to do it with an iframe.
+ $( function () {
+ var url = localEndpoint.replace( '$1', 'L0' );
+ if ( mw.config.get( 'wgCanonicalSpecialPageName' ) ===
'Userlogin' && history.length > 1 ) {
+ url += ( url.indexOf( '?' ) < 0 ? '?' : '&' ) +
'back=1';
+ }
+ $( '<iframe>' )
+ .css( {
+ position: 'absolute',
+ top: 0,
+ left: '-10px',
+ width: '1px',
+ height: '1px'
+ } )
+ .attr( {
+ src: url
+ } )
+ .appendTo( document.body );
+ } );
+ }
+
+}( mediaWiki, jQuery ) );
diff --git a/specials/SpecialCentralLogin.php b/specials/SpecialCentralLogin.php
new file mode 100644
index 0000000..db3d4db
--- /dev/null
+++ b/specials/SpecialCentralLogin.php
@@ -0,0 +1,434 @@
+<?php
+
+/**
+ * Unlisted Special page to set requisite cookies for being logged into this
wiki.
+ *
+ * @ingroup Extensions
+ */
+class SpecialCentralLogin extends UnlistedSpecialPage {
+ private $isForm = false;
+
+ function __construct() {
+ parent::__construct( 'CentralLogin' );
+ }
+
+ function execute( $par ) {
+ global $wgMemc;
+
+ switch ( $par ) {
+ case null:
+ $this->setHeaders();
+ $this->getOutput()->addWikiMsg(
'centralauth-centrallogin-desc' );
+ return;
+
+ case 'L0': // Output form for C1
+ $this->isForm = 1;
+ $data = array(
+ 'status' => 'ok',
+ 'nextState' => 'C1',
+ 'params' => array(
+ 'wikiid' => wfWikiID(),
+ ),
+ );
+ break;
+
+ case 'C1': // Query gu_id
+ $data = $this->checkInputState( $par, true );
+ if ( $data ) {
+ break;
+ }
+
+ global $wgUser;
+ $centralUser = CentralAuthUser::getInstance( $wgUser );
+ $data = array(
+ 'status' => 'ok',
+ 'nextState' => 'L1',
+ 'params' => array(
+ 'gu_id' => $centralUser ?
$centralUser->getId() : 0,
+ )
+ );
+ break;
+
+ case 'L1': // Start session for gu_id
+ $data = $this->checkInputState( $par, false );
+ if ( $data ) {
+ break;
+ }
+
+ $gu_id = +$this->getRequest()->getVal( 'gu_id', 0 );
+ if ( $gu_id <= 0 ) {
+ // Should only get here for iframe mode
+ $script = "var t = new Date();\n" .
+ "t.setTime( t.getTime() + 86400000
);\n" .
+ "if ( 'localStorage' in window ) {\n" .
+ "\tlocalStorage.setItem(
'CentralAuthAnon', t.getTime() );\n" .
+ "} else {\n" .
+ "\tdocument.cookie =
'CentralAuthAnon=1; expires=' + t.toGMTString() + '; path=/';\n" .
+ "}\n";
+ $data = array(
+ 'status' => 'script',
+ 'script' => $script,
+ );
+ break;
+ }
+
+ $script = "if ( 'localStorage' in window ) {\n" .
+ "\tlocalStorage.removeItem( 'CentralAuthAnon'
);\n" .
+ "}\n" .
+ "if ( /(^|; )CentralAuthAnon=/.test(
document.cookie ) ) {\n" .
+ "\tdocument.cookie = 'CentralAuthAnon=0;
expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/';\n" .
+ "}\n";
+
+ // Ensure that a session exists
+ if ( session_id() == '' ) {
+ wfSetupSession();
+ }
+
+ // Create memc token
+ $wikiid = wfWikiID();
+ $memcData = array(
+ 'gu_id' => $gu_id,
+ 'wikiid' => $wikiid,
+ );
+ do {
+ $token = MWCryptRand::generateHex( 32 );
+ $key = CentralAuthUser::memcKey(
'centrallogin-token', $token, $wikiid );
+ } while ( !$wgMemc->add( $key, $memcData, 10 ) );
+
+ // Save memc token for L2
+ $this->getRequest()->setSessionData(
'centrallogin-token', $token );
+
+ $data = array(
+ 'status' => 'ok',
+ 'nextState' => 'C2',
+ 'script' => $script,
+ 'params' => array(
+ 'token' => $token,
+ 'wikiid' => wfWikiID(),
+ )
+ );
+ break;
+
+ case 'C2': // Complete session for memc token
+ $data = $this->checkInputState( $par, true );
+ if ( $data ) {
+ break;
+ }
+
+ // Validate params
+ $wikiid = $this->getRequest()->getVal( 'wikiid', '' );
+ $token = $this->getRequest()->getVal( 'token', '' );
+ if ( $token === '' || $wikiid === '' ) {
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badparams' )
+ );
+ break;
+ }
+
+ // Load memc data
+ $key = CentralAuthUser::memcKey( 'centrallogin-token',
$token, $wikiid );
+ $memcData = $wgMemc->get( $key );
+ $wgMemc->delete( $key );
+
+ // Check memc data
+ global $wgUser;
+ $centralUser = CentralAuthUser::getInstance( $wgUser );
+ if ( !$memcData ||
+ $memcData['wikiid'] !== $wikiid ||
+ !$centralUser ||
+ !$centralUser->getId() ||
+ $memcData['gu_id'] != $centralUser->getId()
+ ) {
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badparams' )
+ );
+ break;
+ }
+
+ // Write info for session creation into memc
+ $memcData += array(
+ 'userName' => $centralUser->getName(),
+ 'token' => $centralUser->getAuthToken(),
+ );
+ $wgMemc->set( $key, $memcData, 10 );
+
+ $data = array(
+ 'status' => 'ok',
+ 'nextState' => 'L2',
+ 'params' => array(),
+ );
+ break;
+
+ case 'L2': // Set cookies for session in memc
+ $data = $this->checkInputState( $par, false );
+ if ( $data ) {
+ break;
+ }
+
+ // Check saved memc token
+ $token = $this->getRequest()->getSessionData(
'centrallogin-token' );
+ if ( $token === null ) {
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-lostsession' ),
+ );
+ break;
+ }
+
+ // Load memc data
+ $wikiid = wfWikiID();
+ $key = CentralAuthUser::memcKey( 'centrallogin-token',
$token, $wikiid );
+ $memcData = $wgMemc->get( $key );
+ $wgMemc->delete( $key );
+
+ // Check memc data
+ if ( !$memcData ||
+ $memcData['wikiid'] !== $wikiid ||
+ !isset( $memcData['userName'] ) ||
+ !isset( $memcData['token'] )
+ ) {
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-lostsession' ),
+ );
+ break;
+ }
+
+ // Load and check CentralAuthUser
+ $centralUser = new CentralAuthUser(
$memcData['userName'] );
+ if ( !$centralUser->getId() || $centralUser->getId() !=
$memcData['gu_id'] ) {
+ $msg = "Wrong user: expected
{$memcData['gu_id']}, got {$centralUser->getId()}";
+ wfDebug( __METHOD__ . ": $msg\n" );
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-lostsession' ),
+ );
+ break;
+ }
+ $loginResult = $centralUser->authenticateWithToken(
$memcData['token'] );
+ if ( $loginResult != 'ok' ) {
+ $msg = "Bad token: $loginResult";
+ wfDebug( __METHOD__ . ": $msg\n" );
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-lostsession' ),
+ );
+ break;
+ }
+
+ // Ok. Set cookies.
+ $centralUser->setGlobalCookies( false );
+
+ if ( $this->getRequest()->getBool( 'back' ) ) {
+ $script = 'top.history.go( -1 );';
+ } else {
+ $script = 'top.location.reload( true );';
+ }
+
+ $data = array(
+ 'status' => 'ok',
+ 'script' => $script,
+ 'params' => array(),
+ );
+ break;
+
+ default:
+ $data = array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badstate', $par ),
+ );
+ break;
+ }
+
+ $this->outputData( $data );
+ }
+
+ private function checkInputState( $par, $central ) {
+ global $wgCentralAuthCentralWiki;
+
+ $request = $this->getRequest();
+ $this->isForm = $request->getBool( 'form' );
+
+ // Make sure it was posted.
+ if ( !$request->wasPosted() && $request->getMethod() !==
'OPTIONS' ) {
+ return array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-notposted' ),
+ );
+ }
+
+ // Validate the state for this wiki
+ if ( $central ) {
+ if ( wfWikiID() !== $wgCentralAuthCentralWiki ) {
+ return array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badstate-central', $par ),
+ );
+ }
+
+ $wikiId = $request->getVal( 'wikiid' );
+ if ( $wikiId === $wgCentralAuthCentralWiki ) {
+ return array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badwiki', $wikiId ),
+ );
+ }
+ $wiki = WikiMap::getWiki( $wikiId );
+ if ( !$wiki ) {
+ return array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badwiki', $wikiId ),
+ );
+ }
+
+ // CORS request, validate origin and set CORS headers
+ if ( !$this->isForm ) {
+ $response = $request->response();
+
+ $originHeader = $request->getHeader( 'Origin' );
+ if ( $originHeader === false ) {
+ $origins = array();
+ } else {
+ $origins = explode( ' ', $originHeader
);
+ }
+
+ $wikiOrigin = 'http://' . strtolower(
$wiki->getHostname() );
+ $ok = false;
+ foreach ( $origins as $origin ) {
+ if ( $wikiOrigin === str_replace(
'https://', 'http://', strtolower( $origin ) ) ) {
+ $wikiOrigin = $origin;
+ $ok = true;
+ break;
+ }
+ }
+ if ( !$ok ) {
+ $message = HttpStatus::getMessage( 403
);
+ $response->header( "HTTP/1.1 403
$message", true, 403 );
+ return array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-corsfail' )
+ );
+ }
+
+ $response->header(
"Access-Control-Allow-Origin: $wikiOrigin" );
+ $response->header(
'Access-Control-Allow-Credentials: true' );
+ $this->getOutput()->addVaryHeader( 'Origin' );
+ }
+ } else {
+ if ( wfWikiID() === $wgCentralAuthCentralWiki ) {
+ return array(
+ 'status' => 'error',
+ 'msg' => array(
'centralauth-centrallogin-badstate-local', $par ),
+ );
+ }
+ }
+
+ if ( $request->getMethod() === 'OPTIONS' ) {
+ return array(
+ 'status' => 'cors'
+ );
+ }
+
+ return null;
+ }
+
+ private function outputData( $data ) {
+ global $wgMimeType, $wgLanguageCode;
+
+ $output = $this->getOutput();
+ $output->enableClientCache( false );
+ $output->sendCacheControl();
+ $output->disable();
+ $response = $this->getRequest()->response();
+
+ if ( !$this->isForm ) {
+ $frameOptions = $output->getFrameOptions();
+ if ( $frameOptions ) {
+ $response->header( "X-Frame-Options:
$frameOptions" );
+ }
+ }
+
+ if ( $this->isForm ) {
+ $script='';
+ $bodyParams = array();
+ $body='';
+ switch ( $data['status'] ) {
+ case 'script':
+ $script = $data['script'];
+ break;
+
+ case 'ok':
+ if ( isset( $data['script'] ) ) {
+ $script = $data['script'];
+ }
+
+ if ( isset( $data['nextState'] ) ) {
+ $script .= "\n\nfunction doSubmit()
{\n" .
+ "\tif ( document.forms[0] )
{\n" .
+
"\t\tdocument.forms[0].submit();\n" .
+ "\t}\n" .
+ "}";
+ $bodyParams['onload'] = 'doSubmit()';
+
+ if ( substr( $data['nextState'], 0, 1 )
=== 'C' ) {
+ global
$wgCentralAuthCentralWiki;
+ $target =
$wgCentralAuthCentralWiki;
+ } else {
+ $target =
$this->getRequest()->getVal( 'wikiid', wfWikiID() );
+ }
+ $body .= "\n" . Html::openElement(
'form', array(
+ 'method' => 'POST',
+ 'action' =>
WikiMap::getForeignURL( $target, 'Special:CentralLogin/' . $data['nextState'] ),
+ ) ) . "\n";
+ $body .= Html::hidden( 'form', '1' ) .
"\n";
+ if ( $this->getRequest()->getBool(
'back' ) ) {
+ $body .= Html::hidden( 'back',
'1' ) . "\n";
+ }
+ foreach ( $data['params'] as $k => $v )
{
+ $body .= Html::hidden( $k, $v )
. "\n";
+ }
+ $body .= Html::closeElement( 'form' );
+ }
+ break;
+
+ case 'error':
+ $params = $data['msg'];
+ $key = array_shift( $params );
+ $body = wfMessage( $key, $params )->escaped();
+ break;
+ }
+
+ $response->header( "Content-type: $wgMimeType;
charset=UTF-8" );
+ $response->header( 'Content-language: ' .
$wgLanguageCode );
+ print Html::htmlHeader();
+ print Html::openElement( 'head' );
+ print Html::element( 'title', null,
$output->getHTMLTitle() );
+ if ( $script !== '' ) {
+ print Html::inlineScript( $script );
+ }
+ print Html::closeElement( 'head' );
+ print Html::openElement( 'body', $bodyParams );
+ print $body;
+ print Html::closeElement( 'body' );
+ print Html::closeElement( 'html' );
+ } else {
+ $response->header( "Content-type: application/json;
charset=UTF-8" );
+ $response->header( 'Content-language: ' .
$wgLanguageCode );
+ switch ( $data['status'] ) {
+ case 'cors':
+ break;
+
+ case 'ok':
+ $data['params']['status'] = 'ok';
+ print FormatJson::encode( $data['params'] );
+ break;
+
+ default:
+ print FormatJson::encode( $data );
+ break;
+ }
+ }
+ }
+}
--
To view, visit https://gerrit.wikimedia.org/r/58924
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib6e9cce4fa4c5f1482c59bfac28087f558786efe
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CentralAuth
Gerrit-Branch: master
Gerrit-Owner: Anomie <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits