Issues (16)

src/Controller/SignatureController.php (4 issues)

Labels
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2018 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 U2FAuthentication\Bundle\Controller;
13
14
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
15
use Symfony\Component\HttpFoundation\JsonResponse;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
18
use Symfony\Component\HttpKernel\Exception\HttpException;
19
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
20
use U2FAuthentication\Bundle\Event\Events;
21
use U2FAuthentication\Bundle\Event\SignatureRequestIssuedEvent;
22
use U2FAuthentication\Bundle\Event\SignatureResponseInvalidEvent;
23
use U2FAuthentication\Bundle\Event\SignatureResponseValidatedEvent;
24
use U2FAuthentication\Bundle\Model\HasKeyCounters;
25
use U2FAuthentication\Bundle\Model\HasRegisteredKeys;
26
use U2FAuthentication\KeyHandle;
0 ignored issues
show
The type U2FAuthentication\KeyHandle was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use U2FAuthentication\SignatureRequest;
0 ignored issues
show
The type U2FAuthentication\SignatureRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use U2FAuthentication\SignatureResponse;
0 ignored issues
show
The type U2FAuthentication\SignatureResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
30
class SignatureController
31
{
32
    /**
33
     * @var string
34
     */
35
    private $applicationId;
36
37
    /**
38
     * @var EventDispatcherInterface
39
     */
40
    private $eventDispatcher;
41
42
    /**
43
     * @var TokenStorageInterface
44
     */
45
    private $tokenStorage;
46
47
    /**
48
     * SignatureRequestController constructor.
49
     *
50
     * @param EventDispatcherInterface $eventDispatcher
51
     * @param string                   $applicationId
52
     * @param TokenStorageInterface    $tokenStorage
53
     */
54
    public function __construct(EventDispatcherInterface $eventDispatcher, string $applicationId, TokenStorageInterface $tokenStorage)
55
    {
56
        $this->eventDispatcher = $eventDispatcher;
57
        $this->applicationId = $applicationId;
58
        $this->tokenStorage = $tokenStorage;
59
    }
60
61
    /**
62
     * @param Request $request
63
     *
64
     * @return JsonResponse
65
     */
66
    public function getSignatureRequestAction(Request $request): JsonResponse
67
    {
68
        $user = $this->getUser();
69
70
        try {
71
            $signatureRequest = SignatureRequest::create(
72
                $this->applicationId,
73
                $user->getRegisteredKeys()
74
            );
75
            $request->getSession()->set('U2F_SIGNATURE_REQUEST', $signatureRequest);
76
            $this->eventDispatcher->dispatch(
77
                Events::U2F_SIGNATURE_REQUEST_ISSUED,
78
                new SignatureRequestIssuedEvent($user, $signatureRequest)
79
            );
80
81
            return new JsonResponse($signatureRequest);
82
        } catch (\Exception $e) {
83
            throw new HttpException(500, 'An error occurred during the creation of the signature request.', $e);
84
        }
85
    }
86
87
    /**
88
     * @param Request $request
89
     *
90
     * @return JsonResponse
91
     */
92
    public function postSignatureRequestAction(Request $request): JsonResponse
93
    {
94
        $user = $this->getUser();
95
        $signatureRequest = $request->getSession()->get('U2F_SIGNATURE_REQUEST');
96
        if (!$signatureRequest instanceof SignatureRequest) {
97
            throw new HttpException(400, 'The signature request is missing');
98
        }
99
        $request->getSession()->remove('U2F_SIGNATURE_REQUEST');
100
101
        $data = $request->request->all();
102
        $signatureResponse = SignatureResponse::create($data);
103
        $counter = $this->getKeyCounter($signatureResponse->getKeyHandle(), $user);
104
105
        if (!$signatureResponse->isValid($signatureRequest, $counter)) {
106
            $this->eventDispatcher->dispatch(
107
                Events::U2F_SIGNATURE_RESPONSE_INVALID,
108
                new SignatureResponseInvalidEvent($user, $signatureResponse)
109
            );
110
111
            throw new HttpException(400, 'The signature response is invalid');
112
        }
113
114
        $this->eventDispatcher->dispatch(
115
            Events::U2F_SIGNATURE_RESPONSE_VALIDATED,
116
            new SignatureResponseValidatedEvent($user, $signatureResponse)
117
        );
118
119
        return new JsonResponse(['signature' => 'ok'], 204);
120
    }
121
122
    /**
123
     * @return HasRegisteredKeys
124
     */
125
    private function getUser(): HasRegisteredKeys
126
    {
127
        $token = $this->tokenStorage->getToken();
128
        if (null === $token) {
129
            throw new AccessDeniedHttpException('The user must be connected');
130
        }
131
        $user = $token->getUser();
132
        if (null === $user) {
0 ignored issues
show
The condition null === $user is always false.
Loading history...
133
            throw new AccessDeniedHttpException('The user must be connected');
134
        }
135
        if (!$user instanceof HasRegisteredKeys) {
136
            throw new AccessDeniedHttpException('The user does not support the U2F keys');
137
        }
138
139
        return $user;
140
    }
141
142
    /**
143
     * @param KeyHandle         $keyHandle
144
     * @param HasRegisteredKeys $user
145
     *
146
     * @return int|null
147
     */
148
    private function getKeyCounter(KeyHandle $keyHandle, HasRegisteredKeys $user): ?int
149
    {
150
        if (!$user instanceof HasKeyCounters) {
151
            return null;
152
        }
153
154
        return $user->getCounterForKey($keyHandle);
155
    }
156
}
157