summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'OAuth/src/Repository/ScopeRepository.php')
-rw-r--r--OAuth/src/Repository/ScopeRepository.php116
1 files changed, 116 insertions, 0 deletions
diff --git a/OAuth/src/Repository/ScopeRepository.php b/OAuth/src/Repository/ScopeRepository.php
new file mode 100644
index 00000000..5c6a5979
--- /dev/null
+++ b/OAuth/src/Repository/ScopeRepository.php
@@ -0,0 +1,116 @@
+<?php
+
+namespace MediaWiki\Extensions\OAuth\Repository;
+
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
+use MediaWiki\Extensions\OAuth\Backend\MWOAuthException;
+use MediaWiki\Extensions\OAuth\Backend\Utils;
+use MediaWiki\Extensions\OAuth\Entity\ClientEntity;
+use MediaWiki\Extensions\OAuth\Entity\ScopeEntity;
+use MediaWiki\Extensions\OAuth\Entity\UserEntity;
+use MWGrants;
+
+class ScopeRepository implements ScopeRepositoryInterface {
+ /**
+ * @var array
+ */
+ protected $allowedScopes = [
+ '#default',
+ 'mwoauth-authonly',
+ 'mwoauth-authonlyprivate'
+ ];
+
+ public function __construct() {
+ $this->allowedScopes = array_merge( $this->allowedScopes, MWGrants::getValidGrants() );
+ }
+
+ /**
+ * Return information about a scope.
+ *
+ * @param string $identifier The scope identifier
+ *
+ * @return ScopeEntityInterface|null
+ */
+ public function getScopeEntityByIdentifier( $identifier ) {
+ if ( in_array( $identifier, $this->allowedScopes, true ) ) {
+ return new ScopeEntity( $identifier );
+ }
+
+ return null;
+ }
+
+ /**
+ * Given a client, grant type and optional user identifier
+ * validate the set of scopes requested are valid and optionally
+ * append additional scopes or remove requested scopes.
+ *
+ * @param ScopeEntityInterface[] $scopes
+ * @param string $grantType
+ * @param ClientEntityInterface|ClientEntity $clientEntity
+ * @param null|string $userIdentifier
+ *
+ * @return ScopeEntityInterface[]
+ */
+ public function finalizeScopes( array $scopes, $grantType,
+ ClientEntityInterface $clientEntity, $userIdentifier = null ) {
+ $scopes = $this->replaceDefaultScope( $scopes, $clientEntity );
+
+ if ( $grantType !== 'authorization_code' ) {
+ // For grants that do not require approval,
+ // just filter out the scopes that are not allowed for the client
+ return array_filter(
+ $scopes,
+ function ( ScopeEntityInterface $scope ) use ( $clientEntity ) {
+ return in_array( $scope->getIdentifier(), $clientEntity->getGrants(), true );
+ }
+ );
+ }
+ if ( !is_numeric( $userIdentifier ) ) {
+ return [];
+ }
+
+ $mwUser = Utils::getLocalUserFromCentralId( $userIdentifier );
+ $userEntity = UserEntity::newFromMWUser( $mwUser );
+ if ( $userEntity === null ) {
+ return [];
+ }
+
+ // Filter out not approved scopes
+ try {
+ $approval = $clientEntity->getCurrentAuthorization( $mwUser, wfWikiID() );
+ $approvedScopeIds = $approval->getGrants();
+ } catch ( MWOAuthException $ex ) {
+ $approvedScopeIds = [];
+ }
+
+ return array_filter(
+ $scopes,
+ function ( ScopeEntityInterface $scope ) use ( $approvedScopeIds ) {
+ return in_array( $scope->getIdentifier(), $approvedScopeIds, true );
+ }
+ );
+ }
+
+ /**
+ * Detect "#default" scope and replace it with all client's allowed scopes
+ *
+ * @param array $scopes
+ * @param ClientEntityInterface|ClientEntity $client
+ * @return array
+ */
+ private function replaceDefaultScope( array $scopes, ClientEntityInterface $client ) {
+ // Normally, #default scope would be an only scope set, but go through whole array in case
+ // someone explicitly made a request with that scope set
+ $index = array_search( '#default', array_map( function ( ScopeEntityInterface $scope ) {
+ return $scope->getIdentifier();
+ }, $scopes ) );
+
+ if ( $index === false ) {
+ return $scopes;
+ }
+
+ return $client->getScopes();
+ }
+}