Failed Conditions
Push — master ( e0834e...22ddb5 )
by Florent
03:18
created

AnnotationDriver::onKernelController()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 33
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 18
nc 7
nop 1
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 OAuth2Framework\Bundle\Server\Annotation;
15
16
use Doctrine\Common\Annotations\Reader;
17
use OAuth2Framework\Bundle\Server\Annotation\Checker\CheckerInterface;
18
use OAuth2Framework\Bundle\Server\Security\Authentication\Token\OAuth2Token;
19
use OAuth2Framework\Component\Server\Response\OAuth2Exception;
20
use OAuth2Framework\Component\Server\Response\OAuth2ResponseFactoryManager;
21
use OAuth2Framework\Component\Server\TokenType\TokenTypeManager;
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
use Zend\Diactoros\Response;
26
27
final class AnnotationDriver
28
{
29
    /**
30
     * @var Reader
31
     */
32
    private $reader;
33
34
    /**
35
     * @var TokenStorageInterface
36
     */
37
    private $tokenStorage;
38
39
    /**
40
     * @var CheckerInterface[]
41
     */
42
    private $checkers = [];
43
44
    /**
45
     * @var TokenTypeManager
46
     */
47
    private $tokenTypeManager;
48
49
    /**
50
     * AnnotationDriver constructor.
51
     *
52
     * @param Reader                $reader
53
     * @param TokenStorageInterface $tokenStorage
54
     * @param TokenTypeManager      $tokenTypeManager
55
     */
56
    public function __construct(Reader $reader, TokenStorageInterface $tokenStorage, TokenTypeManager $tokenTypeManager)
57
    {
58
        $this->reader = $reader;
59
        $this->tokenStorage = $tokenStorage;
60
        $this->tokenTypeManager = $tokenTypeManager;
61
    }
62
63
    /**
64
     * @param CheckerInterface $checker
65
     *
66
     * @return AnnotationDriver
67
     */
68
    public function addChecker(CheckerInterface $checker): AnnotationDriver
69
    {
70
        $this->checkers[] = $checker;
71
72
        return $this;
73
    }
74
75
    /**
76
     * @return CheckerInterface[]
77
     */
78
    public function getCheckers(): array
79
    {
80
        return $this->checkers;
81
    }
82
83
    public function onKernelController(FilterControllerEvent $event)
84
    {
85
        if (!is_array($controller = $event->getController())) {
86
            return;
87
        }
88
89
        $object = new \ReflectionObject($controller[0]);
90
        $method = $object->getMethod($controller[1]);
91
        $classConfigurations = $this->reader->getClassAnnotations($object);
92
        $methodConfigurations = $this->reader->getMethodAnnotations($method);
93
94
        foreach (array_merge($classConfigurations, $methodConfigurations) as $configuration) {
95
            if ($configuration instanceof OAuth2) {
96
                $token = $this->tokenStorage->getToken();
97
98
                // If no access token is found by the firewall, then returns an authentication error
99
                if (!$token instanceof OAuth2Token) {
100
                    $this->createAuthenticationException($event, 'OAuth2 authentication required');
101
102
                    return;
103
                }
104
105
                foreach ($this->getCheckers() as $checker) {
106
                    $result = $checker->check($token, $configuration);
107
                    if (null !== $result) {
108
                        $this->createAccessDeniedException($event, $result);
109
110
                        return;
111
                    }
112
                }
113
            }
114
        }
115
    }
116
117
    /**
118
     * @param FilterControllerEvent $event
119
     * @param string                $message
120
     */
121
    private function createAuthenticationException(FilterControllerEvent &$event, $message)
122
    {
123
        $schemes = $this->tokenTypeManager->getSchemes();
124
        $exception = new OAuth2Exception(
125
            401,
126
            [
127
                'error' => OAuth2ResponseFactoryManager::ERROR_ACCESS_DENIED,
128
                'error_description' => $message,
129
                'schemes' => $schemes,
130
            ]
131
        );
132
133
        $this->updateFilterControllerEvent($event, $exception);
134
    }
135
136
    /**
137
     * @param FilterControllerEvent $event
138
     * @param string                $message
139
     */
140
    private function createAccessDeniedException(FilterControllerEvent &$event, $message)
141
    {
142
        $exception = new OAuth2Exception(
143
            403,
144
            [
145
                'error' => OAuth2ResponseFactoryManager::ERROR_ACCESS_DENIED,
146
                'error_description' => $message,
147
            ]
148
        );
149
150
        $this->updateFilterControllerEvent($event, $exception);
151
    }
152
153
    /**
154
     * @param FilterControllerEvent $event
155
     * @param OAuth2Exception       $exception
156
     */
157
    private function updateFilterControllerEvent(FilterControllerEvent &$event, OAuth2Exception $exception)
158
    {
159
        $event->setController(function () use ($exception) {
160
            $response = new Response();
161
            //$exception->getHttpResponse($response);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
162
            $response->getBody()->rewind();
163
            $factory = new HttpFoundationFactory();
164
            $response = $factory->createResponse($response);
165
166
            return $response;
167
        });
168
    }
169
}
170