DiscoveryProvider::fetch()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Facile\OpenIDClient\Issuer\Metadata\Provider;
6
7
use function array_key_exists;
8
use Facile\OpenIDClient\Exception\RuntimeException;
9
use function Facile\OpenIDClient\parse_metadata_response;
10
use function preg_match;
11
use Psr\Http\Client\ClientExceptionInterface;
12
use Psr\Http\Client\ClientInterface;
13
use Psr\Http\Message\RequestFactoryInterface;
14
use Psr\Http\Message\UriFactoryInterface;
15
use function rtrim;
16
use function strpos;
17
18
/**
19
 * @psalm-import-type DiscoveryConfigurationObject from DiscoveryProviderInterface
20
 */
21
final class DiscoveryProvider implements DiscoveryProviderInterface
22
{
23
    private const OIDC_DISCOVERY = '/.well-known/openid-configuration';
24
25
    private const OAUTH2_DISCOVERY = '/.well-known/oauth-authorization-server';
26
27
    /** @var ClientInterface */
28
    private $client;
29
30
    /** @var RequestFactoryInterface */
31
    private $requestFactory;
32
33
    /** @var UriFactoryInterface */
34
    private $uriFactory;
35
36 3
    public function __construct(
37
        ClientInterface $client,
38
        RequestFactoryInterface $requestFactory,
39
        UriFactoryInterface $uriFactory
40
    ) {
41 3
        $this->client = $client;
42 3
        $this->requestFactory = $requestFactory;
43 3
        $this->uriFactory = $uriFactory;
44 3
    }
45
46
    public function isAllowedUri(string $uri): bool
47
    {
48
        return (int) preg_match('/https?:\/\//', $uri) > 0;
49
    }
50
51 3
    public function discovery(string $url): array
52
    {
53 3
        $uri = $this->uriFactory->createUri($url);
54 3
        $uriPath = $uri->getPath() ?: '/';
55
56 3
        if (false !== strpos($uriPath, '/.well-known/')) {
57 1
            return $this->fetchOpenIdConfiguration((string) $uri);
58
        }
59
60
        $uris = [
61 2
            $uri->withPath(rtrim($uriPath, '/') . self::OIDC_DISCOVERY),
62 2
            $uri->withPath('/' === $uriPath
63 1
                ? self::OAUTH2_DISCOVERY
64 2
                : rtrim($uriPath, '/') . self::OAUTH2_DISCOVERY),
65
        ];
66
67 2
        foreach ($uris as $wellKnownUri) {
68
            try {
69 2
                return $this->fetchOpenIdConfiguration((string) $wellKnownUri);
70
            } catch (RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
71
            }
72
        }
73
74
        throw new RuntimeException('Unable to fetch provider metadata');
75
    }
76
77
    /**
78
     * @param string $uri
79
     *
80
     * @return array<mixed, string>
81
     * @psalm-return DiscoveryConfigurationObject
82
     */
83 3
    private function fetchOpenIdConfiguration(string $uri): array
84
    {
85 3
        $request = $this->requestFactory->createRequest('GET', $uri)
86 3
            ->withHeader('accept', 'application/json');
87
88
        try {
89
            /** @var DiscoveryConfigurationObject $data */
90 3
            $data = parse_metadata_response($this->client->sendRequest($request));
91
        } catch (ClientExceptionInterface $e) {
92
            throw new RuntimeException('Unable to fetch provider metadata', 0, $e);
93
        }
94
95 3
        if (! array_key_exists('issuer', $data)) {
96
            throw new RuntimeException('Invalid metadata content, no "issuer" key found');
97
        }
98
99 3
        return $data;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $data returns the type Facile\OpenIDClient\Issu...veryConfigurationObject which is incompatible with the type-hinted return array.
Loading history...
100
    }
101
102
    public function fetch(string $uri): array
103
    {
104
        return $this->discovery($uri);
105
    }
106
}
107