Bartosz Dziewoński has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/231711

Change subject: Implement a mediawiki.ForeignApi extension
......................................................................

Implement a mediawiki.ForeignApi extension

Extends mw.ForeignApi with CentralAuth authentication handling,
amending every request with a 'centralauthtoken' parameter, if
required.

Every request to the foreign wiki will be preceded by a
'action=centralauthtoken' request to the local wiki, except in cases
where we detect that it is unproductive or unnecessary.

Depends on Ic20b9682d28633baa87d22e6e9fb71ce507da58d in MediaWiki core.

Bug: T66636
Change-Id: I0fd05ef8b9c9db0fdb59c6cb248f364259f80456
---
M CentralAuth.php
M includes/CentralAuthHooks.php
A modules/ext.centralauth.ForeignApi.js
3 files changed, 133 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CentralAuth 
refs/changes/11/231711/1

diff --git a/CentralAuth.php b/CentralAuth.php
index 693d5de..2486625 100644
--- a/CentralAuth.php
+++ b/CentralAuth.php
@@ -388,6 +388,7 @@
 $wgHooks['UnitTestsList'][] = 'CentralAuthHooks::onUnitTestsList';
 $wgHooks['SpecialContributionsBeforeMainOutput'][] = 
'CentralAuthHooks::onSpecialContributionsBeforeMainOutput';
 $wgHooks['SpecialPage_initList'][] = 
'CentralAuthHooks::onSpecialPage_initList';
+$wgHooks['ResourceLoaderForeignApiModules'][] = 
'CentralAuthHooks::onResourceLoaderForeignApiModules';
 
 // For interaction with the Special:Renameuser extension
 $wgHooks['RenameUserWarning'][] = 'CentralAuthHooks::onRenameUserWarning';
@@ -569,5 +570,12 @@
        )
 ) + $commonModuleInfo;
 
+$wgResourceModules['ext.centralauth.ForeignApi'] = array(
+       'scripts' => 'ext.centralauth.ForeignApi.js',
+       'dependencies' => array(
+               'mw.ForeignApi.core',
+       ),
+) + $commonModuleInfo;
+
 // Finish configuration after other extensions and settings are loaded.
 $wgExtensionFunctions[] = 'CentralAuthHooks::onRunExtensionFunctions';
diff --git a/includes/CentralAuthHooks.php b/includes/CentralAuthHooks.php
index 0544cc8..5eebe80 100644
--- a/includes/CentralAuthHooks.php
+++ b/includes/CentralAuthHooks.php
@@ -2174,4 +2174,9 @@
                        );
                }
        }
+
+       public static function onResourceLoaderForeignApiModules( 
&$dependencies, ResourceLoaderContext $context = null ) {
+               $dependencies[] = 'ext.centralauth.ForeignApi';
+               return true;
+       }
 }
