Issues (37)

src/Provider/ProviderLoader.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace Parroauth2\Client\Provider;
4
5
use Http\Client\Common\HttpMethodsClient;
6
use Http\Discovery\Psr17FactoryDiscovery;
7
use Http\Discovery\Psr18ClientDiscovery;
8
use Parroauth2\Client\Factory\BaseClientFactory;
9
use Parroauth2\Client\Factory\ClientFactoryInterface;
10
use Psr\Http\Client\ClientInterface;
11
use Psr\Http\Message\RequestFactoryInterface;
12
use Psr\Http\Message\StreamFactoryInterface;
13
14
/**
15
 * Load authorization providers
16
 *
17
 * <code>
18
 * $loader = new ProviderLoader();
19
 * $provider = $loader->discover('http://example.com');
20
 * $client = $provider->client(...);
21
 * </code>
22
 */
23
final class ProviderLoader
24
{
25
    /**
26
     * List of well-known paths
27
     * The first element is the path, and the second is a boolean for define if the server supports open id connect
28
     *
29
     * @var list<array{0:string, 1:bool}>
0 ignored issues
show
The type Parroauth2\Client\Provider\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
     */
31
    private $wellKnownUris = [
32
        ['openid-configuration', true],
33
        ['oauth-authorization-server', false],
34
    ];
35
36
    /**
37
     * @var ClientFactoryInterface
38
     */
39
    private $clientFactory;
40
41
    /**
42
     * @var ClientInterface
43
     */
44
    private $httpClient;
45
46
    /**
47
     * @var RequestFactoryInterface
48
     */
49
    private $messageFactory;
50
51
    /**
52
     * @var StreamFactoryInterface
53
     */
54
    private $streamFactory;
55
56
    /**
57
     * @var ProviderConfigPool
58
     */
59
    private $configPool;
60
61
62
    /**
63
     * ProviderLoader constructor.
64
     *
65
     * @param ClientFactoryInterface|null $clientFactory
66
     * @param ClientInterface|null $httpClient The HTTP client to use. If null will discover registered clients
67
     * @param RequestFactoryInterface|null $messageFactory The HTTP message factory to use.
68
     *     If null will discover registered factories
69
     * @param StreamFactoryInterface|null $streamFactory The HTTP stream factory to use.
70
     *     If null will discover registered factories
71
     * @param ProviderConfigPool|null $configPool
72
     */
73 182
    public function __construct(ClientFactoryInterface $clientFactory = null, ClientInterface $httpClient = null, RequestFactoryInterface $messageFactory = null, StreamFactoryInterface $streamFactory = null, ProviderConfigPool $configPool = null)
74
    {
75 182
        $this->clientFactory = $clientFactory ?? new BaseClientFactory();
76 182
        $this->httpClient = $httpClient ?? Psr18ClientDiscovery::find();
77 182
        $this->messageFactory = $messageFactory ?? Psr17FactoryDiscovery::findRequestFactory();
78 182
        $this->streamFactory = $streamFactory ?? Psr17FactoryDiscovery::findStreamFactory();
79 182
        $this->configPool = $configPool ?? new ProviderConfigPool();
80 182
    }
81
82
    /**
83
     * Creates the provider using the well known URI for get server metadata
84
     *
85
     * @param string $providerUrl
86
     *
87
     * @return ProviderInterface
88
     *
89
     * @throws \Http\Client\Exception
90
     *
91
     * @see ProviderLoader::lazy() For perform a lazy loading of the metadata
92
     *
93
     * @psalm-suppress InvalidThrow
94
     */
95 89
    public function discover(string $providerUrl): ProviderInterface
96
    {
97 89
        if ($config = $this->configPool->get($providerUrl)) {
98 1
            return $this->create($config);
99
        }
100
101 89
        $client = new HttpMethodsClient($this->httpClient, $this->messageFactory, $this->streamFactory);
102
103 89
        foreach ($this->wellKnownUris as list($uri, $openid)) {
104 89
            $response = $client->get($providerUrl . '/.well-known/' . $uri);
105
106 89
            if ($response->getStatusCode() !== 200) {
107 2
                continue;
108
            }
109
110 88
            $config = $this->configPool->createFromJson($providerUrl, (string) $response->getBody(), $openid);
111 88
            $config->save();
112
113 88
            return $this->create($config);
114
        }
115
116 1
        throw new \InvalidArgumentException('Authorization provider discovery is not supported by the server');
117
    }
118
119
    /**
120
     * Creates the provider using server metadata, but loaded in lazy way
121
     *
122
     * @param string $providerUrl The base provider URL
123
     *
124
     * @return ProviderInterface
125
     *
126
     * @see ProviderLoader::discover() Non-lazy provider creation method
127
     */
128 9
    public function lazy(string $providerUrl): ProviderInterface
129
    {
130 9
        return new ProxyProvider($providerUrl, $this);
131
    }
132
133
    /**
134
     * Creates a provider using a config
135
     * The configuration format must follow the server metadata form
136
     *
137
     * @param array<string, mixed>|ProviderConfig $config The provider configuration
138
     * @param bool|null $openid Does the provider supports openid ?
139
     *
140
     * @return ProviderInterface
141
     *
142
     * @see ProviderLoader::builder() For simple configuration of the provider
143
     *
144
     * @see https://openid.net/specs/openid-connect-discovery-1_0.html The OpenID Connect metadata
145
     * @see https://tools.ietf.org/html/rfc8414 The OAuth 2.0 server metadata
146
     */
147 180
    public function create($config, ?bool $openid = null): ProviderInterface
148
    {
149 180
        if (!$config instanceof ProviderConfig) {
150 75
            $config = $this->configPool->createFromArray($config, $openid);
151
        }
152
153 180
        return new Provider(
154 180
            $this->clientFactory,
155 180
            $this->httpClient,
156 180
            $this->messageFactory,
157 180
            $this->streamFactory,
158
            $config
159
        );
160
    }
161
162
    /**
163
     * Get a provider builder for manual configuration of the provider
164
     *
165
     * <code>
166
     * $provider = $loader->builder('http://op.example.com')
167
     *     ->authorizationEndPoint('/authorize')
168
     *     ->tokenEndPoint('/token')
169
     *     ->addKeyFile('/path/to/rsa.key')
170
     *     ->openid()
171
     *     ->create()
172
     * ;
173
     * </code>
174
     *
175
     * @param string $url The base URL of the provider
176
     *
177
     * @return ProviderBuilder
178
     *
179
     * @see ProviderLoader::create() For creation without builder
180
     */
181 19
    public function builder(string $url): ProviderBuilder
182
    {
183 19
        return new ProviderBuilder($this, $this->configPool, $url);
184
    }
185
}
186