Failed Conditions
Push — ng ( 17df75...6face8 )
by Florent
04:09
created

IssuerDiscoveryEndpoint::getResourceId()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
cc 5
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\Component\IssuerDiscoveryEndpoint;
15
16
use Http\Message\ResponseFactory;
17
use OAuth2Framework\Component\IssuerDiscoveryEndpoint\IdentifierResolver\IdentifierResolverManager;
18
use Psr\Http\Server\RequestHandlerInterface;
19
use Psr\Http\Server\MiddlewareInterface;
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
23
class IssuerDiscoveryEndpoint implements MiddlewareInterface
24
{
25
    private const REL_NAME = 'http://openid.net/specs/connect/1.0/issuer';
26
27
    /**
28
     * @var ResourceRepository
29
     */
30
    private $resourceManager;
31
32
    /**
33
     * @var ResponseFactory
34
     */
35
    private $responseFactory;
36
37
    /**
38
     * @var IdentifierResolverManager
39
     */
40
    private $identifierResolverManager;
41
42
    /**
43
     * @var string
44
     */
45
    private $domain;
46
47
    /**
48
     * @var int
49
     */
50
    private $port;
51
52
    /**
53
     * IssuerDiscoveryEndpoint constructor.
54
     *
55
     * @param ResourceRepository        $resourceManager
56
     * @param ResponseFactory           $responseFactory
57
     * @param IdentifierResolverManager $identifierResolverManager
58
     * @param string                    $domain
59
     * @param int                       $port
60
     */
61
    public function __construct(ResourceRepository $resourceManager, ResponseFactory $responseFactory, IdentifierResolverManager $identifierResolverManager, string $domain, int $port)
62
    {
63
        $this->resourceManager = $resourceManager;
64
        $this->responseFactory = $responseFactory;
65
        $this->identifierResolverManager = $identifierResolverManager;
66
        $this->domain = $domain;
67
        $this->port = $port;
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
74
    {
75
        try {
76
            $this->checkRel($request);
77
            $resourceName = $this->getResourceName($request);
78
            $resourceId = $this->getResourceId($resourceName);
79
            $resource = $this->resourceManager->find($resourceId);
80
            if (null === $resource) {
81
                throw new \InvalidArgumentException(sprintf('The resource identified with "%s" does not exist or is not supported by this server.', $resourceName), 400);
82
            }
83
            $data = $this->getResourceData($resourceName, $resource);
84
            $response = $this->responseFactory->createResponse(200);
85
            $headers = [
86
                'Content-Type' => 'application/jrd+json; charset=UTF-8',
87
            ];
88
            $response->getBody()->write(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
89
        } catch (\InvalidArgumentException $e) {
90
            $response = $this->responseFactory->createResponse($e->getCode());
91
            $headers = [
92
                'Content-Type' => 'application/json; charset=UTF-8',
93
            ];
94
            $response->getBody()->write(json_encode(['error' => 'invalid_request', 'error_description' => $e->getMessage()], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
95
        }
96
        $headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate, private';
97
        $headers['Pragma'] = 'no-cache';
98
        foreach ($headers as $k => $v) {
99
            $response = $response->withHeader($k, $v);
100
        }
101
102
        return $response;
103
    }
104
105
    /**
106
     * @param string         $resourceName
107
     * @param ResourceObject $resource
108
     *
109
     * @return array
110
     */
111
    private function getResourceData(string $resourceName, ResourceObject $resource): array
112
    {
113
        return [
114
            'subject' => $resourceName,
115
            'links' => [
116
                [
117
                    'rel' => self::REL_NAME,
118
                    'href' => $resource->getIssuer(),
119
                ],
120
            ],
121
        ];
122
    }
123
124
    /**
125
     * @param ServerRequestInterface $request
126
     *
127
     * @throws \InvalidArgumentException
128
     */
129
    private function checkRel(ServerRequestInterface $request)
130
    {
131
        $query_params = $request->getQueryParams() ?? [];
132
        if (!array_key_exists('rel', $query_params)) {
133
            throw new \InvalidArgumentException('The parameter "rel" is mandatory.', 400);
134
        }
135
        if (self::REL_NAME !== $query_params['rel']) {
136
            throw new \InvalidArgumentException('Unsupported "rel" parameter value.', 400);
137
        }
138
    }
139
140
    /**
141
     * @param string $resourceName
142
     *
143
     * @throws \InvalidArgumentException
144
     *
145
     * @return ResourceId
146
     */
147
    private function getResourceId(string $resourceName): ResourceId
148
    {
149
        try {
150
            $identifier = $this->identifierResolverManager->resolve($resourceName);
151
        } catch (\Exception $e) {
152
            throw new \InvalidArgumentException(sprintf('The resource identified with "%s" does not exist or is not supported by this server.', $resourceName), 400, $e);
153
        }
154
        if ($this->domain !== $identifier->getDomain()) {
155
            throw new \InvalidArgumentException(sprintf('The resource identified with "%s" does not exist or is not supported by this server.', $resourceName), 400);
156
        }
157
        if ($identifier->getPort() !== null && $this->port !== $identifier->getPort()) {
158
            throw new \InvalidArgumentException(sprintf('The resource identified with "%s" does not exist or is not supported by this server.', $resourceName), 400);
159
        }
160
161
        return ResourceId::create($identifier->getUsername());
162
    }
163
164
    /**
165
     * @param ServerRequestInterface $request
166
     *
167
     * @throws \InvalidArgumentException
168
     *
169
     * @return string
170
     */
171
    private function getResourceName(ServerRequestInterface $request): string
172
    {
173
        $query_params = $request->getQueryParams() ?? [];
174
        if (!array_key_exists('resource', $query_params)) {
175
            throw new \InvalidArgumentException('The parameter "resource" is mandatory.', 400);
176
        }
177
        return $query_params['resource'];
178
    }
179
}
180