Daniel Kinzler has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/397899 )

Change subject: Make wbsetclaim and friends check entity permissions.
......................................................................

Make wbsetclaim and friends check entity permissions.

wbsetclaim, wbsetclaimvalue, wbsetqualifier, and wbsetreference did not
check user permissions against the actions required by the respective ChangeOp.

Since we currently do not have special permissions defined for modifying 
Statements,
this was not a problem in practice. BUt it's an incosistency that may lead to
nasty surprises down the road.

Change-Id: Ie0d83165508723f89b3a6e9bac6c4704237c7d5a
---
M repo/includes/Api/CreateClaim.php
M repo/includes/Api/SetClaim.php
M repo/includes/Api/SetClaimValue.php
M repo/includes/Api/SetQualifier.php
M repo/includes/Api/SetReference.php
M repo/includes/Api/StatementModificationHelper.php
M repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php
7 files changed, 105 insertions(+), 5 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase 
refs/changes/99/397899/1

diff --git a/repo/includes/Api/CreateClaim.php 
b/repo/includes/Api/CreateClaim.php
index 1224620..4ced0b3 100644
--- a/repo/includes/Api/CreateClaim.php
+++ b/repo/includes/Api/CreateClaim.php
@@ -95,6 +95,7 @@
                /* @var ChangeOpMainSnak $changeOp */
                $changeOp = $this->statementChangeOpFactory->newSetMainSnakOp( 
'', $snak );
 
+               $this->modificationHelper->checkPermissions( $entity, 
$this->getUser(), $changeOp );
                $this->modificationHelper->applyChangeOp( $changeOp, $entity, 
$summary );
 
                $statement = 
$entity->getStatements()->getFirstStatementWithGuid( 
$changeOp->getStatementGuid() );
diff --git a/repo/includes/Api/SetClaim.php b/repo/includes/Api/SetClaim.php
index 7f0a164..37cc663 100644
--- a/repo/includes/Api/SetClaim.php
+++ b/repo/includes/Api/SetClaim.php
@@ -132,6 +132,7 @@
 
                $index = isset( $params['index'] ) ? $params['index'] : null;
                $changeop = $this->statementChangeOpFactory->newSetStatementOp( 
$statement, $index );
+               $this->modificationHelper->checkPermissions( $entity, 
$this->getUser(), $changeop );
                $this->modificationHelper->applyChangeOp( $changeop, $entity, 
$summary );
 
                $status = $this->entitySavingHelper->attemptSaveEntity( 
$entity, $summary );
diff --git a/repo/includes/Api/SetClaimValue.php 
b/repo/includes/Api/SetClaimValue.php
index ed76bab..e3d00ed 100644
--- a/repo/includes/Api/SetClaimValue.php
+++ b/repo/includes/Api/SetClaimValue.php
@@ -96,6 +96,7 @@
 
                $changeOp = $this->statementChangeOpFactory->newSetMainSnakOp( 
$guid, $snak );
 
+               $this->modificationHelper->checkPermissions( $entity, 
$this->getUser(), $changeOp );
                $this->modificationHelper->applyChangeOp( $changeOp, $entity, 
$summary );
 
                $status = $this->entitySavingHelper->attemptSaveEntity( 
$entity, $summary );
diff --git a/repo/includes/Api/SetQualifier.php 
b/repo/includes/Api/SetQualifier.php
index 34be6a2..07dc96e 100644
--- a/repo/includes/Api/SetQualifier.php
+++ b/repo/includes/Api/SetQualifier.php
@@ -102,6 +102,7 @@
                }
 
                $changeOp = $this->getChangeOp();
+               $this->modificationHelper->checkPermissions( $entity, 
$this->getUser(), $changeOp );
                $this->modificationHelper->applyChangeOp( $changeOp, $entity, 
$summary );
 
                $status = $this->entitySavingHelper->attemptSaveEntity( 
$entity, $summary );
diff --git a/repo/includes/Api/SetReference.php 
b/repo/includes/Api/SetReference.php
index 8f4d060..5626a44 100644
--- a/repo/includes/Api/SetReference.php
+++ b/repo/includes/Api/SetReference.php
@@ -129,6 +129,7 @@
                $newReference = new Reference( $snakList );
 
                $changeOp = $this->getChangeOp( $newReference );
