Failed Conditions
Pull Request — master (#63)
by Florent
07:25 queued 04:17
created

TokenIntrospectionEndpoint::process()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 40
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 26
nc 7
nop 2
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\Component\Server\Endpoint\TokenIntrospection;
15
16
use Http\Message\MessageFactory;
17
use Interop\Http\Server\RequestHandlerInterface;
18
use Interop\Http\Server\MiddlewareInterface;
19
use OAuth2Framework\Component\Server\Model\ResourceServer\ResourceServerInterface;
20
use OAuth2Framework\Component\Server\Response\OAuth2Exception;
21
use OAuth2Framework\Component\Server\Response\OAuth2ResponseFactoryManager;
22
use OAuth2Framework\Component\Server\TokenTypeHint\TokenTypeHintInterface;
23
use OAuth2Framework\Component\Server\TokenTypeHint\TokenTypeHintManager;
24
use Psr\Http\Message\ServerRequestInterface;
25
26
final class TokenIntrospectionEndpoint implements MiddlewareInterface
27
{
28
    /**
29
     * @var TokenTypeHintManager
30
     */
31
    private $tokenTypeHintManager;
32
33
    /**
34
     * @var MessageFactory
35
     */
36
    private $messageFactory;
37
38
    /**
39
     * TokenIntrospectionEndpoint constructor.
40
     *
41
     * @param TokenTypeHintManager $tokenTypeHintManager
42
     * @param MessageFactory       $messageFactory
43
     */
44
    public function __construct(TokenTypeHintManager $tokenTypeHintManager, MessageFactory $messageFactory)
45
    {
46
        $this->tokenTypeHintManager = $tokenTypeHintManager;
47
        $this->messageFactory = $messageFactory;
48
    }
49
50
    /**
51
     * @return TokenTypeHintManager
52
     */
53
    protected function getTokenTypeHintManager(): TokenTypeHintManager
54
    {
55
        return $this->tokenTypeHintManager;
56
    }
57
58
    /**
59
     * @param string $tokenTypeHint
60
     *
61
     * @throws OAuth2Exception
62
     *
63
     * @return TokenTypeHintInterface[]
64
     */
65
    protected function getTokenTypeHint(string $tokenTypeHint): array
66
    {
67
        $tokenTypeHints = $this->getTokenTypeHintManager()->getTokenTypeHints();
68
        if (!array_key_exists($tokenTypeHint, $tokenTypeHints)) {
69
            throw new OAuth2Exception(
70
                400,
71
                [
72
                    'error' => 'unsupported_token_type',
73
                    'error_description' => sprintf('The token type hint \'%s\' is not supported. Please use one of the following values: %s.', $tokenTypeHint, implode(', ', array_keys($tokenTypeHints))),
74
                ]
75
            );
76
        }
77
78
        $key = array_search($tokenTypeHint, $tokenTypeHints);
79
        unset($tokenTypeHints[$key]);
80
        array_unshift($tokenTypeHints, $tokenTypeHint);
81
82
        return $tokenTypeHints;
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function process(ServerRequestInterface $request, RequestHandlerInterface $requestHandler)
89
    {
90
        $resourceServer = $this->getResourceServer($request);
91
        $token = $this->getToken($request);
92
        $hints = $this->getTokenTypeHints($request);
93
94
        foreach ($hints as $hint) {
95
            $result = $hint->find($token);
96
            if (null !== $result) {
97
                if (null === $result->getResourceServerId() || $result->getResourceServerId()->getValue() === $resourceServer->getResourceServerId()->getValue()) {
98
                    $data = $hint->introspect($result);
99
                    $response = $this->messageFactory->createResponse();
100
                    $response->getBody()->write(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
101
                    $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate, private', 'Pragma' => 'no-cache'];
102
                    foreach ($headers as $k => $v) {
103
                        $response = $response->withHeader($k, $v);
104
                    }
105
106
                    return $response;
107
                } else {
108
                    throw new OAuth2Exception(
109
                        400,
110
                        [
111
                            'error' => OAuth2ResponseFactoryManager::ERROR_INVALID_REQUEST,
112
                            'error_description' => 'The parameter \'token\' is invalid.',
113
                        ]
114
                    );
115
                }
116
            }
117
        }
118
119
        $response = $this->messageFactory->createResponse();
120
        $response->getBody()->write(json_encode(['active' => false], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
121
        $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate, private', 'Pragma' => 'no-cache'];
122
        foreach ($headers as $k => $v) {
123
            $response = $response->withHeader($k, $v);
124
        }
125
126
        return $response;
127
    }
128
129
    /**
130
     * @param ServerRequestInterface $request
131
     *
132
     * @throws OAuth2Exception
133
     *
134
     * @return ResourceServerInterface
135
     */
136
    private function getResourceServer(ServerRequestInterface $request): ResourceServerInterface
137
    {
138
        $resourceServer = $request->getAttribute('resource_server');
139
        if (null === $resourceServer) {
140
            throw new OAuth2Exception(
141
                401,
142
                [
143
                    'error' => OAuth2ResponseFactoryManager::ERROR_INVALID_RESOURCE_SERVER,
144
                    'error_description' => 'Resource Server authentication failed.',
145
                ]
146
            );
147
        }
148
149
        return $resourceServer;
150
    }
151
152
    /**
153
     * @param ServerRequestInterface $request
154
     *
155
     * @throws OAuth2Exception
156
     *
157
     * @return string
158
     */
159
    protected function getToken(ServerRequestInterface $request): string
160
    {
161
        $params = $this->getRequestParameters($request);
162
        if (!array_key_exists('token', $params)) {
163
            throw new OAuth2Exception(
164
                400,
165
                [
166
                    'error' => OAuth2ResponseFactoryManager::ERROR_INVALID_REQUEST,
167
                    'error_description' => 'The parameter \'token\' is missing.',
168
                ]
169
            );
170
        }
171
172
        return $params['token'];
173
    }
174
175
    /**
176
     * @param ServerRequestInterface $request
177
     *
178
     * @throws OAuth2Exception
179
     *
180
     * @return TokenTypeHintInterface[]
181
     */
182
    protected function getTokenTypeHints(ServerRequestInterface $request): array
183
    {
184
        $params = $this->getRequestParameters($request);
185
        $tokenTypeHints = $this->getTokenTypeHintManager()->getTokenTypeHints();
186
187
        if (array_key_exists('token_type_hint', $params)) {
188
            $tokenTypeHint = $params['token_type_hint'];
189
            if (!array_key_exists($params['token_type_hint'], $tokenTypeHints)) {
190
                throw new OAuth2Exception(
191
                    400,
192
                    [
193
                        'error' => 'unsupported_token_type',
194
                        'error_description' => sprintf('The token type hint \'%s\' is not supported. Please use one of the following values: %s.', $params['token_type_hint'], implode(', ', array_keys($tokenTypeHints))),
195
                    ]
196
                );
197
            }
198
199
            $hint = $tokenTypeHints[$tokenTypeHint];
200
            unset($tokenTypeHints[$tokenTypeHint]);
201
            $tokenTypeHints = [$tokenTypeHint => $hint] + $tokenTypeHints;
202
        }
203
204
        return $tokenTypeHints;
205
    }
206
207
    /**
208
     * @param ServerRequestInterface $request
209
     *
210
     * @return array
211
     */
212
    protected function getRequestParameters(ServerRequestInterface $request): array
213
    {
214
        $parameters = $request->getParsedBody() ?? [];
215
216
        return array_intersect_key($parameters, array_flip(['token', 'token_type_hint']));
217
    }
218
}
219