Failed Conditions
Push — master ( a2c488...cc649a )
by Florent
04:14 queued 10s
created

UserInfo::getPairwiseSubjectIdentifierAlgorithm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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\ClaimSource\ClaimSourceManager;
17
use OAuth2Framework\Component\OpenIdConnect\UserInfo\Pairwise\PairwiseSubjectIdentifierAlgorithm;
18
use OAuth2Framework\Component\OpenIdConnect\UserInfo\ScopeSupport\UserInfoScopeSupportManager;
19
use OAuth2Framework\Component\Core\Client\Client;
20
use OAuth2Framework\Component\Core\UserAccount\UserAccount;
21
22
class UserInfo
23
{
24
    /**
25
     * @var null|PairwiseSubjectIdentifierAlgorithm
26
     */
27
    private $pairwiseAlgorithm = null;
28
29
    /**
30
     * @var UserInfoScopeSupportManager
31
     */
32
    private $userinfoScopeSupportManager;
33
34
    /**
35
     * @var ClaimSourceManager
36
     */
37
    private $claimSourceManager;
38
39
    /**
40
     * UserInfo constructor.
41
     *
42
     * @param UserInfoScopeSupportManager $userinfoScopeSupportManager
43
     * @param ClaimSourceManager          $claimSourceManager
44
     */
45
    public function __construct(UserInfoScopeSupportManager $userinfoScopeSupportManager, ClaimSourceManager $claimSourceManager)
46
    {
47
        $this->userinfoScopeSupportManager = $userinfoScopeSupportManager;
48
        $this->claimSourceManager = $claimSourceManager;
49
    }
50
51
    /**
52
     * @return string[]
53
     */
54
    public function getSupportedClaims(): array
55
    {
56
        $claimsSupported = [];
57
        foreach ($this->userinfoScopeSupportManager->all() as $infoScopeSupport) {
58
            $claimsSupported += $infoScopeSupport->getClaims();
59
        }
60
61
        return array_unique($claimsSupported);
62
    }
63
64
    /**
65
     * @param Client      $client
66
     * @param UserAccount $userAccount
67
     * @param string      $redirectUri
68
     * @param array       $requestClaims
69
     * @param string      $scope
70
     * @param string|null $claimsLocales
71
     *
72
     * @return array
73
     */
74
    public function getUserinfo(Client $client, UserAccount $userAccount, string $redirectUri, array $requestClaims, string $scope, ? string $claimsLocales): array
75
    {
76
        $requestClaims = array_merge(
77
            $this->getClaimsFromClaimScope($scope),
78
            $requestClaims
79
        );
80
        $claims = $this->getClaimValues($userAccount, $requestClaims, $claimsLocales);
81
        $claims = array_merge(
82
            $claims,
83
            $this->claimSourceManager->getUserInfo($userAccount, $scope, [])
84
        );
85
        $claims['sub'] = $this->calculateSubjectIdentifier($client, $userAccount, $redirectUri);
86
87
        return $claims;
88
    }
89
90
    /**
91
     * @param string $scope
92
     *
93
     * @return array
94
     */
95
    private function getClaimsFromClaimScope(string $scope): array
96
    {
97
        $result = [];
98
99
        foreach (explode(' ', $scope) as $scp) {
100
            if ($this->userinfoScopeSupportManager->has($scp)) {
101
                $scope_claims = $this->userinfoScopeSupportManager->get($scp)->getClaims();
102
                foreach ($scope_claims as $scope_claim) {
103
                    $result[$scope_claim] = null;
104
                }
105
            }
106
        }
107
108
        return $result;
109
    }
110
111
    /**
112
     * @param UserAccount $userAccount
113
     * @param string|null $claimsLocales
114
     * @param array       $claims
115
     *
116
     * @return array
117
     */
118
    private function getClaimValues(UserAccount $userAccount, array $claims, ? string $claimsLocales): array
119
    {
120
        $result = [];
121
        if (null === $claimsLocales) {
122
            $claimsLocales = [];
123
        } elseif (true === is_string($claimsLocales)) {
124
            $claimsLocales = explode(' ', $claimsLocales);
125
        }
126
        $claimsLocales[] = '';
127
        foreach ($claims as $claim => $config) {
128
            foreach ($claimsLocales as $claims_locale) {
129
                $claim_locale = $this->computeClaimWithLocale($claim, $claims_locale);
130
                $claim_value = $this->getUserClaim($userAccount, $claim_locale, $config);
131
                if (null !== $claim_value) {
132
                    $result[$claim_locale] = $claim_value;
133
134
                    break;
135
                }
136
            }
137
        }
138
139
        return $result;
140
    }
141
142
    /**
143
     * @param string $claim
144
     * @param string $locale
145
     *
146
     * @return string
147
     */
148
    private function computeClaimWithLocale($claim, $locale): string
149
    {
150
        if (empty($locale)) {
151
            return $claim;
152
        }
153
154
        return sprintf('%s#%s', $claim, $locale);
155
    }
156
157
    /**
158
     * @param UserAccount $userAccount
159
     * @param string      $claimName
160
     * @param null|array  $config
161
     *
162
     * @return null|mixed
163
     */
164
    private function getUserClaim(UserAccount $userAccount, string $claimName, ?array $config)
165
    {
166
        // FIXME: "acr" claim support has to be added.
167
        if ($userAccount->has($claimName)) {
168
            $claim = $userAccount->get($claimName);
169
            switch (true) {
170
                case is_array($config) && array_key_exists('value', $config):
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
171
                    dump($config);
172
                    dump($claimName);
173
                    dump($claim);
174
                    dump($claim === $config['value']);
175
                    if ($claim === $config['value']) {
176
                        return $claim;
177
                    }
178
179
                    break;
180
                case is_array($config) && array_key_exists('values', $config) && is_array($config['values']):
181
                    if (in_array($claim, $config['values'])) {
182
                        return $claim;
183
                    }
184
185
                    break;
186
                default:
187
                    return $claim;
188
            }
189
        }
190
191
        return null;
192
    }
193
194
    /**
195
     * @param PairwiseSubjectIdentifierAlgorithm $pairwiseAlgorithm
196
     */
197
    public function enablePairwiseSubject(PairwiseSubjectIdentifierAlgorithm $pairwiseAlgorithm)
198
    {
199
        $this->pairwiseAlgorithm = $pairwiseAlgorithm;
200
    }
201
202
    /**
203
     * @return bool
204
     */
205
    public function isPairwiseSubjectIdentifierSupported(): bool
206
    {
207
        return null !== $this->pairwiseAlgorithm;
208
    }
209
210
    /**
211
     * @return PairwiseSubjectIdentifierAlgorithm|null
212
     */
213
    public function getPairwiseSubjectIdentifierAlgorithm(): ? PairwiseSubjectIdentifierAlgorithm
214
    {
215
        return $this->pairwiseAlgorithm;
216
    }
217
218
    /**
219
     * @param Client      $client
220
     * @param UserAccount $userAccount
221
     * @param string      $redirectUri
222
     *
223
     * @return string
224
     */
225
    private function calculateSubjectIdentifier(Client $client, UserAccount $userAccount, string $redirectUri): string
226
    {
227
        $sub = $userAccount->getUserAccountId()->getValue();
228
        if (false === $this->isPairwiseSubjectIdentifierSupported()) {
229
            return $sub;
230
        }
231
        if (($client->has('subject_type') && ('pairwise' === $client->get('subject_type')))) {
232
            $sectorIdentifierHost = $this->getSectorIdentifierHost($client, $redirectUri);
233
234
            return $this->pairwiseAlgorithm->calculateSubjectIdentifier(
235
                $userAccount,
236
                $sectorIdentifierHost
237
            );
238
        }
239
240
        return $sub;
241
    }
242
243
    /**
244
     * @param Client $client
245
     * @param string $redirectUri
246
     *
247
     * @return string
248
     */
249
    private function getSectorIdentifierHost(Client $client, string $redirectUri): string
250
    {
251
        $uri = $redirectUri;
252
253
        if (true === $client->has('sector_identifier_uri')) {
254
            $uri = $client->get('sector_identifier_uri');
255
        }
256
257
        $data = parse_url($uri);
258
        if (!is_array($data) || !array_key_exists('host', $data)) {
259
            throw new \InvalidArgumentException(sprintf('Invalid Sector Identifier Uri "%s".', $uri));
260
        }
261
262
        return $data['host'];
263
    }
264
}
265