+               $this->modificationHelper->checkPermissions( $entity, 
$this->getUser(), $changeOp );
                $this->modificationHelper->applyChangeOp( $changeOp, $entity, 
$summary );
 
                $status = $this->entitySavingHelper->attemptSaveEntity( 
$entity, $summary );
diff --git a/repo/includes/Api/StatementModificationHelper.php 
b/repo/includes/Api/StatementModificationHelper.php
index 78c729c..39bc1ee 100644
--- a/repo/includes/Api/StatementModificationHelper.php
+++ b/repo/includes/Api/StatementModificationHelper.php
@@ -7,6 +7,8 @@
 use LogicException;
 use OutOfBoundsException;
 use ApiUsageException;
+use Status;
+use User;
 use Wikibase\Repo\ChangeOp\ChangeOp;
 use Wikibase\Repo\ChangeOp\ChangeOpException;
 use Wikibase\Repo\ChangeOp\ChangeOpValidationException;
@@ -21,6 +23,7 @@
 use Wikibase\DataModel\Statement\Statement;
 use Wikibase\DataModel\Statement\StatementListProvider;
 use Wikibase\Repo\SnakFactory;
+use Wikibase\Repo\Store\EntityPermissionChecker;
 use Wikibase\Summary;
 
 /**
@@ -46,23 +49,31 @@
        private $guidValidator;
 
        /**
-        * @var ApiErrorReporter
-        *
+        * @var EntityPermissionChecker
+        */
+       private $permissionChecker;
+
+       /**
         * @param SnakFactory $snakFactory
         * @param EntityIdParser $entityIdParser
         * @param StatementGuidValidator $guidValidator
         * @param ApiErrorReporter $errorReporter
+        * @param EntityPermissionChecker $permissionChecker
+        * @internal param ApiErrorReporter $
+        *
         */
        public function __construct(
                SnakFactory $snakFactory,
                EntityIdParser $entityIdParser,
                StatementGuidValidator $guidValidator,
-               ApiErrorReporter $errorReporter
+               ApiErrorReporter $errorReporter,
+               EntityPermissionChecker $permissionChecker
        ) {
                $this->snakFactory = $snakFactory;
                $this->entityIdParser = $entityIdParser;
                $this->guidValidator = $guidValidator;
                $this->errorReporter = $errorReporter;
+               $this->permissionChecker = $permissionChecker;
        }
 
        /**
@@ -165,6 +176,32 @@
        }
 
        /**
+        * Check permission to apply the ChangeOp. If permission checks fail,
+        * this calls ApiErrorReporter::dieStatus() which causes the an 
exception
+        * that lets the API request fail.
+        *
+        * @param EntityDocument $entity the entity to check
+        * @param User $user User doing the action
+        * @param ChangeOp $changeOp
+        */
+       public function checkPermissions( EntityDocument $entity, User $user, 
ChangeOp $changeOp ) {
+               $status = Status::newGood();
+
+               foreach ( $changeOp->getActions() as $perm ) {
+                       $permStatus = 
$this->permissionChecker->getPermissionStatusForEntity(
+                               $user,
+                               $perm,
+                               $entity
+                       );
+                       $status->merge( $permStatus );
+               }
+
+               if ( !$status->isOK() ) {
+                       $this->errorReporter->dieStatus( $status, 
'permissiondenied' );
+               }
+       }
+
+       /**
         * Applies the given ChangeOp to the given Entity.
         * Any ChangeOpException is converted into an ApiUsageException with 
the code 'modification-failed'.
         *
diff --git 
a/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php 
b/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php
index 3241209..0c468c7 100644
--- a/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php
+++ b/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php
@@ -5,6 +5,8 @@
 use ApiMain;
 use DataValues\StringValue;
 use RuntimeException;
+use Status;
+use User;
 use ValueValidators\Result;
 use Wikibase\Repo\ChangeOp\ChangeOp;
 use Wikibase\Repo\ChangeOp\ChangeOpException;
@@ -19,6 +21,7 @@
 use Wikibase\Repo\Api\CreateClaim;
 use Wikibase\Repo\Api\StatementModificationHelper;
 use Wikibase\Repo\SnakFactory;
+use Wikibase\Repo\Store\EntityPermissionChecker;
 use Wikibase\Repo\WikibaseRepo;
 
 /**
@@ -81,7 +84,8 @@
                        $wikibaseRepo->getSnakFactory(),
                        $wikibaseRepo->getEntityIdParser(),
                        $wikibaseRepo->getStatementGuidValidator(),
-                       $apiHelperFactory->getErrorReporter( $apiMain )
+                       $apiHelperFactory->getErrorReporter( $apiMain ),
+                       $this->newPermissionChecker()
                );
 
                return new CreateClaim(
@@ -129,6 +133,32 @@
 
                $this->setExpectedException( RuntimeException::class, 
'no-such-claim' );
                $helper->getStatementFromEntity( 'unknown', $entity );
+       }
+
+       public function testCheckPermission_passesWhenPermissionGranted() {
+               $helper = $this->getNewInstance();
+
+               $changeOp = $this->getMock( ChangeOp::class );
+               $changeOp->method( 'getActions' )
+                       ->will( $this->returnValue( [ 'test' ] ) );
+
+               $user = $this->getTestUser()->getUser();
+               $helper->checkPermissions( new Item(), $user, $changeOp );
+
+               $this->assertTrue( true ); // dummy, we just have to get here
+       }
+
+       public function testCheckPermission_reportsErrorWhenPermissionDenied() {
+               $helper = $this->getNewInstance();
+
+               $changeOp = $this->getMock( ChangeOp::class );
+               $changeOp->method( 'getActions' )
+                       ->will( $this->returnValue( [ 'bad' ] ) );
+
+               $this->setExpectedException( RuntimeException::class, 
'permissiondenied' );
+
+               $user = $this->getTestUser()->getUser();
+               $helper->checkPermissions( new Item(), $user, $changeOp );
        }
 
        public function testApplyChangeOp_validatesAndAppliesChangeOp() {
@@ -189,7 +219,8 @@
                        $this->getMockBuilder( SnakFactory::class 
)->disableOriginalConstructor()->getMock(),
                        $entityIdParser,
                        new StatementGuidValidator( $entityIdParser ),
-                       $errorReporter ?: $this->newApiErrorReporter()
+                       $errorReporter ?: $this->newApiErrorReporter(),
+                       $this->newPermissionChecker()
                );
        }
 
@@ -211,7 +242,34 @@
                                throw new RuntimeException( $message );
                        } ) );
 
+               $errorReporter->method( 'dieStatus' )
+                       ->will( $this->returnCallback( function ( Status 
$status, $description ) {
+                               throw new RuntimeException( $description . ': ' 
. $status->getWikiText() );
+                       } ) );
+
                return $errorReporter;
        }
 
+       /**
+        * @return EntityPermissionChecker
+        */
+       private function newPermissionChecker() {
+               $permissionChecker = $this->getMockBuilder( 
EntityPermissionChecker::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $permissionChecker->method( 'getPermissionStatusForEntity' )
+                       ->will( $this->returnCallback(
+                               function ( User $user, $action, EntityDocument 
$entity, $quick = '' ) {
+                                       if ( $action === 'bad' ) {
+                                               return Status::newFatal( 'bad' 
);
+                                       } else {
+                                               return Status::newGood();
+                                       }
+                               }
+                       ) );
+
+               return $permissionChecker;
+       }
+
 }

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie0d83165508723f89b3a6e9bac6c4704237c7d5a
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to