Failed Conditions
Push — master ( ec502b...7a4e00 )
by Florent
05:33
created

AnnotationDriver::onKernelController()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.2
c 0
b 0
f 0
cc 4
eloc 10
nc 4
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 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 OAuth2Framework\ServerBundle\Annotation;
15
16
use Doctrine\Common\Annotations\Reader;
17
use OAuth2Framework\ServerBundle\Annotation\Checker\Checker;
18
use OAuth2Framework\ServerBundle\Security\Authentication\Token\OAuth2Token;
19
use OAuth2Framework\Component\Core\Message\OAuth2Message;
20
use OAuth2Framework\Component\Core\Message\OAuth2MessageFactoryManager;
21
use Psr\Http\Message\ResponseInterface;
22
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
23
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
24
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
25
26
class AnnotationDriver
27
{
28
    /**
29
     * @var Reader
30
     */
31
    private $reader;
32
33
    /**
34
     * @var TokenStorageInterface
35
     */
36
    private $tokenStorage;
37
38
    /**
39
     * @var Checker[]
40
     */
41
    private $checkers = [];
42
43
    /**
44
     * @var OAuth2MessageFactoryManager
45
     */
46
    private $oauth2ResponseFactoryManager;
47
48
    /**
49
     * AnnotationDriver constructor.
50
     *
51
     * @param Reader                      $reader
52
     * @param TokenStorageInterface       $tokenStorage
53
     * @param OAuth2MessageFactoryManager $oauth2ResponseFactoryManager
54
     */
55
    public function __construct(Reader $reader, TokenStorageInterface $tokenStorage, OAuth2MessageFactoryManager $oauth2ResponseFactoryManager)
56
    {
57
        $this->reader = $reader;
58
        $this->tokenStorage = $tokenStorage;
59
        $this->oauth2ResponseFactoryManager = $oauth2ResponseFactoryManager;
60
    }
61
62
    /**
63
     * @param Checker $checker
64
     *
65
     * @return AnnotationDriver
66
     */
67
    public function add(Checker $checker): self
68
    {
69
        $this->checkers[] = $checker;
70
71
        return $this;
72
    }
73
74
    /**
75
     * @return Checker[]
76
     */
77
    public function all(): array
78
    {
79
        return $this->checkers;
80
    }
81
82
    public function onKernelController(FilterControllerEvent $event)
83
    {
84
        if (!is_array($controller = $event->getController())) {
85
            return;
86
        }
87
88
        $object = new \ReflectionObject($controller[0]);
89
        $method = $object->getMethod($controller[1]);
90
        $classConfigurations = $this->reader->getClassAnnotations($object);
91
        $methodConfigurations = $this->reader->getMethodAnnotations($method);
92
93
        foreach (array_merge($classConfigurations, $methodConfigurations) as $configuration) {
94
            if ($configuration instanceof OAuth2) {
95
                $this->processOAuth2Annotation($event, $configuration);
96
            }
97
        }
98
    }
99
100
    /**
101
     * @param FilterControllerEvent $event
102
     *
103
     * @param OAuth2 $configuration
104
     */
105
    private function processOAuth2Annotation(FilterControllerEvent $event, OAuth2 $configuration): void
106
    {
107
        $token = $this->tokenStorage->getToken();
108
109
        if (!$token instanceof OAuth2Token) {
110
            $this->createAuthenticationException($event, 'OAuth2 authentication required', $configuration);
111
112
            return;
113
        }
114
115
        foreach ($this->all() as $checker) {
116
            try {
117
                $checker->check($token, $configuration);
118
            } catch (\Exception $e) {
119
                $this->createAccessDeniedException($event, $e->getMessage(), $configuration, $e);
120
            }
121
        }
122
    }
123
124
    /**
125
     * @param FilterControllerEvent $event
126
     * @param string                $message
127
     * @param OAuth2                $configuration
128
     */
129
    private function createAuthenticationException(FilterControllerEvent $event, string $message, OAuth2 $configuration)
130
    {
131
        $additionalData = $configuration->getScope() ? ['scope' => $configuration->getScope()] : [];
132
        $response = $this->oauth2ResponseFactoryManager->getResponse(
133
            new OAuth2Message(
134
                401,
135
                OAuth2Message::ERROR_ACCESS_DENIED,
136
                $message
137
            ),
138
            $additionalData
139
        );
140
141
        $this->updateFilterControllerEvent($event, $response);
142
    }
143
144
    /**
145
     * @param FilterControllerEvent $event
146
     * @param string $message
147
     * @param OAuth2 $configuration
148
     * @param \Exception $previous
149
     */
150
    private function createAccessDeniedException(FilterControllerEvent $event, string $message, OAuth2 $configuration, \Exception $previous)
151
    {
152
        $additionalData = $configuration->getScope() ? ['scope' => $configuration->getScope()] : [];
153
        $response = $this->oauth2ResponseFactoryManager->getResponse(
154
            new OAuth2Message(
155
            403,
156
            OAuth2Message::ERROR_ACCESS_DENIED,
157
                $message,
158
                $previous
159
            ),
160
            $additionalData
161
        );
162
        $this->updateFilterControllerEvent($event, $response);
163
    }
164
165
    /**
166
     * @param FilterControllerEvent $event
167
     * @param ResponseInterface     $psr7Response
168
     */
169
    private function updateFilterControllerEvent(FilterControllerEvent $event, ResponseInterface $psr7Response)
170
    {
171
        $event->setController(function () use ($psr7Response) {
172
            $factory = new HttpFoundationFactory();
173
            $symfonyResponse = $factory->createResponse($psr7Response);
174
175
            return $symfonyResponse;
176
        });
177
    }
178
}
179