Completed
Push — master ( 547bd7...8b2a0a )
by Florent
02:35
created

JWTLoader::getSupportedKeyEncryptionAlgorithms()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 0
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\Factory;
13
14
use Assert\Assertion;
15
use Jose\Checker\CheckerManagerInterface;
16
use Jose\Decrypter;
17
use Jose\Loader;
18
use Jose\Object\JWEInterface;
19
use Jose\Object\JWKSetInterface;
20
use Jose\Object\JWSInterface;
21
use Jose\Verifier;
22
use Psr\Log\LoggerInterface;
23
24
final class JWTLoader
25
{
26
    /**
27
     * @var null|\Psr\Log\LoggerInterface
28
     */
29
    private $logger;
30
31
    /**
32
     * @var \Jose\LoaderInterface
33
     */
34
    private $loader;
35
36
    /**
37
     * @var \Jose\Checker\CheckerManagerInterface
38
     */
39
    private $checker_manager;
40
41
    /**
42
     * @var \Jose\DecrypterInterface|null
43
     */
44
    private $decrypter = null;
45
46
    /**
47
     * @var \Jose\VerifierInterface
48
     */
49
    private $verifier;
50
51
    /**
52
     * JWTLoader constructor.
53
     *
54
     * @param \Jose\Checker\CheckerManagerInterface                  $checker_manager
55
     * @param string[]|\Jose\Algorithm\SignatureAlgorithmInterface[] $supported_signature_algorithms
56
     * @param \Psr\Log\LoggerInterface|null                          $logger
57
     */
58
    public function __construct(CheckerManagerInterface $checker_manager, array $supported_signature_algorithms, LoggerInterface $logger = null)
59
    {
60
        $this->checker_manager = $checker_manager;
61
        $this->logger = $logger;
62
        $this->loader = new Loader($logger);
63
        $this->verifier = Verifier::createVerifier($supported_signature_algorithms, $logger);
64
    }
65
66
    /**
67
     * @param string[]|\Jose\Algorithm\KeyEncryptionAlgorithmInterface[]     $supported_key_encryption_algorithms
68
     * @param string[]|\Jose\Algorithm\ContentEncryptionAlgorithmInterface[] $supported_content_encryption_algorithms
69
     * @param string[]|\Jose\Compression\CompressionInterface                $supported_compression_methods
70
     */
71
    public function enableEncryptionSupport(array $supported_key_encryption_algorithms,
72
                                            array $supported_content_encryption_algorithms,
73
                                            array $supported_compression_methods = ['DEF', 'ZLIB', 'GZ']
74
    ) {
75
        Assertion::notEmpty($supported_key_encryption_algorithms, 'At least one key encryption algorithm must be set.');
76
        Assertion::notEmpty($supported_content_encryption_algorithms, 'At least one content encryption algorithm must be set.');
77
78
        $this->decrypter = Decrypter::createDecrypter(
79
            $supported_key_encryption_algorithms,
80
            $supported_content_encryption_algorithms,
81
            $supported_compression_methods,
82
            $this->logger
83
        );
84
    }
85
86
    /**
87
     * @return string[]
88
     */
89
    public function getSupportedSignatureAlgorithms()
90
    {
91
        return $this->verifier->getSupportedSignatureAlgorithms();
92
    }
93
94
    /**
95
     * @return string[]
96
     */
97
    public function getSupportedKeyEncryptionAlgorithms()
98
    {
99
        return null === $this->decrypter ? [] : $this->decrypter->getSupportedKeyEncryptionAlgorithms();
100
    }
101
102
    /**
103
     * @return string[]
104
     */
105
    public function getSupportedContentEncryptionAlgorithms()
106
    {
107
        return null === $this->decrypter ? [] : $this->decrypter->getSupportedContentEncryptionAlgorithms();
108
    }
109
110
    /**
111
     * @return string[]
112
     */
113
    public function getSupportedCompressionMethods()
114
    {
115
        return null === $this->decrypter ? [] : $this->decrypter->getSupportedCompressionMethods();
116
    }
117
118
    /**
119
     * @param string                            $assertion
120
     * @param array                             $allowed_key_encryption_algorithms
121
     * @param array                             $allowed_content_encryption_algorithms
122
     * @param \Jose\Object\JWKSetInterface|null $encryption_key_set
123
     * @param bool                              $is_encryption_required
124
     *
125
     * @return \Jose\Object\JWSInterface
126
     */
127
    public function load($assertion, array $allowed_key_encryption_algorithms = [], array $allowed_content_encryption_algorithms = [], JWKSetInterface $encryption_key_set = null, $is_encryption_required = false)
128
    {
129
        Assertion::string($assertion);
130
        Assertion::boolean($is_encryption_required);
131
        $jwt = $this->loader->load($assertion);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->loader->load($assertion); of type Jose\Object\JWSInterface|Jose\Object\JWEInterface adds the type Jose\Object\JWEInterface to the return on line 143 which is incompatible with the return type documented by Jose\Factory\JWTLoader::load of type Jose\Object\JWSInterface.
Loading history...
132
        if ($jwt instanceof JWEInterface) {
133
            Assertion::true($this->isEncryptionSupportEnabled(), 'Encryption support is not enabled.');
134
            $key_encryption_algorithms = array_intersect($allowed_key_encryption_algorithms, $this->getSupportedKeyEncryptionAlgorithms());
135
            $content_encryption_algorithms = array_intersect($allowed_content_encryption_algorithms, $this->getSupportedContentEncryptionAlgorithms());
136
            Assertion::inArray($jwt->getSharedProtectedHeader('alg'), $key_encryption_algorithms, sprintf('The key encryption algorithm "%s" is not allowed.', $jwt->getSharedProtectedHeader('alg')));
137
            Assertion::inArray($jwt->getSharedProtectedHeader('enc'), $content_encryption_algorithms, sprintf('The content encryption algorithm "%s" is not allowed or not supported.', $jwt->getSharedProtectedHeader('enc')));
138
            $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 127 can be null; however, Jose\Factory\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...
Bug Compatibility introduced by
The expression $this->decryptAssertion(..., $encryption_key_set); of type Jose\Object\JWEInterface|Jose\Object\JWSInterface adds the type Jose\Object\JWEInterface to the return on line 143 which is incompatible with the return type documented by Jose\Factory\JWTLoader::load of type Jose\Object\JWSInterface.
Loading history...
139
        } elseif (true === $is_encryption_required) {
140
            throw new \InvalidArgumentException('The assertion must be encrypted.');
141
        }
142
143
        return $jwt;
144
    }
145
146
    /**
147
     * @return bool
148
     */
149
    private function isEncryptionSupportEnabled()
150
    {
151
        return null !== $this->decrypter;
152
    }
153
154
    /**
155
     * @param \Jose\Object\JWEInterface    $jwe
156
     * @param \Jose\Object\JWKSetInterface $encryption_key_set
157
     *
158
     * @return \Jose\Object\JWEInterface|\Jose\Object\JWSInterface
159
     */
160
    private function decryptAssertion(JWEInterface $jwe, JWKSetInterface $encryption_key_set)
161
    {
162
        $this->decrypter->decryptUsingKeySet($jwe, $encryption_key_set);
163
164
        $jws = $this->loader->load($jwe->getPayload());
165
        Assertion::isInstanceOf($jws, JWSInterface::class, 'The encrypted assertion does not contain a JWS.');
166
167
        return $jws;
168
    }
169
170
    /**
171
     * @param \Jose\Object\JWSInterface    $jws
172
     * @param \Jose\Object\JWKSetInterface $signature_key_set
173
     * @param array                        $allowed_signature_algorithms
174
     */
175
    public function verifySignature(JWSInterface $jws, JWKSetInterface $signature_key_set, array $allowed_signature_algorithms)
176
    {
177
        $algorithms = array_intersect(
178
            $allowed_signature_algorithms,
179
            $this->getSupportedSignatureAlgorithms()
180
        );
181
        Assertion::inArray($jws->getSignature(0)->getProtectedHeader('alg'), $algorithms, sprintf('The signature algorithm "%s" is not supported or not allowed.', $jws->getSignature(0)->getProtectedHeader('alg')));
182
183
        $index = null;
184
        $this->verifier->verifyWithKeySet($jws, $signature_key_set, null, $index);
185
        $this->checker_manager->checkJWS($jws, $index);
186
    }
187
}
188