From f7ed8615e145f0ad8595fbb48e09c4ed08770966 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Tue, 9 Jul 2019 12:39:06 +1000 Subject: [PATCH] REST: add write access checks to BasicAccess This is a stub implementation which just checks for the apiwrite permission. Change-Id: Ib84cd93e7f0f5e31cf620b2d30609035c4448c95 --- .../BasicAccess/BasicAuthorizerInterface.php | 2 +- .../BasicAccess/BasicRequestAuthorizer.php | 14 ++++++- .../BasicAccess/MWBasicRequestAuthorizer.php | 6 ++- .../MWBasicRequestAuthorizerTest.php | 37 +++++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/includes/Rest/BasicAccess/BasicAuthorizerInterface.php b/includes/Rest/BasicAccess/BasicAuthorizerInterface.php index 7eb7f3fba1..64143d4f4b 100644 --- a/includes/Rest/BasicAccess/BasicAuthorizerInterface.php +++ b/includes/Rest/BasicAccess/BasicAuthorizerInterface.php @@ -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. diff --git a/includes/Rest/BasicAccess/BasicRequestAuthorizer.php b/includes/Rest/BasicAccess/BasicRequestAuthorizer.php index f940589a59..2c977324b8 100644 --- a/includes/Rest/BasicAccess/BasicRequestAuthorizer.php +++ b/includes/Rest/BasicAccess/BasicRequestAuthorizer.php @@ -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(); } diff --git a/includes/Rest/BasicAccess/MWBasicRequestAuthorizer.php b/includes/Rest/BasicAccess/MWBasicRequestAuthorizer.php index 01367d1b13..8c459c63f4 100644 --- a/includes/Rest/BasicAccess/MWBasicRequestAuthorizer.php +++ b/includes/Rest/BasicAccess/MWBasicRequestAuthorizer.php @@ -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 ); } diff --git a/tests/phpunit/includes/Rest/BasicAccess/MWBasicRequestAuthorizerTest.php b/tests/phpunit/includes/Rest/BasicAccess/MWBasicRequestAuthorizerTest.php index 5a16434c23..076ff3643b 100644 --- a/tests/phpunit/includes/Rest/BasicAccess/MWBasicRequestAuthorizerTest.php +++ b/tests/phpunit/includes/Rest/BasicAccess/MWBasicRequestAuthorizerTest.php @@ -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() ); + } } -- 2.20.1