New convenience method ApiBase::lacksSameOriginSecurity()
authorRicordisamoa <ricordisamoa@openmailbox.org>
Wed, 17 Dec 2014 11:09:04 +0000 (11:09 +0000)
committerBrad Jorsch <bjorsch@wikimedia.org>
Fri, 27 Feb 2015 14:48:37 +0000 (09:48 -0500)
For consistent handling of API requests with the 'callback' argument.

Change-Id: Ic6e3483f5e8819498c693650a11728efc1bafcc0

13 files changed:
RELEASE-NOTES-1.25
includes/api/ApiBase.php
includes/api/ApiCreateAccount.php
includes/api/ApiLogin.php
includes/api/ApiMain.php
includes/api/ApiQueryDeletedrevs.php
includes/api/ApiQueryInfo.php
includes/api/ApiQueryRecentChanges.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQueryTokens.php
includes/api/ApiQueryUserInfo.php
includes/api/ApiQueryUsers.php
includes/api/ApiTokens.php

index f365d70..45e669a 100644 (file)
@@ -261,6 +261,9 @@ production.
   to allow generators to include data in the action=query result.
 * New hooks 'ApiMain::moduleManager' and 'ApiQuery::moduleManager', can be
   used for conditional registration of API modules.
+* Added ApiBase::lacksSameOriginSecurity() to allow modules to easily check if
+  the current request was sent with the 'callback' parameter (or any future
+  method that breaks the same-origin policy).
 * The following methods have been deprecated and may be removed in a future
   release:
   * ApiBase::getDescription
index 3a31b2a..be5a9c3 100644 (file)
@@ -380,6 +380,20 @@ abstract class ApiBase extends ContextSource {
                return $this->isMain() ? null : $this->getMain();
        }
 
+       /**
+        * Returns true if the current request breaks the same-origin policy.
+        *
+        * For example, json with callbacks.
+        *
+        * https://en.wikipedia.org/wiki/Same-origin_policy
+        *
+        * @since 1.25
+        * @return bool
+        */
+       public function lacksSameOriginSecurity() {
+               return $this->getMain()->getRequest()->getVal( 'callback' ) !== null;
+       }
+
        /**
         * Get the path to this module
         *
index a7ba48a..b56a244 100644 (file)
  */
 class ApiCreateAccount extends ApiBase {
        public function execute() {
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
-                       $this->dieUsage( 'Cannot create account when using a callback', 'aborted' );
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
+                       $this->dieUsage(
+                               'Cannot create account when the same-origin policy is not applied', 'aborted'
+                       );
                }
 
                // $loginForm->addNewaccountInternal will throw exceptions
index 920dbbf..5480d94 100644 (file)
@@ -46,11 +46,12 @@ class ApiLogin extends ApiBase {
         * is reached. The expiry is $this->mLoginThrottle.
         */
        public function execute() {
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        $this->getResult()->addValue( null, 'login', array(
                                'result' => 'Aborted',
-                               'reason' => 'Cannot log in when using a callback',
+                               'reason' => 'Cannot log in when the same-origin policy is not applied',
                        ) );
 
                        return;
index fe01f11..d5cd475 100644 (file)
@@ -181,10 +181,10 @@ class ApiMain extends ApiBase {
                        // Remove all modules other than login
                        global $wgUser;
 
-                       if ( $this->getVal( 'callback' ) !== null ) {
-                               // JSON callback allows cross-site reads.
-                               // For safety, strip user credentials.
-                               wfDebug( "API: stripping user credentials for JSON callback\n" );
+                       if ( $this->lacksSameOriginSecurity() ) {
+                               // If we're in a mode that breaks the same-origin policy, strip
+                               // user credentials for security.
+                               wfDebug( "API: stripping user credentials when the same-origin policy is not applied\n" );
                                $wgUser = new User();
                                $this->getContext()->setUser( $wgUser );
                        }
index f828255..f46fb34 100644 (file)
@@ -75,8 +75,9 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
                        );
                }
 
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        $fld_token = false;
                }
 
index 02c88c4..5af44ee 100644 (file)
@@ -90,8 +90,9 @@ class ApiQueryInfo extends ApiQueryBase {
                        return $this->tokenFunctions;
                }
 
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        return array();
                }
 
index bfdc5ab..1482034 100644 (file)
@@ -56,8 +56,9 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                        return $this->tokenFunctions;
                }
 
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        return array();
                }
 
index 7092fc4..552ca3b 100644 (file)
@@ -53,8 +53,9 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                        return $this->tokenFunctions;
                }
 
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        return array();
                }
 
index 2e107ac..f8eee8d 100644 (file)
@@ -37,8 +37,8 @@ class ApiQueryTokens extends ApiQueryBase {
                $params = $this->extractRequestParams();
                $res = array();
 
-               if ( $this->getMain()->getRequest()->getVal( 'callback' ) !== null ) {
-                       $this->setWarning( 'Tokens may not be obtained when using a callback' );
+               if ( $this->lacksSameOriginSecurity() ) {
+                       $this->setWarning( 'Tokens may not be obtained when the same-origin policy is not applied' );
                        return;
                }
 
index 7fc0ba8..1e3a432 100644 (file)
@@ -115,7 +115,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
                        );
                }
                if ( isset( $this->prop['preferencestoken'] ) &&
-                       is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) &&
+                       !$this->lacksSameOriginSecurity() &&
                        $user->isAllowed( 'editmyoptions' )
                ) {
                        $vals['preferencestoken'] = $user->getEditToken( '', $this->getMain()->getRequest() );
index b7f2f9a..52636cc 100644 (file)
@@ -67,8 +67,9 @@ class ApiQueryUsers extends ApiQueryBase {
                        return $this->tokenFunctions;
                }
 
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        return array();
                }
 
index 073495c..9eb4020 100644 (file)
@@ -54,8 +54,9 @@ class ApiTokens extends ApiBase {
        }
 
        private function getTokenTypes() {
-               // If we're in JSON callback mode, no tokens can be obtained
-               if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
+               // If we're in a mode that breaks the same-origin policy, no tokens can
+               // be obtained
+               if ( $this->lacksSameOriginSecurity() ) {
                        return array();
                }