Failed Conditions
Push — v7 ( 1e67af...6a6683 )
by Florent
02:18
created

KeysetAnalyzerCommand   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 0
Metric Value
wmc 16
lcom 2
cbo 6
dl 0
loc 93
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 9 1
C execute() 0 53 11
A getKeyset() 0 15 4
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2017 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace Jose\Bundle\Console\Command;
15
16
use Jose\Component\Core\JWKSet;
17
use Jose\Component\KeyManagement\KeyAnalyzer\JWKAnalyzerManager;
18
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Output\OutputInterface;
22
23
final class KeysetAnalyzerCommand extends ContainerAwareCommand
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    protected function configure()
29
    {
30
        $this
31
            ->setName('keyset:analyze')
32
            ->setDescription('JWKSet quality analyzer.')
33
            ->setHelp('This command will analyze a JWKSet object and find security issues.')
34
            ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object')
35
        ;
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41
    protected function execute(InputInterface $input, OutputInterface $output)
42
    {
43
        /** @var JWKAnalyzerManager $analyzerManager */
44
        $analyzerManager = $this->getContainer()->get(JWKAnalyzerManager::class);
45
        $jwkset = $this->getKeyset($input);
46
47
        $privateKeys = 0;
48
        $publicKeys = 0;
49
        $sharedKeys = 0;
50
        $mixedKeys = false;
51
52
        foreach ($jwkset as $kid => $jwk) {
53
            $output->writeln(sprintf('Analysing key with index/kid "%s"', $kid));
54
            $messages = $analyzerManager->analyze($jwk);
0 ignored issues
show
Bug introduced by
It seems like $jwk defined by $jwk on line 52 can be null; however, Jose\Component\KeyManage...lyzerManager::analyze() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
55
            if (!empty($messages)) {
56
                foreach ($messages as $message) {
57
                    $output->writeln('    '.$message);
58
                }
59
            } else {
60
                $output->writeln('    No issue with this key');
61
            }
62
63
            switch (true) {
64
                case 'oct' === $jwk->get('kty'):
65
                    $sharedKeys++;
66
                    if (0 !== $privateKeys + $publicKeys) {
67
                        $mixedKeys = true;
68
                    }
69
70
                    break;
71
                case in_array($jwk->get('kty'), ['RSA', 'EC', 'OKP']):
72
                    if ($jwk->has('d')) {
73
                        ++$privateKeys;
74
                        if (0 !== $sharedKeys + $publicKeys) {
75
                            $mixedKeys = true;
76
                        }
77
                    } else {
78
                        ++$publicKeys;
79
                        if (0 !== $privateKeys + $sharedKeys) {
80
                            $mixedKeys = true;
81
                        }
82
                    }
83
84
                    break;
85
                default:
86
                    break;
87
            }
88
        }
89
90
        if ($mixedKeys) {
91
            $output->writeln('/!\\ This key set mixes share, public and private keys. You should create one key set per key type. /!\\');
92
        }
93
    }
94
95
    /**
96
     * @param InputInterface $input
97
     *
98
     * @return JWKSet
99
     */
100
    private function getKeyset(InputInterface $input): JWKSet
101
    {
102
        $jwkset = $input->getArgument('jwkset');
103
        $json = json_decode($jwkset, true);
104
        if (is_array($json)) {
105
            return JWKSet::createFromKeyData($json);
106
        } elseif ($this->getContainer()->has($jwkset)) {
107
            $id = $this->getContainer()->get($jwkset);
108
            if ($id instanceof JWKSet) {
109
                return $id;
110
            }
111
        }
112
113
        throw new \InvalidArgumentException('The argument must be a valid JWKSet or a service ID to a JWKSet.');
114
    }
115
}
116