Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
13.16% |
5 / 38 |
|
40.00% |
2 / 5 |
CRAP | |
0.00% |
0 / 1 |
ScopeRepository | |
13.16% |
5 / 38 |
|
40.00% |
2 / 5 |
106.31 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getAllowedScopes | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getScopeEntityByIdentifier | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
finalizeScopes | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
42 | |||
replaceDefaultScope | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\OAuth\Repository; |
4 | |
5 | use League\OAuth2\Server\Entities\ClientEntityInterface; |
6 | use League\OAuth2\Server\Entities\ScopeEntityInterface; |
7 | use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; |
8 | use MediaWiki\Extension\OAuth\Backend\MWOAuthException; |
9 | use MediaWiki\Extension\OAuth\Backend\Utils; |
10 | use MediaWiki\Extension\OAuth\Entity\ClientEntity; |
11 | use MediaWiki\Extension\OAuth\Entity\ScopeEntity; |
12 | use MediaWiki\Extension\OAuth\Entity\UserEntity; |
13 | use MediaWiki\MediaWikiServices; |
14 | use MediaWiki\WikiMap\WikiMap; |
15 | |
16 | class ScopeRepository implements ScopeRepositoryInterface { |
17 | /** |
18 | * @var string[] |
19 | */ |
20 | protected $allowedScopes = [ |
21 | '#default', |
22 | 'mwoauth-authonly', |
23 | 'mwoauth-authonlyprivate' |
24 | ]; |
25 | |
26 | public function __construct() { |
27 | $grantsInfo = MediaWikiServices::getInstance()->getGrantsInfo(); |
28 | $this->allowedScopes = array_merge( $this->allowedScopes, $grantsInfo->getValidGrants() ); |
29 | } |
30 | |
31 | /** |
32 | * @return string[] |
33 | */ |
34 | public function getAllowedScopes() { |
35 | return $this->allowedScopes; |
36 | } |
37 | |
38 | /** |
39 | * Return information about a scope. |
40 | * |
41 | * @param string $identifier The scope identifier |
42 | * |
43 | * @return ScopeEntityInterface|null |
44 | */ |
45 | public function getScopeEntityByIdentifier( $identifier ) { |
46 | if ( in_array( $identifier, $this->allowedScopes, true ) ) { |
47 | return new ScopeEntity( $identifier ); |
48 | } |
49 | |
50 | return null; |
51 | } |
52 | |
53 | /** |
54 | * Given a client, grant type and optional user identifier |
55 | * validate the set of scopes requested are valid and optionally |
56 | * append additional scopes or remove requested scopes. |
57 | * |
58 | * @param ScopeEntityInterface[] $scopes |
59 | * @param string $grantType |
60 | * @param ClientEntityInterface|ClientEntity $clientEntity |
61 | * @param null|string $userIdentifier |
62 | * |
63 | * @return ScopeEntityInterface[] |
64 | */ |
65 | public function finalizeScopes( array $scopes, $grantType, |
66 | ClientEntityInterface $clientEntity, $userIdentifier = null ) { |
67 | $scopes = $this->replaceDefaultScope( $scopes, $clientEntity ); |
68 | |
69 | if ( $grantType !== 'authorization_code' ) { |
70 | // For grants that do not require approval, |
71 | // just filter out the scopes that are not allowed for the client |
72 | return array_filter( |
73 | $scopes, |
74 | static function ( ScopeEntityInterface $scope ) use ( $clientEntity ) { |
75 | return in_array( $scope->getIdentifier(), $clientEntity->getGrants(), true ); |
76 | } |
77 | ); |
78 | } |
79 | if ( !is_numeric( $userIdentifier ) ) { |
80 | return []; |
81 | } |
82 | |
83 | $mwUser = Utils::getLocalUserFromCentralId( (int)$userIdentifier ); |
84 | if ( !$mwUser ) { |
85 | return []; |
86 | } |
87 | $userEntity = UserEntity::newFromMWUser( $mwUser ); |
88 | if ( $userEntity === null ) { |
89 | return []; |
90 | } |
91 | |
92 | // Filter out not approved scopes |
93 | try { |
94 | $approval = $clientEntity->getCurrentAuthorization( $mwUser, WikiMap::getCurrentWikiId() ); |
95 | $approvedScopeIds = $approval->getGrants(); |
96 | } catch ( MWOAuthException $ex ) { |
97 | $approvedScopeIds = []; |
98 | } |
99 | |
100 | return array_filter( |
101 | $scopes, |
102 | static function ( ScopeEntityInterface $scope ) use ( $approvedScopeIds ) { |
103 | return in_array( $scope->getIdentifier(), $approvedScopeIds, true ); |
104 | } |
105 | ); |
106 | } |
107 | |
108 | /** |
109 | * Detect "#default" scope and replace it with all client's allowed scopes |
110 | * |
111 | * @param ScopeEntityInterface[] $scopes |
112 | * @param ClientEntityInterface|ClientEntity $client |
113 | * @return ScopeEntityInterface[] |
114 | */ |
115 | private function replaceDefaultScope( array $scopes, ClientEntityInterface $client ) { |
116 | // Normally, #default scope would be an only scope set, but go through whole array in case |
117 | // someone explicitly made a request with that scope set |
118 | $index = array_search( '#default', array_map( static function ( ScopeEntityInterface $scope ) { |
119 | return $scope->getIdentifier(); |
120 | }, $scopes ) ); |
121 | |
122 | if ( $index === false ) { |
123 | return $scopes; |
124 | } |
125 | |
126 | return $client->getScopes(); |
127 | } |
128 | } |