Passed
Push — master ( 898cc7...450add )
by Thomas Mauro
03:07
created

TokenSetVerifier::getIdTokenVerifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TMV\OpenIdClient\Token;
6
7
use Jose\Component\Checker\ClaimCheckerManager;
8
use function TMV\OpenIdClient\base64url_decode;
9
use TMV\OpenIdClient\ClaimChecker\AtHashChecker;
10
use TMV\OpenIdClient\ClaimChecker\CHashChecker;
11
use TMV\OpenIdClient\ClaimChecker\SHashChecker;
12
use TMV\OpenIdClient\ClientInterface;
13
use TMV\OpenIdClient\Exception\InvalidArgumentException;
14
use TMV\OpenIdClient\Model\AuthSessionInterface;
15
16
class TokenSetVerifier implements TokenSetVerifierInterface
17
{
18
    /** @var IdTokenVerifierInterface */
19
    private $idTokenVerifier;
20
21
    /**
22
     * TokenSetVerifier constructor.
23
     *
24
     * @param null|IdTokenVerifierInterface $idTokenVerifier
25
     */
26
    public function __construct(?IdTokenVerifierInterface $idTokenVerifier = null)
27
    {
28
        $this->idTokenVerifier = $idTokenVerifier ?: new IdTokenVerifier();
29
    }
30
31
    /**
32
     * @return IdTokenVerifierInterface
33
     */
34
    public function getIdTokenVerifier(): IdTokenVerifierInterface
35
    {
36
        return $this->idTokenVerifier;
37
    }
38
39
    public function validate(
40
        TokenSetInterface $tokenSet,
41
        ClientInterface $client,
42
        ?AuthSessionInterface $authSession = null,
43
        bool $fromAuthorization = true,
44
        ?int $maxAge = null
45
    ): void {
46
        $idToken = $tokenSet->getIdToken();
47
48
        if (! $idToken) {
49
            throw new InvalidArgumentException('No id_token in token set');
50
        }
51
52
        $this->getIdTokenVerifier()->validateIdToken($client, $idToken, $authSession);
53
54
        $metadata = $client->getMetadata();
55
56
        $header = \json_decode(base64url_decode(\explode('.', $idToken)[0] ?? '{}'), true);
57
        $payload = \json_decode(base64url_decode(\explode('.', $idToken)[1] ?? '{}'), true);
58
59
        if (! \is_array($payload)) {
60
            throw new InvalidArgumentException('Unable to decode token payload');
61
        }
62
63
        $claimCheckers = [];
64
        $requiredClaims = [];
65
66
        if ($maxAge || (null !== $maxAge && $metadata->get('require_auth_time'))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $maxAge of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
67
            $requiredClaims[] = 'auth_time';
68
        }
69
70
        if ($fromAuthorization) {
71
            $requiredClaims = \array_merge($requiredClaims, [
72
                $tokenSet->getAccessToken() ? 'at_hash' : null,
73
                $tokenSet->getCode() ? 'c_hash' : null,
74
            ]);
75
76
            if (\array_key_exists('s_hash', $payload)) {
77
                $state = $authSession ? $authSession->getState() : null;
78
79
                if (! $state) {
80
                    throw new InvalidArgumentException('Cannot verify s_hash, "state" not provided');
81
                }
82
83
                $claimCheckers[] = new SHashChecker($state, $header['alg'] ?? '');
84
            }
85
        }
86
87
        $accessToken = $tokenSet->getAccessToken();
88
        if ($accessToken) {
89
            $claimCheckers[] = new AtHashChecker($accessToken, $header['alg'] ?? '');
90
        }
91
92
        $code = $tokenSet->getCode();
93
94
        if ($code) {
95
            $claimCheckers[] = new CHashChecker($code, $header['alg'] ?? '');
96
        }
97
98
        $claimCheckerManager = new ClaimCheckerManager(\array_filter($claimCheckers));
99
100
        $claimCheckerManager->check($payload, \array_filter($requiredClaims));
101
    }
102
}
103