Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 97 |
|
0.00% |
0 / 19 |
CRAP | |
0.00% |
0 / 1 |
ConsumerAcceptance | |
0.00% |
0 / 97 |
|
0.00% |
0 / 19 |
992 | |
0.00% |
0 / 1 |
getSchema | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
getFieldPermissionChecks | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
newFromToken | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
newFromUserConsumerWiki | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
getId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getWiki | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getUserId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getConsumerId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAccessToken | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAccessSecret | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getGrants | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAccepted | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getOAuthVersion | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
normalizeValues | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
encodeRow | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
decodeRow | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
userCanSee | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
userCanSeePrivate | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
userCanSeeSecret | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\OAuth\Backend; |
4 | |
5 | use MediaWiki\Context\IContextSource; |
6 | use MediaWiki\Json\FormatJson; |
7 | use MediaWiki\MediaWikiServices; |
8 | use Wikimedia\Rdbms\IDatabase; |
9 | use Wikimedia\Rdbms\IDBAccessObject; |
10 | |
11 | /** |
12 | * (c) Aaron Schulz 2013, GPL |
13 | * |
14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * This program is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License along |
25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
27 | * http://www.gnu.org/copyleft/gpl.html |
28 | */ |
29 | |
30 | /** |
31 | * Representation of an OAuth consumer acceptance. |
32 | * Created when the user clicks through the OAuth authorization dialog, this allows |
33 | * the specified consumer to perform actions in the name of the user |
34 | * (subject to the grant and wiki restrictions stored in the acceptance object). |
35 | */ |
36 | class ConsumerAcceptance extends MWOAuthDAO { |
37 | /** @var int Unique ID */ |
38 | protected $id; |
39 | |
40 | /** @var string Wiki ID the application can be used on (or "*" for all) */ |
41 | protected $wiki; |
42 | |
43 | /** @var int Publisher user ID (on central wiki) */ |
44 | protected $userId; |
45 | |
46 | /** @var int */ |
47 | protected $consumerId; |
48 | |
49 | /** @var string Hex token */ |
50 | protected $accessToken; |
51 | |
52 | /** @var string Secret HMAC key */ |
53 | protected $accessSecret; |
54 | |
55 | /** @var string[] List of grants */ |
56 | protected $grants; |
57 | |
58 | /** @var string TS_MW timestamp of acceptance */ |
59 | protected $accepted; |
60 | |
61 | /** @var string */ |
62 | protected $oauth_version; |
63 | |
64 | protected static function getSchema() { |
65 | return [ |
66 | 'table' => 'oauth_accepted_consumer', |
67 | 'fieldColumnMap' => [ |
68 | 'id' => 'oaac_id', |
69 | 'wiki' => 'oaac_wiki', |
70 | 'userId' => 'oaac_user_id', |
71 | 'consumerId' => 'oaac_consumer_id', |
72 | 'accessToken' => 'oaac_access_token', |
73 | 'accessSecret' => 'oaac_access_secret', |
74 | 'grants' => 'oaac_grants', |
75 | 'accepted' => 'oaac_accepted', |
76 | 'oauth_version' => 'oaac_oauth_version', |
77 | ], |
78 | 'idField' => 'id', |
79 | 'autoIncrField' => 'id', |
80 | ]; |
81 | } |
82 | |
83 | protected static function getFieldPermissionChecks() { |
84 | return [ |
85 | 'wiki' => 'userCanSee', |
86 | 'userId' => 'userCanSee', |
87 | 'consumerId' => 'userCanSee', |
88 | 'accessToken' => 'userCanSeePrivate', |
89 | 'accessSecret' => 'userCanSeeSecret', |
90 | 'grants' => 'userCanSee', |
91 | 'accepted' => 'userCanSee', |
92 | 'oauth_version' => 'userCanSee', |
93 | ]; |
94 | } |
95 | |
96 | /** |
97 | * @param IDatabase $db |
98 | * @param string $token Access token |
99 | * @param int $flags ConsumerAcceptance::READ_* bitfield |
100 | * @return ConsumerAcceptance|bool |
101 | */ |
102 | public static function newFromToken( IDatabase $db, $token, $flags = 0 ) { |
103 | $queryBuilder = $db->newSelectQueryBuilder() |
104 | ->select( array_values( static::getFieldColumnMap() ) ) |
105 | ->from( static::getTable() ) |
106 | ->where( [ 'oaac_access_token' => (string)$token ] ) |
107 | ->caller( __METHOD__ ); |
108 | if ( $flags & IDBAccessObject::READ_LOCKING ) { |
109 | $queryBuilder->forUpdate(); |
110 | } |
111 | $row = $queryBuilder->fetchRow(); |
112 | |
113 | if ( $row ) { |
114 | $consumer = new self(); |
115 | $consumer->loadFromRow( $db, $row ); |
116 | return $consumer; |
117 | } else { |
118 | return false; |
119 | } |
120 | } |
121 | |
122 | /** |
123 | * @param IDatabase $db |
124 | * @param int $userId of user who authorized (central wiki's id) |
125 | * @param Consumer $consumer |
126 | * @param string $wiki wiki associated with the acceptance |
127 | * @param int $flags ConsumerAcceptance::READ_* bitfield |
128 | * @param int $oauthVersion |
129 | * @return ConsumerAcceptance|bool |
130 | */ |
131 | public static function newFromUserConsumerWiki( |
132 | IDatabase $db, $userId, $consumer, |
133 | $wiki, $flags = 0, $oauthVersion = Consumer::OAUTH_VERSION_1 |
134 | ) { |
135 | $queryBuilder = $db->newSelectQueryBuilder() |
136 | ->select( array_values( static::getFieldColumnMap() ) ) |
137 | ->from( static::getTable() ) |
138 | ->where( [ |
139 | 'oaac_user_id' => $userId, |
140 | 'oaac_consumer_id' => $consumer->getId(), |
141 | 'oaac_oauth_version' => $oauthVersion, |
142 | 'oaac_wiki' => (string)$wiki |
143 | ] ) |
144 | ->caller( __METHOD__ ); |
145 | if ( $flags & IDBAccessObject::READ_LOCKING ) { |
146 | $queryBuilder->forUpdate(); |
147 | } |
148 | $row = $queryBuilder->fetchRow(); |
149 | |
150 | if ( $row ) { |
151 | $consumer = new self(); |
152 | $consumer->loadFromRow( $db, $row ); |
153 | return $consumer; |
154 | } else { |
155 | return false; |
156 | } |
157 | } |
158 | |
159 | /** |
160 | * Database ID. |
161 | * @return int |
162 | */ |
163 | public function getId() { |
164 | return $this->get( 'id' ); |
165 | } |
166 | |
167 | /** |
168 | * Wiki on which the user has authorized the consumer to access their account. Wiki ID or '*' |
169 | * for all. |
170 | * @return string |
171 | */ |
172 | public function getWiki() { |
173 | return $this->get( 'wiki' ); |
174 | } |
175 | |
176 | /** |
177 | * Central user ID of the authorizing user. |
178 | * @return int |
179 | */ |
180 | public function getUserId() { |
181 | return $this->get( 'userId' ); |
182 | } |
183 | |
184 | /** |
185 | * Database ID of the consumer. |
186 | * @return int |
187 | */ |
188 | public function getConsumerId() { |
189 | return $this->get( 'consumerId' ); |
190 | } |
191 | |
192 | /** |
193 | * The access token for the OAuth protocol |
194 | * @return string |
195 | */ |
196 | public function getAccessToken() { |
197 | return $this->get( 'accessToken' ); |
198 | } |
199 | |
200 | /** |
201 | * Secret key used to derive the access secret for the OAuth protocol. |
202 | * The actual access secret will be calculated via Utils::hmacDBSecret() to mitigate |
203 | * DB leaks. |
204 | * @return string |
205 | */ |
206 | public function getAccessSecret() { |
207 | return $this->get( 'accessSecret' ); |
208 | } |
209 | |
210 | /** |
211 | * The list of grants which have been granted. |
212 | * @return string[] |
213 | */ |
214 | public function getGrants() { |
215 | return $this->get( 'grants' ); |
216 | } |
217 | |
218 | /** |
219 | * Date of the authorization, in TS_MW format. |
220 | * @return string |
221 | */ |
222 | public function getAccepted() { |
223 | return $this->get( 'accepted' ); |
224 | } |
225 | |
226 | /** |
227 | * @return int |
228 | */ |
229 | public function getOAuthVersion() { |
230 | return (int)$this->get( 'oauth_version' ); |
231 | } |
232 | |
233 | protected function normalizeValues() { |
234 | $this->userId = (int)$this->userId; |
235 | $this->consumerId = (int)$this->consumerId; |
236 | $this->accepted = wfTimestamp( TS_MW, $this->accepted ); |
237 | $this->grants = (array)$this->grants; |
238 | } |
239 | |
240 | protected function encodeRow( IDatabase $db, $row ) { |
241 | if ( (int)$row['oaac_user_id'] === 0 ) { |
242 | throw new MWOAuthException( 'mwoauth-consumer-access-no-user', [ |
243 | 'consumer_id' => $row['oaac_consumer_id'], |
244 | ] ); |
245 | } |
246 | // For compatibility with other wikis in the farm, un-remap some grants |
247 | foreach ( Consumer::$mapBackCompatGrants as $old => $new ) { |
248 | // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition |
249 | while ( ( $i = array_search( $new, $row['oaac_grants'], true ) ) !== false ) { |
250 | $row['oaac_grants'][$i] = $old; |
251 | } |
252 | } |
253 | |
254 | $row['oaac_grants'] = FormatJson::encode( $row['oaac_grants'] ); |
255 | $row['oaac_accepted'] = $db->timestamp( $row['oaac_accepted'] ); |
256 | return $row; |
257 | } |
258 | |
259 | protected function decodeRow( IDatabase $db, $row ) { |
260 | $row['oaac_grants'] = FormatJson::decode( $row['oaac_grants'], true ); |
261 | $row['oaac_accepted'] = wfTimestamp( TS_MW, $row['oaac_accepted'] ); |
262 | |
263 | // For backwards compatibility, remap some grants |
264 | foreach ( Consumer::$mapBackCompatGrants as $old => $new ) { |
265 | // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition |
266 | while ( ( $i = array_search( $old, $row['oaac_grants'], true ) ) !== false ) { |
267 | $row['oaac_grants'][$i] = $new; |
268 | } |
269 | } |
270 | |
271 | return $row; |
272 | } |
273 | |
274 | protected function userCanSee( $name, IContextSource $context ) { |
275 | $centralUserId = Utils::getCentralIdFromLocalUser( $context->getUser() ); |
276 | $permissionManager = MediaWikiServices::getInstance()->getPermissionManager(); |
277 | |
278 | if ( $this->userId != $centralUserId |
279 | && !$permissionManager->userHasRight( $context->getUser(), 'mwoauthviewprivate' ) |
280 | ) { |
281 | return $context->msg( 'mwoauth-field-private' ); |
282 | } else { |
283 | return true; |
284 | } |
285 | } |
286 | |
287 | protected function userCanSeePrivate( $name, IContextSource $context ) { |
288 | $permissionManager = MediaWikiServices::getInstance()->getPermissionManager(); |
289 | |
290 | if ( !$permissionManager->userHasRight( $context->getUser(), 'mwoauthviewprivate' ) ) { |
291 | return $context->msg( 'mwoauth-field-private' ); |
292 | } else { |
293 | return $this->userCanSee( $name, $context ); |
294 | } |
295 | } |
296 | |
297 | protected function userCanSeeSecret( $name, IContextSource $context ) { |
298 | return $context->msg( 'mwoauth-field-private' ); |
299 | } |
300 | } |