Failed Conditions
Push — master ( be7876...4c7313 )
by Florent
03:22
created

AnnotationDriver   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
eloc 46
c 1
b 0
f 0
dl 0
loc 113
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A add() 0 3 1
A onKernelController() 0 15 4
A all() 0 3 1
A processOAuth2Annotation() 0 15 4
A createAccessDeniedException() 0 14 2
A updateControllerEvent() 0 6 1
A createAuthenticationException() 0 9 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2019 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\SecurityBundle\Annotation;
15
16
use Doctrine\Common\Annotations\Reader;
17
use OAuth2Framework\Component\Core\Message\OAuth2Error;
18
use OAuth2Framework\Component\Core\Message\OAuth2MessageFactoryManager;
19
use OAuth2Framework\SecurityBundle\Annotation\Checker\Checker;
20
use OAuth2Framework\SecurityBundle\Security\Authentication\Token\OAuth2Token;
21
use Psr\Http\Message\ResponseInterface;
22
use ReflectionObject;
23
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
24
use Symfony\Component\HttpFoundation\Response;
25
use Symfony\Component\HttpKernel\Event\ControllerEvent;
26
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
27
use Throwable;
28
29
class AnnotationDriver
30
{
31
    /**
32
     * @var Reader
33
     */
34
    private $reader;
35
36
    /**
37
     * @var TokenStorageInterface
38
     */
39
    private $tokenStorage;
40
41
    /**
42
     * @var Checker[]
43
     */
44
    private $checkers = [];
45
46
    /**
47
     * @var OAuth2MessageFactoryManager
48
     */
49
    private $oauth2ResponseFactoryManager;
50
51
    public function __construct(Reader $reader, TokenStorageInterface $tokenStorage, OAuth2MessageFactoryManager $oauth2ResponseFactoryManager)
52
    {
53
        $this->reader = $reader;
54
        $this->tokenStorage = $tokenStorage;
55
        $this->oauth2ResponseFactoryManager = $oauth2ResponseFactoryManager;
56
    }
57
58
    public function add(Checker $checker): void
59
    {
60
        $this->checkers[] = $checker;
61
    }
62
63
    /**
64
     * @return Checker[]
65
     */
66
    public function all(): array
67
    {
68
        return $this->checkers;
69
    }
70
71
    public function onKernelController(ControllerEvent $event): void
72
    {
73
        $controller = $event->getController();
74
        if (!\is_array($controller)) {
75
            return;
76
        }
77
78
        $object = new ReflectionObject($controller[0]);
79
        $method = $object->getMethod($controller[1]);
80
        $classConfigurations = $this->reader->getClassAnnotations($object);
81
        $methodConfigurations = $this->reader->getMethodAnnotations($method);
82
83
        foreach (array_merge($classConfigurations, $methodConfigurations) as $configuration) {
84
            if ($configuration instanceof OAuth2) {
85
                $this->processOAuth2Annotation($event, $configuration);
86
            }
87
        }
88
    }
89
90
    private function processOAuth2Annotation(ControllerEvent $event, OAuth2 $configuration): void
91
    {
92
        $token = $this->tokenStorage->getToken();
93
94
        if (!$token instanceof OAuth2Token) {
95
            $this->createAuthenticationException($event, 'OAuth2 authentication required', $configuration);
96
97
            return;
98
        }
99
100
        foreach ($this->all() as $checker) {
101
            try {
102
                $checker->check($token, $configuration);
103
            } catch (Throwable $e) {
104
                $this->createAccessDeniedException($event, $e->getMessage(), $configuration, $e);
105
            }
106
        }
107
    }
108
109
    private function createAuthenticationException(ControllerEvent $event, string $message, OAuth2 $configuration): void
110
    {
111
        $additionalData = null !== $configuration->getScope() ? ['scope' => $configuration->getScope()] : [];
112
        $response = $this->oauth2ResponseFactoryManager->getResponse(
113
            OAuth2Error::accessDenied($message),
114
            $additionalData
115
        );
116
117
        $this->updateControllerEvent($event, $response);
118
    }
119
120
    private function createAccessDeniedException(ControllerEvent $event, string $message, OAuth2 $configuration, Throwable $previous): void
121
    {
122
        $additionalData = null !== $configuration->getScope() ? ['scope' => $configuration->getScope()] : [];
123
        $response = $this->oauth2ResponseFactoryManager->getResponse(
124
            new OAuth2Error(
125
                403,
126
                OAuth2Error::ERROR_ACCESS_DENIED,
127
                $message,
128
                [],
129
                $previous
130
            ),
131
            $additionalData
132
        );
133
        $this->updateControllerEvent($event, $response);
134
    }
135
136
    private function updateControllerEvent(ControllerEvent $event, ResponseInterface $psr7Response): void
137
    {
138
        $event->setController(static function () use ($psr7Response): Response {
139
            $factory = new HttpFoundationFactory();
140
141
            return $factory->createResponse($psr7Response);
142
        });
143
    }
144
}
145