TokenSetVerifier   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 33
dl 0
loc 85
ccs 0
cts 54
cp 0
rs 10
c 1
b 0
f 0
wmc 17

3 Methods

Rating   Name   Duplication   Size   Complexity  
C validate() 0 62 14
A getIdTokenVerifier() 0 3 1
A __construct() 0 3 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TMV\OpenIdClient\Token;
6
7
use function array_filter;
8
use function array_key_exists;
9
use function array_merge;
10
use function explode;
11
use function is_array;
12
use Jose\Component\Checker\ClaimCheckerManager;
13
use function json_decode;
14
use function TMV\OpenIdClient\base64url_decode;
15
use TMV\OpenIdClient\ClaimChecker\AtHashChecker;
16
use TMV\OpenIdClient\ClaimChecker\CHashChecker;
17
use TMV\OpenIdClient\ClaimChecker\SHashChecker;
18
use TMV\OpenIdClient\Client\ClientInterface;
19
use TMV\OpenIdClient\Exception\InvalidArgumentException;
20
use TMV\OpenIdClient\Session\AuthSessionInterface;
21
22
class TokenSetVerifier implements TokenSetVerifierInterface
23
{
24
    /** @var IdTokenVerifierInterface */
25
    private $idTokenVerifier;
26
27
    /**
28
     * TokenSetVerifier constructor.
29
     *
30
     * @param null|IdTokenVerifierInterface $idTokenVerifier
31
     */
32
    public function __construct(?IdTokenVerifierInterface $idTokenVerifier = null)
33
    {
34
        $this->idTokenVerifier = $idTokenVerifier ?: new IdTokenVerifier();
35
    }
36
37
    /**
38
     * @return IdTokenVerifierInterface
39
     */
40
    public function getIdTokenVerifier(): IdTokenVerifierInterface
41
    {
42
        return $this->idTokenVerifier;
43
    }
44
45
    public function validate(
46
        TokenSetInterface $tokenSet,
47
        ClientInterface $client,
48
        ?AuthSessionInterface $authSession = null,
49
        bool $fromAuthorization = true,
50
        ?int $maxAge = null
51
    ): void {
52
        $idToken = $tokenSet->getIdToken();
53
54
        if (null === $idToken) {
55
            throw new InvalidArgumentException('No id_token in token set');
56
        }
57
58
        $this->getIdTokenVerifier()->validateIdToken($client, $idToken, $authSession);
59
60
        $metadata = $client->getMetadata();
61
62
        $header = json_decode(base64url_decode(explode('.', $idToken)[0] ?? '{}'), true);
63
        $payload = json_decode(base64url_decode(explode('.', $idToken)[1] ?? '{}'), true);
64
65
        if (! is_array($payload)) {
66
            throw new InvalidArgumentException('Unable to decode token payload');
67
        }
68
69
        $claimCheckers = [];
70
        $requiredClaims = [];
71
72
        if ((int) $maxAge > 0 || (null !== $maxAge && null !== $metadata->get('require_auth_time'))) {
73
            $requiredClaims[] = 'auth_time';
74
        }
75
76
        if ($fromAuthorization) {
77
            $requiredClaims = array_merge($requiredClaims, [
78
                null !== $tokenSet->getAccessToken() ? 'at_hash' : null,
79
                null !== $tokenSet->getCode() ? 'c_hash' : null,
80
            ]);
81
82
            if (array_key_exists('s_hash', $payload)) {
83
                $state = null !== $authSession ? $authSession->getState() : null;
84
85
                if (null === $state) {
86
                    throw new InvalidArgumentException('Cannot verify s_hash, "state" not provided');
87
                }
88
89
                $claimCheckers[] = new SHashChecker($state, $header['alg'] ?? '');
90
            }
91
        }
92
93
        $accessToken = $tokenSet->getAccessToken();
94
        if (null !== $accessToken) {
95
            $claimCheckers[] = new AtHashChecker($accessToken, $header['alg'] ?? '');
96
        }
97
98
        $code = $tokenSet->getCode();
99
100
        if (null !== $code) {
101
            $claimCheckers[] = new CHashChecker($code, $header['alg'] ?? '');
102
        }
103
104
        $claimCheckerManager = new ClaimCheckerManager(array_filter($claimCheckers));
105
106
        $claimCheckerManager->check($payload, array_filter($requiredClaims));
107
    }
108
}
109