Completed
Push — master ( c79410...2b815c )
by Florent
02:46
created

JWTLoader   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
c 1
b 0
f 0
lcom 2
cbo 9
dl 0
loc 156
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 2
A enableEncryptionSupport() 0 4 1
A getSupportedSignatureAlgorithms() 0 4 1
A getSupportedKeyEncryptionAlgorithms() 0 4 2
A getSupportedContentEncryptionAlgorithms() 0 4 2
A getSupportedCompressionMethods() 0 4 2
A load() 0 19 3
A isEncryptionSupportEnabled() 0 4 1
A decryptAssertion() 0 9 1
A verifySignature() 0 12 1
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose;
13
14
use Assert\Assertion;
15
use Jose\Checker\CheckerManagerInterface;
16
use Jose\Object\JWEInterface;
17
use Jose\Object\JWKSetInterface;
18
use Jose\Object\JWSInterface;
19
use Psr\Log\LoggerInterface;
20
21
final class JWTLoader
22
{
23
    /**
24
     * @var null|\Psr\Log\LoggerInterface
25
     */
26
    private $logger;
27
28
    /**
29
     * @var \Jose\LoaderInterface
30
     */
31
    private $loader;
32
33
    /**
34
     * @var \Jose\Checker\CheckerManagerInterface
35
     */
36
    private $checker_manager;
37
38
    /**
39
     * @var \Jose\DecrypterInterface|null
40
     */
41
    private $decrypter = null;
42
43
    /**
44
     * @var \Jose\VerifierInterface
45
     */
46
    private $verifier;
47
48
    /**
49
     * JWTLoader constructor.
50
     *
51
     * @param \Jose\Checker\CheckerManagerInterface $checker_manager
52
     * @param \Jose\VerifierInterface               $verifier
53
     * @param \Psr\Log\LoggerInterface|null         $logger
54
     */
55
    public function __construct(CheckerManagerInterface $checker_manager, VerifierInterface $verifier, LoggerInterface $logger = null)
56
    {
57
        $this->checker_manager = $checker_manager;
58
        $this->verifier = $verifier;
59
        $this->logger = $logger;
60
        $this->loader = new Loader();
61
        if (null !== $logger) {
62
            $this->loader->enableLogging($logger);
63
        }
64
    }
65
66
    /**
67
     * @param \Jose\DecrypterInterface $decrypter
68
     */
69
    public function enableEncryptionSupport(DecrypterInterface $decrypter)
70
    {
71
        $this->decrypter = $decrypter;
72
    }
73
74
    /**
75
     * @return string[]
76
     */
77
    public function getSupportedSignatureAlgorithms()
78
    {
79
        return $this->verifier->getSupportedSignatureAlgorithms();
80
    }
81
82
    /**
83
     * @return string[]
84
     */
85
    public function getSupportedKeyEncryptionAlgorithms()
86
    {
87
        return null === $this->decrypter ? [] : $this->decrypter->getSupportedKeyEncryptionAlgorithms();
88
    }
89
90
    /**
91
     * @return string[]
92
     */
93
    public function getSupportedContentEncryptionAlgorithms()
94
    {
95
        return null === $this->decrypter ? [] : $this->decrypter->getSupportedContentEncryptionAlgorithms();
96
    }
97
98
    /**
99
     * @return string[]
100
     */
101
    public function getSupportedCompressionMethods()
102
    {
103
        return null === $this->decrypter ? [] : $this->decrypter->getSupportedCompressionMethods();
104
    }
105
106
    /**
107
     * @param string                            $assertion
108
     * @param array                             $allowed_key_encryption_algorithms
109
     * @param array                             $allowed_content_encryption_algorithms
110
     * @param \Jose\Object\JWKSetInterface|null $encryption_key_set
111
     * @param bool                              $is_encryption_required
112
     *
113
     * @return \Jose\Object\JWSInterface
114
     */
115
    public function load($assertion, array $allowed_key_encryption_algorithms = [], array $allowed_content_encryption_algorithms = [], JWKSetInterface $encryption_key_set = null, $is_encryption_required = false)
116
    {
117
        Assertion::string($assertion);
118
        Assertion::boolean($is_encryption_required);
119
        $jwt = $this->loader->load($assertion);
120
        if ($jwt instanceof JWEInterface) {
121
            Assertion::notNull($encryption_key_set, 'Encryption key set is not available.');
122
            Assertion::true($this->isEncryptionSupportEnabled(), 'Encryption support is not enabled.');
123
            $key_encryption_algorithms = array_intersect($allowed_key_encryption_algorithms, $this->getSupportedKeyEncryptionAlgorithms());
124
            $content_encryption_algorithms = array_intersect($allowed_content_encryption_algorithms, $this->getSupportedContentEncryptionAlgorithms());
125
            Assertion::inArray($jwt->getSharedProtectedHeader('alg'), $key_encryption_algorithms, sprintf('The key encryption algorithm "%s" is not allowed.', $jwt->getSharedProtectedHeader('alg')));
126
            Assertion::inArray($jwt->getSharedProtectedHeader('enc'), $content_encryption_algorithms, sprintf('The content encryption algorithm "%s" is not allowed or not supported.', $jwt->getSharedProtectedHeader('enc')));
127
            $jwt = $this->decryptAssertion($jwt, $encryption_key_set);
0 ignored issues
show
Bug introduced by
It seems like $encryption_key_set defined by parameter $encryption_key_set on line 115 can be null; however, Jose\JWTLoader::decryptAssertion() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
128
        } elseif (true === $is_encryption_required) {
129
            throw new \InvalidArgumentException('The assertion must be encrypted.');
130
        }
131
132
        return $jwt;
133
    }
134
135
    /**
136
     * @return bool
137
     */
138
    private function isEncryptionSupportEnabled()
139
    {
140
        return null !== $this->decrypter;
141
    }
142
143
    /**
144
     * @param \Jose\Object\JWEInterface    $jwe
145
     * @param \Jose\Object\JWKSetInterface $encryption_key_set
146
     *
147
     * @return \Jose\Object\JWSInterface
148
     */
149
    private function decryptAssertion(JWEInterface $jwe, JWKSetInterface $encryption_key_set)
150
    {
151
        $this->decrypter->decryptUsingKeySet($jwe, $encryption_key_set);
152
153
        $jws = $this->loader->load($jwe->getPayload());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->loader->load($jwe->getPayload()); of type Jose\Object\JWSInterface|Jose\Object\JWEInterface adds the type Jose\Object\JWEInterface to the return on line 156 which is incompatible with the return type documented by Jose\JWTLoader::decryptAssertion of type Jose\Object\JWSInterface.
Loading history...
154
        Assertion::isInstanceOf($jws, JWSInterface::class, 'The encrypted assertion does not contain a JWS.');
155
156
        return $jws;
157
    }
158
159
    /**
160
     * @param \Jose\Object\JWSInterface    $jws
161
     * @param \Jose\Object\JWKSetInterface $signature_key_set
162
     * @param array                        $allowed_signature_algorithms
163
     */
164
    public function verifySignature(JWSInterface $jws, JWKSetInterface $signature_key_set, array $allowed_signature_algorithms)
165
    {
166
        $algorithms = array_intersect(
167
            $allowed_signature_algorithms,
168
            $this->getSupportedSignatureAlgorithms()
169
        );
170
        Assertion::inArray($jws->getSignature(0)->getProtectedHeader('alg'), $algorithms, sprintf('The signature algorithm "%s" is not supported or not allowed.', $jws->getSignature(0)->getProtectedHeader('alg')));
171
172
        $index = null;
173
        $this->verifier->verifyWithKeySet($jws, $signature_key_set, null, $index);
174
        $this->checker_manager->checkJWS($jws, $index);
175
    }
176
}
177