Failed Conditions
Push — master ( acffac...83c99e )
by Florent
12:15 queued 06:21
created

UserInfo::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
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      $claim
160
     * @param null|array  $config
161
     *
162
     * @return null|mixed
163
     */
164
    private function getUserClaim(UserAccount $userAccount, $claim, $config)
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
    {
166
        //The parameter $config is not yet used and the claim is returned as-is whatever the client requested
167
        //FIXME
168
        if ($userAccount->has($claim)) {
169
            return $userAccount->get($claim);
170
        }
171
    }
172
173
    /**
174
     * @param PairwiseSubjectIdentifierAlgorithm $pairwiseAlgorithm
175
     * @param bool                               $isPairwiseSubjectDefault
176
     */
177
    public function enablePairwiseSubject(PairwiseSubjectIdentifierAlgorithm $pairwiseAlgorithm, bool $isPairwiseSubjectDefault)
0 ignored issues
show
Unused Code introduced by
The parameter $isPairwiseSubjectDefault is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
178
    {
179
        $this->pairwiseAlgorithm = $pairwiseAlgorithm;
180
    }
181
182
    /**
183
     * @return bool
184
     */
185
    public function isPairwiseSubjectIdentifierSupported(): bool
186
    {
187
        return null !== $this->pairwiseAlgorithm;
188
    }
189
190
    /**
191
     * @return PairwiseSubjectIdentifierAlgorithm|null
192
     */
193
    public function getPairwiseSubjectIdentifierAlgorithm(): ? PairwiseSubjectIdentifierAlgorithm
194
    {
195
        return $this->pairwiseAlgorithm;
196
    }
197
198
    /**
199
     * @param Client      $client
200
     * @param UserAccount $userAccount
201
     * @param string      $redirectUri
202
     *
203
     * @return string
204
     */
205
    private function calculateSubjectIdentifier(Client $client, UserAccount $userAccount, string $redirectUri): string
206
    {
207
        $sub = $userAccount->getUserAccountId()->getValue();
208
        if (false === $this->isPairwiseSubjectIdentifierSupported()) {
209
            return $sub;
210
        }
211
        if (($client->has('subject_type') && ('pairwise' === $client->get('subject_type')))) {
212
            $sectorIdentifierHost = $this->getSectorIdentifierHost($client, $redirectUri);
213
214
            return $this->pairwiseAlgorithm->calculateSubjectIdentifier(
215
                $userAccount,
216
                $sectorIdentifierHost
217
            );
218
        }
219
220
        return $sub;
221
    }
222
223
    /**
224
     * @param Client $client
225
     * @param string $redirectUri
226
     *
227
     * @return string
228
     */
229
    private function getSectorIdentifierHost(Client $client, string $redirectUri): string
230
    {
231
        $uri = $redirectUri;
232
233
        if (true === $client->has('sector_identifier_uri')) {
234
            $uri = $client->get('sector_identifier_uri');
235
        }
236
237
        $data = parse_url($uri);
238
        if (!is_array($data) || !array_key_exists('host', $data)) {
239
            throw new \InvalidArgumentException(sprintf('Invalid Sector Identifier Uri "%s".', $uri));
240
        }
241
242
        return $data['host'];
243
    }
244
}
245