Failed Conditions
Push — master ( b5a0b4...819484 )
by Florent
08:00
created

OpenIdConnectExtension::enableEncryption()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 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;
15
16
use Jose\Component\Core\JWKSet;
17
use Jose\Component\Encryption\JWEBuilder;
18
use Jose\Component\Signature\JWSBuilder;
19
use OAuth2Framework\Component\Core\AccessToken\AccessToken;
20
use OAuth2Framework\Component\Core\Client\Client;
21
use OAuth2Framework\Component\Core\ResourceOwner\ResourceOwner;
22
use OAuth2Framework\Component\Core\UserAccount\UserAccount;
23
use OAuth2Framework\Component\TokenEndpoint\Extension\TokenEndpointExtension;
24
use OAuth2Framework\Component\TokenEndpoint\GrantType;
25
use OAuth2Framework\Component\TokenEndpoint\GrantTypeData;
26
use Psr\Http\Message\ServerRequestInterface;
27
28
class OpenIdConnectExtension implements TokenEndpointExtension
29
{
30
    /**
31
     * @var JWKSet|null
32
     */
33
    private $signatureKeys = null;
34
35
    /**
36
     * @var JWSBuilder|null
37
     */
38
    private $jwsBuilder = null;
39
40
    /**
41
     * @var JWEBuilder|null
42
     */
43
    private $jweBuilder = null;
44
45
    /**
46
     * @var IdTokenBuilderFactory
47
     */
48
    private $idTokenBuilderFactory;
49
50
    /**
51
     * @var string
52
     */
53
    private $defaultSignatureAlgorithm;
54
55
    public function __construct(IdTokenBuilderFactory $idTokenBuilderFactory, string $defaultSignatureAlgorithm, JWSBuilder $jwsBuilder, JWKSet $signatureKeys)
56
    {
57
        $this->jwsBuilder = $jwsBuilder;
58
        $this->signatureKeys = $signatureKeys;
59
        $this->idTokenBuilderFactory = $idTokenBuilderFactory;
60
        $this->defaultSignatureAlgorithm = $defaultSignatureAlgorithm;
61
    }
62
63
    public function enableEncryption(JWEBuilder $jweBuilder)
64
    {
65
        $this->jweBuilder = $jweBuilder;
66
    }
67
68
    public function beforeAccessTokenIssuance(ServerRequestInterface $request, GrantTypeData $grantTypeData, GrantType $grantType, callable $next): GrantTypeData
69
    {
70
        return $next($request, $grantTypeData, $grantType);
71
    }
72
73
    public function afterAccessTokenIssuance(Client $client, ResourceOwner $resourceOwner, AccessToken $accessToken, callable $next): array
74
    {
75
        $data = $next($client, $resourceOwner, $accessToken);
76
        if ($resourceOwner instanceof UserAccount && $this->hasOpenIdScope($accessToken) && $accessToken->getMetadata()->has('redirect_uri')) {
77
            $idToken = $this->issueIdToken($client, $resourceOwner, $accessToken);
78
            $data['id_token'] = $idToken;
79
        }
80
81
        return $data;
82
    }
83
84
    private function issueIdToken(Client $client, UserAccount $userAccount, AccessToken $accessToken): string
85
    {
86
        $redirectUri = $accessToken->getMetadata()->get('redirect_uri');
87
        $idTokenBuilder = $this->idTokenBuilderFactory->createBuilder($client, $userAccount, $redirectUri);
0 ignored issues
show
Bug introduced by
It seems like $redirectUri can also be of type null; however, parameter $redirectUri of OAuth2Framework\Componen...actory::createBuilder() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
        $idTokenBuilder = $this->idTokenBuilderFactory->createBuilder($client, $userAccount, /** @scrutinizer ignore-type */ $redirectUri);
Loading history...
88
89
        $requestedClaims = $this->getIdTokenClaims($accessToken);
90
        $idTokenBuilder->withRequestedClaims($requestedClaims);
91
        $idTokenBuilder->withAccessTokenId($accessToken->getId());
92
93
        if ($client->has('id_token_signed_response_alg')) {
94
            $signatureAlgorithm = $client->get('id_token_signed_response_alg');
95
            $idTokenBuilder->withSignature($this->jwsBuilder, $this->signatureKeys, $signatureAlgorithm);
0 ignored issues
show
Bug introduced by
It seems like $signatureAlgorithm can also be of type null; however, parameter $signatureAlgorithm of OAuth2Framework\Componen...uilder::withSignature() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            $idTokenBuilder->withSignature($this->jwsBuilder, $this->signatureKeys, /** @scrutinizer ignore-type */ $signatureAlgorithm);
Loading history...
Bug introduced by
It seems like $this->jwsBuilder can also be of type null; however, parameter $jwsBuilder of OAuth2Framework\Componen...uilder::withSignature() does only seem to accept Jose\Component\Signature\JWSBuilder, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            $idTokenBuilder->withSignature(/** @scrutinizer ignore-type */ $this->jwsBuilder, $this->signatureKeys, $signatureAlgorithm);
Loading history...
Bug introduced by
It seems like $this->signatureKeys can also be of type null; however, parameter $signatureKeys of OAuth2Framework\Componen...uilder::withSignature() does only seem to accept Jose\Component\Core\JWKSet, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            $idTokenBuilder->withSignature($this->jwsBuilder, /** @scrutinizer ignore-type */ $this->signatureKeys, $signatureAlgorithm);
Loading history...
96
        } else {
97
            $idTokenBuilder->withSignature($this->jwsBuilder, $this->signatureKeys, $this->defaultSignatureAlgorithm);
98
        }
99
        if ($client->has('userinfo_encrypted_response_alg') && $client->has('userinfo_encrypted_response_enc') && null !== $this->jweBuilder) {
100
            $keyEncryptionAlgorithm = $client->get('userinfo_encrypted_response_alg');
101
            $contentEncryptionAlgorithm = $client->get('userinfo_encrypted_response_enc');
102
            $idTokenBuilder->withEncryption($this->jweBuilder, $keyEncryptionAlgorithm, $contentEncryptionAlgorithm);
0 ignored issues
show
Bug introduced by
It seems like $contentEncryptionAlgorithm can also be of type null; however, parameter $contentEncryptionAlgorithm of OAuth2Framework\Componen...ilder::withEncryption() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

102
            $idTokenBuilder->withEncryption($this->jweBuilder, $keyEncryptionAlgorithm, /** @scrutinizer ignore-type */ $contentEncryptionAlgorithm);
Loading history...
Bug introduced by
It seems like $keyEncryptionAlgorithm can also be of type null; however, parameter $keyEncryptionAlgorithm of OAuth2Framework\Componen...ilder::withEncryption() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

102
            $idTokenBuilder->withEncryption($this->jweBuilder, /** @scrutinizer ignore-type */ $keyEncryptionAlgorithm, $contentEncryptionAlgorithm);
Loading history...
103
        }
104
        if ($client->has('require_auth_time')) {
105
            $idTokenBuilder->withAuthenticationTime();
106
        }
107
        $idTokenBuilder->setAccessToken($accessToken);
108
109
        return $idTokenBuilder->build();
110
    }
111
112
    private function getIdTokenClaims(AccessToken $accessToken): array
113
    {
114
        if (!$accessToken->getMetadata()->has('requested_claims')) {
115
            return [];
116
        }
117
118
        $requestedClaims = $accessToken->getMetadata()->get('requested_claims');
119
        $requestedClaims = \Safe\json_decode($requestedClaims, true);
0 ignored issues
show
Bug introduced by
It seems like $requestedClaims can also be of type null; however, parameter $json of Safe\json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
        $requestedClaims = \Safe\json_decode(/** @scrutinizer ignore-type */ $requestedClaims, true);
Loading history...
120
        if (!\is_array($requestedClaims)) {
121
            throw new \InvalidArgumentException('Invalid claim request');
122
        }
123
        if (true === \array_key_exists('id_token', $requestedClaims)) {
124
            return $requestedClaims['id_token'];
125
        }
126
127
        return [];
128
    }
129
130
    private function hasOpenIdScope(AccessToken $accessToken): bool
131
    {
132
        return $accessToken->getParameter()->has('scope') && \in_array('openid', \explode(' ', $accessToken->getParameter()->get('scope')), true);
133
    }
134
}
135