1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* The MIT License (MIT) |
7
|
|
|
* |
8
|
|
|
* Copyright (c) 2014-2018 Spomky-Labs |
9
|
|
|
* |
10
|
|
|
* This software may be modified and distributed under the terms |
11
|
|
|
* of the MIT license. See the LICENSE file for details. |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace OAuth2Framework\Component\OpenIdConnect\UserInfo; |
15
|
|
|
|
16
|
|
|
use OAuth2Framework\Component\OpenIdConnect\UserInfo\Claim\ClaimManager; |
17
|
|
|
use OAuth2Framework\Component\OpenIdConnect\UserInfo\Claim\ClaimSourceManager; |
18
|
|
|
use OAuth2Framework\Component\OpenIdConnect\UserInfo\Pairwise\PairwiseSubjectIdentifierAlgorithm; |
19
|
|
|
use OAuth2Framework\Component\OpenIdConnect\UserInfo\ScopeSupport\UserInfoScopeSupportManager; |
20
|
|
|
use OAuth2Framework\Component\Core\Client\Client; |
21
|
|
|
use OAuth2Framework\Component\Core\UserAccount\UserAccount; |
22
|
|
|
|
23
|
|
|
class UserInfo |
24
|
|
|
{ |
25
|
|
|
/** |
26
|
|
|
* @var null|PairwiseSubjectIdentifierAlgorithm |
27
|
|
|
*/ |
28
|
|
|
private $pairwiseAlgorithm = null; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var UserInfoScopeSupportManager |
32
|
|
|
*/ |
33
|
|
|
private $userinfoScopeSupportManager; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var ClaimSourceManager |
37
|
|
|
*/ |
38
|
|
|
private $claimSourceManager; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var ClaimManager |
42
|
|
|
*/ |
43
|
|
|
private $claimManager; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* UserInfo constructor. |
47
|
|
|
* |
48
|
|
|
* @param UserInfoScopeSupportManager $userinfoScopeSupportManager |
49
|
|
|
* @param ClaimManager $claimManager |
50
|
|
|
* @param ClaimSourceManager $claimSourceManager |
51
|
|
|
*/ |
52
|
|
|
public function __construct(UserInfoScopeSupportManager $userinfoScopeSupportManager, ClaimManager $claimManager, ClaimSourceManager $claimSourceManager) |
53
|
|
|
{ |
54
|
|
|
$this->userinfoScopeSupportManager = $userinfoScopeSupportManager; |
55
|
|
|
$this->claimManager = $claimManager; |
56
|
|
|
$this->claimSourceManager = $claimSourceManager; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @param Client $client |
61
|
|
|
* @param UserAccount $userAccount |
62
|
|
|
* @param string $redirectUri |
63
|
|
|
* @param array $requestedClaims |
64
|
|
|
* @param string $scope |
65
|
|
|
* @param string|null $claimsLocales |
66
|
|
|
* |
67
|
|
|
* @return array |
68
|
|
|
*/ |
69
|
|
|
public function getUserinfo(Client $client, UserAccount $userAccount, string $redirectUri, array $requestedClaims, string $scope, ? string $claimsLocales): array |
70
|
|
|
{ |
71
|
|
|
$requestedClaims = array_merge( |
72
|
|
|
$this->getClaimsFromClaimScope($scope), |
73
|
|
|
$requestedClaims |
74
|
|
|
); |
75
|
|
|
$claims = $this->getClaimValues($userAccount, $requestedClaims, $claimsLocales); |
76
|
|
|
/*$claims = array_merge( |
|
|
|
|
77
|
|
|
$claims, |
78
|
|
|
$this->claimSourceManager->getUserInfo($userAccount, $scope, []) |
79
|
|
|
);*/ |
80
|
|
|
$claims['sub'] = $this->calculateSubjectIdentifier($client, $userAccount, $redirectUri); |
81
|
|
|
|
82
|
|
|
return $claims; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @param string $scope |
87
|
|
|
* |
88
|
|
|
* @return array |
89
|
|
|
*/ |
90
|
|
|
private function getClaimsFromClaimScope(string $scope): array |
91
|
|
|
{ |
92
|
|
|
$result = []; |
93
|
|
|
|
94
|
|
|
foreach (explode(' ', $scope) as $scp) { |
95
|
|
|
if ($this->userinfoScopeSupportManager->has($scp)) { |
96
|
|
|
$scope_claims = $this->userinfoScopeSupportManager->get($scp)->getAssociatedClaims(); |
97
|
|
|
foreach ($scope_claims as $scope_claim) { |
98
|
|
|
$result[$scope_claim] = null; |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
return $result; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @param UserAccount $userAccount |
108
|
|
|
* @param string|null $claimsLocales |
109
|
|
|
* @param array $requestedClaims |
110
|
|
|
* |
111
|
|
|
* @return array |
112
|
|
|
*/ |
113
|
|
|
private function getClaimValues(UserAccount $userAccount, array $requestedClaims, ?string $claimsLocales): array |
114
|
|
|
{ |
115
|
|
|
$result = []; |
|
|
|
|
116
|
|
|
if (null === $claimsLocales) { |
117
|
|
|
$claimsLocales = []; |
118
|
|
|
} elseif (true === is_string($claimsLocales)) { |
119
|
|
|
$claimsLocales = array_unique(explode(' ', $claimsLocales)); |
120
|
|
|
} |
121
|
|
|
$result = $this->claimManager->getUserInfo($userAccount, $requestedClaims, $claimsLocales); |
122
|
|
|
/*foreach ($requestedClaims as $claim => $config) { |
|
|
|
|
123
|
|
|
foreach ($claimsLocales as $claims_locale) { |
124
|
|
|
$claim_locale = $this->computeClaimWithLocale($claim, $claims_locale); |
125
|
|
|
$claim_value = $this->getUserClaim($userAccount, $claim_locale, $config); |
126
|
|
|
if (null !== $claim_value) { |
127
|
|
|
$result[$claim_locale] = $claim_value; |
128
|
|
|
|
129
|
|
|
break; |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
}*/ |
133
|
|
|
|
134
|
|
|
return $result; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* @param UserAccount $userAccount |
139
|
|
|
* @param string $claimName |
140
|
|
|
* @param null|array $config |
141
|
|
|
* |
142
|
|
|
* @return null|mixed |
143
|
|
|
*/ |
144
|
|
|
private function getUserClaim(UserAccount $userAccount, string $claimName, ?array $config) |
|
|
|
|
145
|
|
|
{ |
146
|
|
|
// FIXME: "acr" claim support has to be added. |
147
|
|
|
if ($userAccount->has($claimName)) { |
148
|
|
|
$claim = $userAccount->get($claimName); |
149
|
|
|
switch (true) { |
150
|
|
|
case is_array($config) && array_key_exists('value', $config): |
|
|
|
|
151
|
|
|
if ($claim === $config['value']) { |
152
|
|
|
return $claim; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
break; |
156
|
|
|
case is_array($config) && array_key_exists('values', $config) && is_array($config['values']): |
157
|
|
|
if (in_array($claim, $config['values'])) { |
158
|
|
|
return $claim; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
break; |
162
|
|
|
default: |
163
|
|
|
return $claim; |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
return null; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param PairwiseSubjectIdentifierAlgorithm $pairwiseAlgorithm |
172
|
|
|
*/ |
173
|
|
|
public function enablePairwiseSubject(PairwiseSubjectIdentifierAlgorithm $pairwiseAlgorithm) |
174
|
|
|
{ |
175
|
|
|
$this->pairwiseAlgorithm = $pairwiseAlgorithm; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* @return bool |
180
|
|
|
*/ |
181
|
|
|
public function isPairwiseSubjectIdentifierSupported(): bool |
182
|
|
|
{ |
183
|
|
|
return null !== $this->pairwiseAlgorithm; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @return PairwiseSubjectIdentifierAlgorithm|null |
188
|
|
|
*/ |
189
|
|
|
public function getPairwiseSubjectIdentifierAlgorithm(): ? PairwiseSubjectIdentifierAlgorithm |
190
|
|
|
{ |
191
|
|
|
return $this->pairwiseAlgorithm; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* @param Client $client |
196
|
|
|
* @param UserAccount $userAccount |
197
|
|
|
* @param string $redirectUri |
198
|
|
|
* |
199
|
|
|
* @return string |
200
|
|
|
*/ |
201
|
|
|
private function calculateSubjectIdentifier(Client $client, UserAccount $userAccount, string $redirectUri): string |
202
|
|
|
{ |
203
|
|
|
$sub = $userAccount->getUserAccountId()->getValue(); |
204
|
|
|
if (false === $this->isPairwiseSubjectIdentifierSupported()) { |
205
|
|
|
return $sub; |
206
|
|
|
} |
207
|
|
|
if (($client->has('subject_type') && ('pairwise' === $client->get('subject_type')))) { |
208
|
|
|
$sectorIdentifierHost = $this->getSectorIdentifierHost($client, $redirectUri); |
209
|
|
|
|
210
|
|
|
return $this->pairwiseAlgorithm->calculateSubjectIdentifier( |
211
|
|
|
$userAccount, |
212
|
|
|
$sectorIdentifierHost |
213
|
|
|
); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
return $sub; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* @param Client $client |
221
|
|
|
* @param string $redirectUri |
222
|
|
|
* |
223
|
|
|
* @return string |
224
|
|
|
*/ |
225
|
|
|
private function getSectorIdentifierHost(Client $client, string $redirectUri): string |
226
|
|
|
{ |
227
|
|
|
$uri = $redirectUri; |
228
|
|
|
|
229
|
|
|
if (true === $client->has('sector_identifier_uri')) { |
230
|
|
|
$uri = $client->get('sector_identifier_uri'); |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
$data = parse_url($uri); |
234
|
|
|
if (!is_array($data) || !array_key_exists('host', $data)) { |
235
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid Sector Identifier Uri "%s".', $uri)); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
return $data['host']; |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.