Completed
Push — master ( 7210ec...8e6e06 )
by Florent
08:52
created

Verifier::verify()   C

Complexity

Conditions 11
Paths 33

Size

Total Lines 38
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 38
rs 5.2653
cc 11
eloc 23
nc 33
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2015 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 Jose\Algorithm\JWAManagerInterface;
15
use Jose\Algorithm\Signature\SignatureInterface;
16
use Jose\Behaviour\HasCheckerManager;
17
use Jose\Behaviour\HasCompressionManager;
18
use Jose\Behaviour\HasJWAManager;
19
use Jose\Behaviour\HasJWKFinderManager;
20
use Jose\Behaviour\HasKeyChecker;
21
use Jose\Behaviour\HasPayloadConverter;
22
use Jose\Checker\CheckerManagerInterface;
23
use Jose\Compression\CompressionManagerInterface;
24
use Jose\Finder\JWKFinderManagerInterface;
25
use Jose\Object\JWKInterface;
26
use Jose\Object\JWKSet;
27
use Jose\Object\JWKSetInterface;
28
use Jose\Object\JWSInterface;
29
use Jose\Payload\PayloadConverterManagerInterface;
30
31
/**
32
 */
33
final class Verifier implements VerifierInterface
34
{
35
    use HasKeyChecker;
36
    use HasJWAManager;
37
    use HasJWKFinderManager;
38
    use HasCheckerManager;
39
    use HasPayloadConverter;
40
    use HasCompressionManager;
41
42
    /**
43
     * Loader constructor.
44
     *
45
     * @param \Jose\Algorithm\JWAManagerInterface                      $jwa_manager
46
     * @param \Jose\Finder\JWKFinderManagerInterface                $jwk_finder_manager
47
     * @param \Jose\Payload\PayloadConverterManagerInterface $payload_converter_manager
48
     * @param \Jose\Compression\CompressionManagerInterface  $compression_manager
49
     * @param \Jose\Checker\CheckerManagerInterface          $checker_manager
50
     */
51
    public function __construct(
52
        JWAManagerInterface $jwa_manager,
53
        JWKFinderManagerInterface $jwk_finder_manager,
54
        PayloadConverterManagerInterface $payload_converter_manager,
55
        CompressionManagerInterface $compression_manager,
56
        CheckerManagerInterface $checker_manager)
57
    {
58
        $this->setJWAManager($jwa_manager);
59
        $this->setJWKFinderManager($jwk_finder_manager);
60
        $this->setPayloadConverter($payload_converter_manager);
61
        $this->setCompressionManager($compression_manager);
62
        $this->setCheckerManager($checker_manager);
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     *
68
     * @throws \InvalidArgumentException
69
     */
70
    public function verify(JWSInterface $jws, JWKSetInterface $jwk_set = null, $detached_payload = null)
71
    {
72
        if (null !== $detached_payload && !empty($jws->getPayload())) {
73
            throw new \InvalidArgumentException('A detached payload is set, but the JWS already has a payload');
74
        }
75
        $complete_header = $jws->getHeaders();
76
        if (null === $jwk_set) {
77
            $jwk_set = $this->getKeysFromCompleteHeader(
78
                $complete_header,
79
                JWKFinderManagerInterface::KEY_TYPE_PUBLIC | JWKFinderManagerInterface::KEY_TYPE_SYMMETRIC | JWKFinderManagerInterface::KEY_TYPE_NONE
80
            );
81
        }
82
83
        $input = $jws->getEncodedProtectedHeaders().'.'.(null === $detached_payload ? $jws->getEncodedPayload() : $detached_payload);
84
85
        if (0 === count($jwk_set)) {
86
            return false;
87
        }
88
        foreach ($jwk_set->getKeys() as $jwk) {
89
            $algorithm = $this->getAlgorithm($complete_header, $jwk);
90
            if (!$this->checkKeyUsage($jwk, 'verification')) {
91
                continue;
92
            }
93
            if (!$this->checkKeyAlgorithm($jwk, $algorithm->getAlgorithmName())) {
94
                continue;
95
            }
96
            try {
97
                if (true === $algorithm->verify($jwk, $input, $jws->getSignature())) {
98
                    $this->getCheckerManager()->checkJWT($jws);
99
                    return true;
100
                }
101
            } catch (\InvalidArgumentException $e) {
102
                //We do nothing, we continue with other keys
103
            }
104
        }
105
106
        return false;
107
    }
108
109
    /**
110
     * @param array              $header
111
     * @param \Jose\Object\JWKInterface $key
112
     *
113
     * @return \Jose\Algorithm\Signature\SignatureInterface|null
114
     */
115
    private function getAlgorithm(array $header, JWKInterface $key)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
116
    {
117
        if (!array_key_exists('alg', $header)) {
118
            //if (!$key->hasHeader('alg')) {
119
            throw new \InvalidArgumentException("No 'alg' parameter set in the header or the key.");
120
        }/* else {
121
                $alg = $key->getHeader('alg');
122
            }*/
123
        //} else {
124
        $alg = $header['alg'];
125
        //}
126
127
        $algorithm = $this->getJWAManager()->getAlgorithm($alg);
128
        if (!$algorithm instanceof SignatureInterface) {
129
            throw new \RuntimeException("The algorithm '$alg' is not supported or does not implement SignatureInterface.");
130
        }
131
132
        return $algorithm;
133
    }
134
135
    /**
136
     * @param array $header
137
     * @param int   $key_type
138
     *
139
     * @return \Jose\Object\JWKSetInterface
140
     */
141
    private function getKeysFromCompleteHeader(array $header, $key_type)
142
    {
143
        $keys = $this->getJWKFinderManager()->findJWK($header, $key_type);
144
        $jwkset = new JWKSet($keys);
145
146
        return $jwkset;
147
    }
148
}
149