diff --git a/modules/ext.centralauth.ForeignApi.js 
b/modules/ext.centralauth.ForeignApi.js
new file mode 100644
index 0000000..71828e3
--- /dev/null
+++ b/modules/ext.centralauth.ForeignApi.js
@@ -0,0 +1,120 @@
+( function ( mw, $ ) {
+
+       var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+       /**
+        * Extend mw.ForeignApi with CentralAuth authentication handling.
+        *
+        * Every request to the foreign wiki will be preceded by a 
'action=centralauthtoken' request to
+        * the local wiki. The foreign request will be extended with the 
acquired token to ensure that the
+        * requests to foreign wiki will always be authenticated as the 
currently logged-in user on local
+        * wiki.
+        *
+        * If we detect that the current user is anonymous, that the foreign 
wiki doesn't have
+        * CentralAuth, or that the requests to foreign wiki will be correctly 
authenticated without
+        * sending 'centralauthtoken' every time, the additional requests will 
be skipped.
+        *
+        * @class mw.ForeignApi.plugin.CentralAuth
+        * @extends mw.ForeignApi
+        *
+        * @constructor
+        * @param {Object} [options]
+        *
+        * @author Bartosz Dziewoński
+        * @author Jon Robson
+        */
+       function CentralAuthForeignApi( options ) {
+               var foreignApi = this;
+               this.localApi = new mw.Api();
+               // If this is set, the additional requests for 
'centralauthtoken' will always be skipped
+               this.noTokenEver = false;
+
+               // Call parent constructor
+               CentralAuthForeignApi.parent.call( this, options );
+
+               if ( !options || !options.url ) {
+                       // Actually a local API
+                       this.noTokenEver = true;
+               } else if ( mw.config.get( 'wgUserName' ) === null ) {
+                       // Anonymous users cannot obtain a centralauthtoken
+                       this.noTokenEver = true;
+               } else {
+                       // We're logged in here, check to see if we're logged 
in on the foreign wiki too, and thus can
+                       // skip 'centralauthtoken' requests
+                       CentralAuthForeignApi.parent.prototype.get.call( this, 
{ action: 'query', meta: 'userinfo' } )
+                               .done( function ( resp ) {
+                                       var userinfo = resp.query.userinfo;
+                                       if ( userinfo.anon === undefined && 
userinfo.name === mw.config.get( 'wgUserName' ) ) {
+                                               // We are logged in on the 
foreign wiki
+                                               foreignApi.noTokenEver = true;
+                                       }
+                               } );
+               }
+       }
+
+       OO.inheritClass( CentralAuthForeignApi, mw.ForeignApi );
+
+       /**
+        * Get a 'centralauthtoken' from the local wiki for use on the foreign 
wiki.
+        *
+        * @private
+        * @return {jQuery.Promise}
+        */
+       CentralAuthForeignApi.prototype.getCentralAuthToken = function () {
+               var foreignApi = this;
+               return this.localApi.get( { action: 'centralauthtoken' } 
).then( function ( resp ) {
+                       if ( resp.error ) {
+                               // Check some known cases where we'll never get 
a token, to avoid wasting requests
+                               if ( resp.error.code === 'notloggedin' ) {
+                                       // Anonymous users cannot obtain a 
centralauthtoken
+                                       foreignApi.noTokenEver = true;
+                               }
+                               if ( resp.error.code === 'unknown_action' ) {
+                                       // Remote wiki doesn't have CentralAuth 
installed
+                                       foreignApi.noTokenEver = true;
+                               }
+                               return $.Deferred().reject( resp.error );
+                       } else {
+                               return resp.centralauthtoken.centralauthtoken;
+                       }
+               } );
+       };
+
+       /**
+        * @inheritdoc
+        */
+       CentralAuthForeignApi.prototype.ajax = function ( parameters, 
ajaxOptions ) {
+               var tokenPromise, foreignApi = this;
+               // If we know we can't get a 'centralauthtoken', or if one was 
provided, don't request it
+               if ( this.noTokenEver || hasOwnProperty.call( parameters, 
'centralauthtoken' ) ) {
+                       tokenPromise = $.Deferred().reject().promise();
+               } else {
+                       tokenPromise = this.getCentralAuthToken();
+               }
+
+               return tokenPromise.then(
+                       function ( centralAuthToken ) {
+                               var url, newParameters, newAjaxOptions;
+
+                               // Add 'centralauthtoken' query parameter. Per 
API documentation, it must also be part of
+                               // the request URI, and not just request body 
(even in case of POST requests).
+                               newParameters = $.extend( { centralauthtoken: 
centralAuthToken }, parameters );
+                               url = ( ajaxOptions && ajaxOptions.url ) || 
foreignApi.defaults.ajax.url;
+                               url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' 
) +
+                                       'centralauthtoken=' + 
encodeURIComponent( centralAuthToken );
+                               newAjaxOptions = $.extend( {}, ajaxOptions, { 
url: url } );
+
+                               return 
CentralAuthForeignApi.parent.prototype.ajax.call( foreignApi, newParameters, 
newAjaxOptions );
+                       },
+                       function () {
+                               // We couldn't get the token, but continue 
anyway. This is expected in some cases, like
+                               // anonymous users.
+                               return 
CentralAuthForeignApi.parent.prototype.ajax.call( foreignApi, parameters, 
ajaxOptions );
+                       }
+               );
+       };
+
+       // Expose
+       mw.ForeignApi = CentralAuthForeignApi;
+
+}( mediaWiki, jQuery ) );

-- 
To view, visit https://gerrit.wikimedia.org/r/231711
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0fd05ef8b9c9db0fdb59c6cb248f364259f80456
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CentralAuth
Gerrit-Branch: master
Gerrit-Owner: Bartosz Dziewoński <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to