REST: add write access checks to BasicAccess
authorTim Starling <tstarling@wikimedia.org>
Tue, 9 Jul 2019 02:39:06 +0000 (12:39 +1000)
committerTim Starling <tstarling@wikimedia.org>
Tue, 9 Jul 2019 05:23:57 +0000 (15:23 +1000)
This is a stub implementation which just checks for the apiwrite
permission.

Change-Id: Ib84cd93e7f0f5e31cf620b2d30609035c4448c95

includes/Rest/BasicAccess/BasicAuthorizerInterface.php
includes/Rest/BasicAccess/BasicRequestAuthorizer.php
includes/Rest/BasicAccess/MWBasicRequestAuthorizer.php
tests/phpunit/includes/Rest/BasicAccess/MWBasicRequestAuthorizerTest.php

index 7eb7f3f..64143d4 100644 (file)
@@ -14,7 +14,7 @@ use MediaWiki\Rest\RequestInterface;
 interface BasicAuthorizerInterface {
        /**
         * Determine whether a request should be permitted, given the handler's
-        * needsReadAccess().
+        * needsReadAccess() and needsWriteAccess().
         *
         * If the request should be permitted, return null. If the request should
         * be denied, return a string error identifier.
index f940589..2c97732 100644 (file)
@@ -6,8 +6,8 @@ use MediaWiki\Rest\Handler;
 use MediaWiki\Rest\RequestInterface;
 
 /**
- * A request authorizer which checks needsReadAccess() in the
- * handler and calls isReadAllowed() in the subclass
+ * A request authorizer which checks needsReadAccess() and needsWriteAccess() in the
+ * handler and calls isReadAllowed() and/or isWriteAllowed() in the subclass
  * accordingly.
  *
  * @internal
@@ -34,6 +34,9 @@ abstract class BasicRequestAuthorizer {
                if ( $this->handler->needsReadAccess() && !$this->isReadAllowed() ) {
                        return 'rest-read-denied';
                }
+               if ( $this->handler->needsWriteAccess() && !$this->isWriteAllowed() ) {
+                       return 'rest-write-denied';
+               }
                return null;
        }
 
@@ -43,4 +46,11 @@ abstract class BasicRequestAuthorizer {
         * @return bool
         */
        abstract protected function isReadAllowed();
+
+       /**
+        * Check if the current user is allowed to write to the wiki
+        *
+        * @return bool
+        */
+       abstract protected function isWriteAllowed();
 }
index 01367d1..8c459c6 100644 (file)
@@ -8,7 +8,7 @@ use MediaWiki\Rest\Handler;
 use MediaWiki\Rest\RequestInterface;
 
 /**
- * The concrete implementation of basic read restrictions in MediaWiki
+ * The concrete implementation of basic read/write restrictions in MediaWiki
  *
  * @internal
  */
@@ -32,6 +32,10 @@ class MWBasicRequestAuthorizer extends BasicRequestAuthorizer {
                   || $this->isAllowed( 'read' );
        }
 
+       protected function isWriteAllowed() {
+               return $this->isAllowed( 'writeapi' );
+       }
+
        private function isAllowed( $action ) {
                return $this->permissionManager->userHasRight( $this->user, $action );
        }
index 5a16434..076ff36 100644 (file)
@@ -5,6 +5,7 @@ namespace MediaWiki\Tests\Rest\BasicAccess;
 use GuzzleHttp\Psr7\Uri;
 use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Rest\BasicAccess\MWBasicAuthorizer;
+use MediaWiki\Rest\Handler;
 use MediaWiki\Rest\RequestData;
 use MediaWiki\Rest\ResponseFactory;
 use MediaWiki\Rest\Router;
@@ -70,4 +71,40 @@ class MWBasicRequestAuthorizerTest extends MediaWikiTestCase {
                $response = $router->execute( $request );
                $this->assertSame( 200, $response->getStatusCode() );
        }
+
+       public static function writeHandlerFactory() {
+               return new class extends Handler {
+                       public function needsWriteAccess() {
+                               return true;
+                       }
+
+                       public function execute() {
+                               return '';
+                       }
+               };
+       }
+
+       public function testWriteDenied() {
+               $router = $this->createRouter( [ 'read' => true, 'writeapi' => false ] );
+               $request = new RequestData( [
+                       'uri' => new Uri( '/rest/mock/MWBasicRequestAuthorizerTest/write' )
+               ] );
+               $response = $router->execute( $request );
+               $this->assertSame( 403, $response->getStatusCode() );
+
+               $body = $response->getBody();
+               $body->rewind();
+               $data = json_decode( $body->getContents(), true );
+               $this->assertSame( 'rest-write-denied', $data['error'] );
+       }
+
+       public function testWriteAllowed() {
+               $router = $this->createRouter( [ 'read' => true, 'writeapi' => true ] );
+               $request = new RequestData( [
+                       'uri' => new Uri( '/rest/mock/MWBasicRequestAuthorizerTest/write' )
+               ] );
+               $response = $router->execute( $request );
+
+               $this->assertSame( 200, $response->getStatusCode() );
+       }
 }