ProviderBuilder   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Test Coverage

Coverage 95.08%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 27
eloc 55
c 1
b 0
f 0
dl 0
loc 269
ccs 58
cts 61
cp 0.9508
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A endPoint() 0 10 3
A oauth2() 0 5 1
A introspectionEndPoint() 0 3 1
A create() 0 15 5
A endPoints() 0 7 2
A addKey() 0 13 4
A authorizationEndPoint() 0 3 1
A revocationEndPoint() 0 3 1
A tokenEndPoint() 0 3 1
A addKeyFile() 0 3 1
A keySet() 0 17 4
A openid() 0 5 1
A option() 0 5 1
A __construct() 0 5 1
1
<?php
2
3
namespace Parroauth2\Client\Provider;
4
5
use InvalidArgumentException;
6
use Jose\Component\Core\JWK;
7
use Jose\Component\Core\JWKSet;
8
use Jose\Component\KeyManagement\JWKFactory;
9
10
/**
11
 * Builder for manual configuration of Provider
12
 *
13
 * @see https://openid.net/specs/openid-connect-discovery-1_0.html
14
 * @see https://tools.ietf.org/html/rfc8414
15
 */
16
final class ProviderBuilder
17
{
18
    /**
19
     * @var ProviderLoader
20
     */
21
    private $loader;
22
23
    /**
24
     * @var ProviderConfigPool
25
     */
26
    private $configPool;
27
28
    /**
29
     * @var string
30
     */
31
    private $url;
32
33
    /**
34
     * @var array<string, mixed>
35
     */
36
    private $config = [];
37
38
    /**
39
     * @var bool
40
     */
41
    private $openid = false;
42
43
44
    /**
45
     * ProviderBuilder constructor.
46
     *
47
     * @param ProviderLoader $loader
48
     * @param ProviderConfigPool $configPool
49
     * @param string $url The base provider URL
50
     *
51
     * @internal Use ProviderLoader::builder() for instantiate the builder
52
     */
53 19
    public function __construct(ProviderLoader $loader, ProviderConfigPool $configPool, string $url)
54
    {
55 19
        $this->loader = $loader;
56 19
        $this->configPool = $configPool;
57 19
        $this->url = $url;
58 19
    }
59
60
    /**
61
     * Configure an endpoint URI
62
     *
63
     * <code>
64
     * $builder
65
     *     ->endPoint('authorization', '/authorize')
66
     *     ->endPoint('token', 'https://op.example.com/token')
67
     * ;
68
     * </code>
69
     *
70
     * @param string $name The endpoint name. Should be in lower case
71
     * @param string $url The endpoint URI. Can be relative or absolute
72
     *
73
     * @return $this
74
     */
75 8
    public function endPoint(string $name, string $url): self
76
    {
77
        // Relative URI : use the base URL
78 8
        if (strpos($url, 'http://') === false && strpos($url, 'https://') === false) {
79 7
            $url = rtrim($this->url, '/') . '/' . ltrim($url, '/');
80
        }
81
82 8
        $this->config[$name . '_endpoint'] = $url;
83
84 8
        return $this;
85
    }
86
87
    /**
88
     * Configure multiple endpoints
89
     *
90
     * <code>
91
     * $builder->endPoints([
92
     *     'authorization' => '/authorize',
93
     *     'token' => 'https://op.example.com/token',
94
     * ]);
95
     * </code>
96
     *
97
     * @param array<string, string> $endPoints Endpoints map, with key as name, and uri as value
98
     *
99
     * @return $this
100
     */
101 1
    public function endPoints(array $endPoints): self
102
    {
103 1
        foreach ($endPoints as $name => $uri) {
104 1
            $this->endPoint($name, $uri);
105
        }
106
107 1
        return $this;
108
    }
109
110
    /**
111
     * Define the authorization endpoint
112
     *
113
     * @param string $uri The endpoint URI. Can be relative or absolute
114
     *
115
     * @return $this
116
     */
117 2
    public function authorizationEndPoint(string $uri): self
118
    {
119 2
        return $this->endPoint('authorization', $uri);
120
    }
121
122
    /**
123
     * Define the token endpoint
124
     *
125
     * @param string $uri The endpoint URI. Can be relative or absolute
126
     *
127
     * @return $this
128
     */
129 1
    public function tokenEndPoint(string $uri): self
130
    {
131 1
        return $this->endPoint('token', $uri);
132
    }
133
134
    /**
135
     * Define the revocation endpoint
136
     *
137
     * @param string $uri The endpoint URI. Can be relative or absolute
138
     *
139
     * @return $this
140
     */
141 1
    public function revocationEndPoint(string $uri): self
142
    {
143 1
        return $this->endPoint('revocation', $uri);
144
    }
145
146
    /**
147
     * Define the introspection endpoint
148
     *
149
     * @param string $uri The endpoint URI. Can be relative or absolute
150
     *
151
     * @return $this
152
     */
153 1
    public function introspectionEndPoint(string $uri): self
154
    {
155 1
        return $this->endPoint('introspection', $uri);
156
    }
157
158
    /**
159
     * Define an option
160
     *
161
     * @param string $name The option name
162
     * @param mixed $value The value
163
     *
164
     * @return $this
165
     *
166
     * @see https://openid.net/specs/openid-connect-discovery-1_0.html The OpenID Connect options
167
     * @see https://tools.ietf.org/html/rfc8414 The OAuth 2.0 options
168
     */
169 1
    public function option(string $name, $value): self
170
    {
171 1
        $this->config[$name] = $value;
172
173 1
        return $this;
174
    }
175
176
    /**
177
     * Define the JWKSet
178
     *
179
     * @param JWK|JWK[]|JWKSet $keys
180
     *
181
     * @return $this
182
     */
183 5
    public function keySet($keys): self
184
    {
185
        switch (true) {
186 5
            case $keys instanceof JWKSet:
187 3
            case is_array($keys):
188 3
                $this->config['jwks'] = $keys;
189 3
                break;
190
191 2
            case $keys instanceof JWK:
192 1
                $this->config['jwks'] = [$keys];
193 1
                break;
194
195
            default:
196 1
                throw new \TypeError('$keys must be of type JWKSet, array or JWK');
197
        }
198
199 4
        return $this;
200
    }
201
202
    /**
203
     * Add a new key to the key set
204
     *
205
     * @param JWK $key
206
     *
207
     * @return $this
208
     */
209 4
    public function addKey(JWK $key): self
210
    {
211 4
        if (empty($this->config['jwks'])) {
212 3
            $this->config['jwks'] = [$key];
213 2
        } elseif (is_array($this->config['jwks'])) {
214 1
            $this->config['jwks'][] = $key;
215 1
        } elseif ($this->config['jwks'] instanceof JWKSet) {
216 1
            $this->config['jwks'] = $this->config['jwks']->with($key);
217
        } else {
218
            $this->config['jwks'] = [$key];
219
        }
220
221 4
        return $this;
222
    }
223
224
    /**
225
     * Add a new RSA key file to the key set
226
     *
227
     * @param string $file The RSA key filename
228
     * @param string|null $password Password of the file
229
     * @param array $additionalValues
230
     *
231
     * @return $this
232
     * @throws \Exception
233
     *
234
     * @see JWKFactory::createFromKeyFile()
235
     */
236 1
    public function addKeyFile(string $file, ?string $password = null, array $additionalValues = []): self
237
    {
238 1
        return $this->addKey(JWKFactory::createFromKeyFile($file, $password, $additionalValues));
239
    }
240
241
    /**
242
     * The provider supports OpenID Connect
243
     *
244
     * @return $this
245
     */
246 2
    public function openid(): self
247
    {
248 2
        $this->openid = true;
249
250 2
        return $this;
251
    }
252
253
    /**
254
     * The provider is a simple OAuth2 server
255
     *
256
     * @return $this
257
     */
258 1
    public function oauth2(): self
259
    {
260 1
        $this->openid = false;
261
262 1
        return $this;
263
    }
264
265
    /**
266
     * Build the provider
267
     *
268
     * @return ProviderInterface
269
     */
270 18
    public function create(): ProviderInterface
271
    {
272 18
        if (isset($this->config['issuer'])) {
273
            $this->config['issuer'] = $this->url;
274
        }
275
276 18
        if (!empty($this->config['jwks'])) {
277 7
            if (is_array($this->config['jwks'])) {
278 5
                $this->config['jwks'] = new JWKSet($this->config['jwks']);
279 2
            } elseif (!$this->config['jwks'] instanceof JWKSet) {
280
                throw new InvalidArgumentException('Invalid jwks option : must be a JWKSet or an array');
281
            }
282
        }
283
284 18
        return $this->loader->create($this->configPool->create($this->url, $this->config, $this->openid));
285
    }
286
}
287