Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
72.34% |
34 / 47 |
|
50.00% |
2 / 4 |
CRAP | |
0.00% |
0 / 1 |
UserStatementProvider | |
72.34% |
34 / 47 |
|
50.00% |
2 / 4 |
10.71 | |
0.00% |
0 / 1 |
factory | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
__construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
getUserStatement | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getUserProfile | |
95.45% |
21 / 22 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\OAuth; |
4 | |
5 | use MediaWiki\Config\Config; |
6 | use MediaWiki\Extension\OAuth\Backend\Consumer; |
7 | use MediaWiki\Extension\OAuth\Backend\Utils; |
8 | use MediaWiki\MediaWikiServices; |
9 | use MediaWiki\Permissions\GrantsInfo; |
10 | use MediaWiki\User\User; |
11 | use MediaWiki\User\UserGroupManager; |
12 | |
13 | class UserStatementProvider { |
14 | /** @var Config */ |
15 | protected $config; |
16 | /** @var User */ |
17 | protected $user; |
18 | /** @var Consumer */ |
19 | protected $consumer; |
20 | /** @var string[] */ |
21 | protected $grants; |
22 | /** @var UserGroupManager */ |
23 | private $userGroupManager; |
24 | /** @var GrantsInfo */ |
25 | private $grantsInfo; |
26 | |
27 | /** |
28 | * @param User $user |
29 | * @param Consumer $consumer |
30 | * @param array $grants |
31 | * @return static |
32 | */ |
33 | public static function factory( User $user, Consumer $consumer, $grants = [] ) { |
34 | $services = MediaWikiServices::getInstance(); |
35 | $mainConfig = $services->getMainConfig(); |
36 | $userGroupManager = $services->getUserGroupManager(); |
37 | $grantsInfo = $services->getGrantsInfo(); |
38 | return new static( |
39 | $mainConfig, |
40 | $user, |
41 | $consumer, |
42 | $grants, |
43 | $userGroupManager, |
44 | $grantsInfo |
45 | ); |
46 | } |
47 | |
48 | /** |
49 | * UserStatementProvider constructor. |
50 | * @param Config $config |
51 | * @param User $user |
52 | * @param Consumer $consumer |
53 | * @param array $grants |
54 | * @param UserGroupManager $userGroupManager |
55 | * @param GrantsInfo $grantsInfo |
56 | */ |
57 | protected function __construct( |
58 | $config, |
59 | $user, |
60 | $consumer, |
61 | $grants, |
62 | $userGroupManager, |
63 | $grantsInfo |
64 | ) { |
65 | $this->config = $config; |
66 | $this->user = $user; |
67 | $this->consumer = $consumer; |
68 | $this->grants = $grants; |
69 | $this->userGroupManager = $userGroupManager; |
70 | $this->grantsInfo = $grantsInfo; |
71 | } |
72 | |
73 | /** |
74 | * Retrieve user statement suitable for JWT encoding |
75 | * |
76 | * @return array |
77 | */ |
78 | public function getUserStatement() { |
79 | $statement = []; |
80 | |
81 | // Include some of the OpenID Connect attributes |
82 | // http://openid.net/specs/openid-connect-core-1_0.html (draft 14) |
83 | // Issuer Identifier for the Issuer of the response. |
84 | $statement['iss'] = $this->config->get( 'CanonicalServer' ); |
85 | // Subject identifier. A locally unique and never reassigned identifier. |
86 | // T264560: sub added via $this->getUserProfile() |
87 | // Audience(s) that this ID Token is intended for. |
88 | $statement['aud'] = $this->consumer->getConsumerKey(); |
89 | // Expiration time on or after which the ID Token MUST NOT be accepted for processing. |
90 | $statement['exp'] = (int)wfTimestamp() + 100; |
91 | // Time at which the JWT was issued. |
92 | $statement['iat'] = (int)wfTimestamp(); |
93 | // TODO: Add auth_time, if we start tracking last login timestamp |
94 | |
95 | $statement += $this->getUserProfile(); |
96 | |
97 | return $statement; |
98 | } |
99 | |
100 | /** |
101 | * Retrieve user profile information |
102 | * |
103 | * @return array |
104 | */ |
105 | public function getUserProfile() { |
106 | $profile = [ |
107 | 'sub' => Utils::getCentralIdFromLocalUser( $this->user ), |
108 | ]; |
109 | // Include some MediaWiki info about the user |
110 | if ( !$this->user->isHidden() ) { |
111 | $profile['username'] = $this->user->getName(); |
112 | $profile['editcount'] = intval( $this->user->getEditCount() ); |
113 | // Use confirmed_email for B/C and email_verified because it's in the OIDC spec |
114 | $profile['confirmed_email'] = $profile['email_verified'] = $this->user->isEmailConfirmed(); |
115 | $profile['blocked'] = $this->user->getBlock() !== null; |
116 | $profile['registered'] = $this->user->getRegistration(); |
117 | $profile['groups'] = $this->userGroupManager->getUserEffectiveGroups( $this->user ); |
118 | $profile['rights'] = array_values( array_unique( |
119 | MediaWikiServices::getInstance()->getPermissionManager()->getUserPermissions( $this->user ) |
120 | ) ); |
121 | $profile['grants'] = $this->grants; |
122 | |
123 | if ( in_array( 'mwoauth-authonlyprivate', $this->grants ) || |
124 | in_array( 'viewmyprivateinfo', $this->grantsInfo->getGrantRights( $profile['grants'] ) ) |
125 | ) { |
126 | // Paranoia - avoid showing the real name if the wiki is not configured to use |
127 | // it but it somehow exists (from past configuration, or some identity management |
128 | // extension). This is important as the viewmyprivateinfo grant is presented |
129 | // to the user differently when useRealNames() is false. |
130 | // Don't omit the field completely to avoid a breaking change. |
131 | $profile['realname'] = !in_array( |
132 | 'realname', $this->config->get( 'HiddenPrefs' ), true |
133 | ) ? $this->user->getRealName() : ''; |
134 | $profile['email'] = $this->user->isEmailConfirmed() ? $this->user->getEmail() : ''; |
135 | } |
136 | } else { |
137 | $profile['blocked'] = true; |
138 | } |
139 | |
140 | return $profile; |
141 | } |
142 | } |