@fleetbase/solid-engine 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.php-cs-fixer.php +29 -0
- package/LICENSE.md +21 -0
- package/README.md +222 -0
- package/addon/components/admin/solid-server-config.hbs +19 -0
- package/addon/components/admin/solid-server-config.js +52 -0
- package/addon/components/solid-brand-icon.hbs +9 -0
- package/addon/components/solid-brand-icon.js +13 -0
- package/addon/controllers/application.js +27 -0
- package/addon/engine.js +40 -0
- package/addon/routes/application.js +14 -0
- package/addon/routes.js +3 -0
- package/addon/styles/solid-engine.css +29 -0
- package/addon/templates/application.hbs +15 -0
- package/app/components/admin/solid-server-config.js +1 -0
- package/app/components/solid-brand-icon.js +1 -0
- package/app/controllers/application.js +1 -0
- package/app/routes/application.js +1 -0
- package/composer.json +96 -0
- package/config/environment.js +11 -0
- package/extension.json +8 -0
- package/index.js +26 -0
- package/package.json +134 -0
- package/phpstan.neon.dist +8 -0
- package/phpunit.xml.dist +16 -0
- package/server/config/solid.php +21 -0
- package/server/migrations/2024_04_09_064616_create_solid_identities_table.php +33 -0
- package/server/src/Client/OpenIDConnectClient.php +217 -0
- package/server/src/Client/SolidClient.php +186 -0
- package/server/src/Http/Controllers/OIDCController.php +32 -0
- package/server/src/Http/Controllers/SolidController.php +117 -0
- package/server/src/LegacyClient/Identity/IdentityProvider.php +174 -0
- package/server/src/LegacyClient/Identity/Profile.php +18 -0
- package/server/src/LegacyClient/OIDCClient.php +350 -0
- package/server/src/LegacyClient/Profile/WebID.php +26 -0
- package/server/src/LegacyClient/SolidClient.php +270 -0
- package/server/src/Models/SolidIdentity.php +131 -0
- package/server/src/Providers/SolidServiceProvider.php +62 -0
- package/server/src/Support/Utils.php +9 -0
- package/server/src/routes.php +47 -0
- package/server/tests/Feature.php +5 -0
- package/translations/en-us.yaml +2 -0
- package/tsconfig.declarations.json +10 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\Http\Controllers;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Controllers\Controller as BaseController;
|
|
6
|
+
use Fleetbase\Http\Requests\AdminRequest;
|
|
7
|
+
use Fleetbase\Models\Setting;
|
|
8
|
+
use Fleetbase\Solid\Client\SolidClient;
|
|
9
|
+
use Fleetbase\Solid\Models\SolidIdentity;
|
|
10
|
+
use Fleetbase\Support\Utils;
|
|
11
|
+
use Illuminate\Http\Request;
|
|
12
|
+
|
|
13
|
+
class SolidController extends BaseController
|
|
14
|
+
{
|
|
15
|
+
/**
|
|
16
|
+
* Welcome message only.
|
|
17
|
+
*/
|
|
18
|
+
public function hello()
|
|
19
|
+
{
|
|
20
|
+
return response()->json(
|
|
21
|
+
[
|
|
22
|
+
'message' => 'Fleetbase Solid Extension',
|
|
23
|
+
'version' => config('solid.api.version'),
|
|
24
|
+
]
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public function getServerConfig(AdminRequest $request)
|
|
29
|
+
{
|
|
30
|
+
$defaultConfig = config('solid.server');
|
|
31
|
+
$savedConfig = Setting::system('solid.server');
|
|
32
|
+
$config = array_merge($defaultConfig, $savedConfig);
|
|
33
|
+
|
|
34
|
+
return response()->json($config);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public function saveServerConfig(AdminRequest $request)
|
|
38
|
+
{
|
|
39
|
+
$incomingConfig = $request->array('server');
|
|
40
|
+
$defaultConfig = config('solid.server');
|
|
41
|
+
$config = array_merge($defaultConfig, $incomingConfig);
|
|
42
|
+
Setting::configure('system.solid.server', $config);
|
|
43
|
+
|
|
44
|
+
return response()->json($config);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public function requestAuthentication()
|
|
48
|
+
{
|
|
49
|
+
$solidIdentity = SolidIdentity::initialize();
|
|
50
|
+
$authenticationUrl = Utils::apiUrl('solid/int/v1/authenticate', [], 8000);
|
|
51
|
+
|
|
52
|
+
return response()->json(['authenticationUrl' => $authenticationUrl, 'identifier' => $solidIdentity->identifier]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public function authenticate(string $identifier)
|
|
56
|
+
{
|
|
57
|
+
$identity = SolidIdentity::initialize();
|
|
58
|
+
$oidc = SolidClient::create(['identity' => $identity])->oidc->register(['saveCredentials' => true]);
|
|
59
|
+
|
|
60
|
+
return $oidc->authenticate();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public function getAccountIndex()
|
|
64
|
+
{
|
|
65
|
+
$solidIdentity = SolidIdentity::current();
|
|
66
|
+
$accountResponse = $solidIdentity->request('get', '.account');
|
|
67
|
+
dd($accountResponse->json());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public function play(Request $request)
|
|
71
|
+
{
|
|
72
|
+
$action = $request->input('action');
|
|
73
|
+
$identity = SolidIdentity::first();
|
|
74
|
+
$solid = new SolidClient(['identity' => $identity]);
|
|
75
|
+
|
|
76
|
+
if ($action === 'register_client') {
|
|
77
|
+
$registeredClient = $solid->oidc->register();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if ($action === 'restore') {
|
|
81
|
+
$solid->identity->restoreClientCredentials();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if ($action === 'login') {
|
|
85
|
+
$loginResponse = $solid->post(
|
|
86
|
+
'.account/login/password',
|
|
87
|
+
[
|
|
88
|
+
'email' => 'ron@fleetbase.io',
|
|
89
|
+
'password' => 'Zerina30662!',
|
|
90
|
+
'remember' => true,
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
'withoutAuth' => true,
|
|
94
|
+
'headers' => [
|
|
95
|
+
'Cookie' => '_interaction=TDQMh2DWuC8wZvkEB2n_G; _interaction.sig=3HHA_FUVo7Cw9up2keCJ7IaQJws; _session.legacy=jdxTxnTGmvWx2ECaiwYeP; _session.legacy.sig=EUGYX6DAKtBNQqZN5PGcbIJ-5ac',
|
|
96
|
+
],
|
|
97
|
+
]
|
|
98
|
+
);
|
|
99
|
+
dump($loginResponse->json());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if ($action === 'test') {
|
|
103
|
+
// $solidClient->identity->restoreTokens();
|
|
104
|
+
dump('AccessToken: ' . $solid->identity->getAccessToken());
|
|
105
|
+
dump('IdToken: ' . $solid->identity->getIdToken());
|
|
106
|
+
|
|
107
|
+
$indexResponse = $solid->get('.account', [], ['withoutAuth' => true]);
|
|
108
|
+
dump($indexResponse->json());
|
|
109
|
+
|
|
110
|
+
// $createPodResponse = $solidClient->post('rondon/blog');
|
|
111
|
+
// dump($createPodResponse->json());
|
|
112
|
+
|
|
113
|
+
// $createFileResponse = $solidClient->put('test.txt', ['test'], ['content-type' => 'text/plain']);
|
|
114
|
+
// dump($createFileResponse->json());
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\LegacyClient\Identity;
|
|
4
|
+
|
|
5
|
+
use EasyRdf\Graph;
|
|
6
|
+
use Fleetbase\Solid\Client\OIDCClient;
|
|
7
|
+
use Fleetbase\Solid\Client\SolidClient;
|
|
8
|
+
use Fleetbase\Support\Utils;
|
|
9
|
+
use Jumbojett\OpenIDConnectClientException;
|
|
10
|
+
|
|
11
|
+
class IdentityProvider
|
|
12
|
+
{
|
|
13
|
+
/**
|
|
14
|
+
* The Solid client instance.
|
|
15
|
+
*/
|
|
16
|
+
private SolidClient $solidClient;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The OIDC client instance for handling OpenID Connect authentication.
|
|
20
|
+
*/
|
|
21
|
+
private OIDCClient $oidcClient;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default MIME type for RDF data.
|
|
25
|
+
*/
|
|
26
|
+
private const DEFAULT_MIME_TYPE = 'text/turtle';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* RDF type for LDP Basic Containers.
|
|
30
|
+
*/
|
|
31
|
+
private const LDP_BASIC_CONTAINER = 'http://www.w3.org/ns/ldp#BasicContainer';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* RDF type for LDP Resources.
|
|
35
|
+
*/
|
|
36
|
+
private const LDP_RESOURCE = 'http://www.w3.org/ns/ldp#Resource';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* RDF property for OIDC issuer.
|
|
40
|
+
*/
|
|
41
|
+
private const OIDC_ISSUER = 'http://www.w3.org/ns/solid/terms#oidcIssuer';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Constructs a new IdentityProvider instance.
|
|
45
|
+
*
|
|
46
|
+
* @param SolidClient $solidClient the Solid client instance
|
|
47
|
+
*/
|
|
48
|
+
public function __construct(SolidClient $solidClient)
|
|
49
|
+
{
|
|
50
|
+
$this->solidClient = $solidClient;
|
|
51
|
+
$this->oidcClient = OIDCClient::create($solidClient);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Gets the OIDC client instance.
|
|
56
|
+
*
|
|
57
|
+
* @return OIDCClient the OIDC client instance
|
|
58
|
+
*/
|
|
59
|
+
public function getOidcClient(): OIDCClient
|
|
60
|
+
{
|
|
61
|
+
if (!$this->oidcClient) {
|
|
62
|
+
return OIDCClient::create($this->solidClient);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return $this->oidcClient;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Magic method to delegate method calls to either IdentityProvider or OIDCClient.
|
|
70
|
+
*
|
|
71
|
+
* @param string $name the name of the method being called
|
|
72
|
+
* @param array $arguments the arguments passed to the method
|
|
73
|
+
*
|
|
74
|
+
* @return mixed the result of the method call
|
|
75
|
+
*/
|
|
76
|
+
public function __call(string $name, $arguments)
|
|
77
|
+
{
|
|
78
|
+
if (method_exists($this, $name)) {
|
|
79
|
+
return $this->{$name}(...$arguments);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (method_exists($this->oidcClient, $name)) {
|
|
83
|
+
return $this->oidcClient->{$name}(...$arguments);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw new \BadMethodCallException("Method {$name} does not exist.");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public function registerClient(array $options = []): self
|
|
90
|
+
{
|
|
91
|
+
// Get registration options
|
|
92
|
+
$clientName = data_get($options, 'clientName', $this->oidcClient::CLIENT_NAME);
|
|
93
|
+
$requestParams = data_get($options, 'requestParams', []);
|
|
94
|
+
$requestOptions = data_get($options, 'requestOptions', []);
|
|
95
|
+
$redirectUri = data_get($options, 'redirectUri');
|
|
96
|
+
if (!$redirectUri) {
|
|
97
|
+
$requestCode = data_get($options, 'requestCode');
|
|
98
|
+
$redirectUri = Utils::apiUrl('solid/int/v1/oidc/complete-registration' . $requestCode ? '/' . $requestCode : '', [], 8000);
|
|
99
|
+
}
|
|
100
|
+
$withResponse = data_get($options, 'withResponse');
|
|
101
|
+
|
|
102
|
+
// Get OIDC Config and Registration URL
|
|
103
|
+
$oidcConfig = $this->solidClient->getOpenIdConfiguration();
|
|
104
|
+
$registrationUrl = data_get($oidcConfig, 'registration_endpoint');
|
|
105
|
+
|
|
106
|
+
// Request registration for Client which should handle authentication
|
|
107
|
+
$response = $this->solidClient->post($registrationUrl, ['client_name' => $clientName, 'redirect_uris' => [$redirectUri], ...$requestParams], ['withoutAuth' => true, ...$requestOptions]);
|
|
108
|
+
if ($response->successful()) {
|
|
109
|
+
$clientCredentials = $response->json();
|
|
110
|
+
$this->setClientCredentials($clientName, $clientCredentials);
|
|
111
|
+
if (is_callable($withResponse)) {
|
|
112
|
+
$withResponse($clientCredentials);
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
throw new OpenIDConnectClientException('Error registering: Please contact the OpenID Connect provider and obtain a Client ID and Secret directly from them');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return $this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public function getClient(array $options = [])
|
|
122
|
+
{
|
|
123
|
+
$clientName = data_get($options, 'clientName', $this->oidcClient::CLIENT_NAME);
|
|
124
|
+
$restoredClient = $this->restoreClientCredentials($clientName);
|
|
125
|
+
if ($restoredClient === null) {
|
|
126
|
+
return $this->registerClient($options);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return $restoredClient;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Retrieves the WebID profile of a user as an RDF graph.
|
|
134
|
+
*
|
|
135
|
+
* @param string $webId the WebID of the user
|
|
136
|
+
* @param array $options additional options for the request
|
|
137
|
+
*
|
|
138
|
+
* @return Graph the user's WebID profile as an RDF graph
|
|
139
|
+
*/
|
|
140
|
+
public function getWebIdProfile(string $webId, array $options = []): Graph
|
|
141
|
+
{
|
|
142
|
+
$response = $this->solidClient->get($webId, $options);
|
|
143
|
+
$format = $response->header('Content-Type');
|
|
144
|
+
|
|
145
|
+
if ($format) {
|
|
146
|
+
// strip parameters (such as charset) if any
|
|
147
|
+
$format = explode(';', $format, 2)[0];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return new Graph($webId, $response->getContent(), $format);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Retrieves the OIDC issuer URL from a WebID profile.
|
|
155
|
+
*
|
|
156
|
+
* @param string $webId the WebID of the user
|
|
157
|
+
* @param array $options additional options for the request
|
|
158
|
+
*
|
|
159
|
+
* @return string the OIDC issuer URL
|
|
160
|
+
*
|
|
161
|
+
* @throws \Exception if the OIDC issuer cannot be found
|
|
162
|
+
*/
|
|
163
|
+
public function getOidcIssuer(string $webId, array $options = []): string
|
|
164
|
+
{
|
|
165
|
+
$graph = $this->getWebIdProfile($webId, $options);
|
|
166
|
+
$issuer = $graph->get($webId, sprintf('<%s>', self::OIDC_ISSUER))->getUri();
|
|
167
|
+
|
|
168
|
+
if (!\is_string($issuer)) {
|
|
169
|
+
throw new \Exception('Unable to find the OIDC issuer associated with this WebID', 1);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return $issuer;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\LegacyClient\Identity;
|
|
4
|
+
|
|
5
|
+
use EasyRdf\Graph;
|
|
6
|
+
|
|
7
|
+
class Profile
|
|
8
|
+
{
|
|
9
|
+
private Graph $graph;
|
|
10
|
+
public string $webId;
|
|
11
|
+
public string $name;
|
|
12
|
+
public string $email;
|
|
13
|
+
|
|
14
|
+
public function __construct(Graph $graph)
|
|
15
|
+
{
|
|
16
|
+
$this->graph = $graph;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\LegacyClient;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Support\Utils;
|
|
6
|
+
use Illuminate\Support\Facades\Redis;
|
|
7
|
+
use IlluminateAgnostic\Str\Support\Str;
|
|
8
|
+
use Jose\Component\Checker\AlgorithmChecker;
|
|
9
|
+
use Jose\Component\Checker\HeaderCheckerManager;
|
|
10
|
+
use Jose\Component\Core\AlgorithmManager;
|
|
11
|
+
use Jose\Component\Core\JWK;
|
|
12
|
+
use Jose\Component\Core\JWKSet;
|
|
13
|
+
use Jose\Component\KeyManagement\JWKFactory;
|
|
14
|
+
use Jose\Component\Signature\Algorithm\ES256;
|
|
15
|
+
use Jose\Component\Signature\Algorithm\ES384;
|
|
16
|
+
use Jose\Component\Signature\Algorithm\ES512;
|
|
17
|
+
use Jose\Component\Signature\Algorithm\HS256;
|
|
18
|
+
use Jose\Component\Signature\Algorithm\HS384;
|
|
19
|
+
use Jose\Component\Signature\Algorithm\HS512;
|
|
20
|
+
use Jose\Component\Signature\Algorithm\RS256;
|
|
21
|
+
use Jose\Component\Signature\Algorithm\RS384;
|
|
22
|
+
use Jose\Component\Signature\Algorithm\RS512;
|
|
23
|
+
use Jose\Component\Signature\JWS;
|
|
24
|
+
use Jose\Component\Signature\JWSBuilder;
|
|
25
|
+
use Jose\Component\Signature\JWSTokenSupport;
|
|
26
|
+
use Jose\Component\Signature\JWSVerifier;
|
|
27
|
+
use Jose\Component\Signature\Serializer\CompactSerializer;
|
|
28
|
+
use Jose\Component\Signature\Serializer\JWSSerializerManager;
|
|
29
|
+
use Jumbojett\OpenIDConnectClient;
|
|
30
|
+
use Jumbojett\OpenIDConnectClientException;
|
|
31
|
+
|
|
32
|
+
final class OIDCClient extends OpenIDConnectClient
|
|
33
|
+
{
|
|
34
|
+
public const CLIENT_NAME = 'Fleetbase';
|
|
35
|
+
private ?JWK $dpopPrivateKey = null;
|
|
36
|
+
private ?string $redirectURL = null;
|
|
37
|
+
protected $refreshToken;
|
|
38
|
+
protected $idToken;
|
|
39
|
+
protected $tokenResponse;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param $provider_url string optional
|
|
43
|
+
* @param $client_id string optional
|
|
44
|
+
* @param $client_secret string optional
|
|
45
|
+
* @param null $issuer
|
|
46
|
+
*/
|
|
47
|
+
public function __construct($provider_url = null, $client_id = null, $client_secret = null, $issuer = null)
|
|
48
|
+
{
|
|
49
|
+
$this->setProviderURL($provider_url);
|
|
50
|
+
if ($issuer === null) {
|
|
51
|
+
$this->setIssuer($provider_url);
|
|
52
|
+
} else {
|
|
53
|
+
$this->setIssuer($issuer);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// $this->setDefaultRedirectURL();
|
|
57
|
+
$this->setCodeChallengeMethod('S256');
|
|
58
|
+
$this->setClientID($client_id);
|
|
59
|
+
$this->setClientSecret($client_secret);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public static function create(SolidClient $solidClient): self
|
|
63
|
+
{
|
|
64
|
+
$oidcConfig = $solidClient->getOpenIdConfiguration();
|
|
65
|
+
$oidcClient = new self(data_get($oidcConfig, 'issuer'));
|
|
66
|
+
$oidcClient->providerConfigParam($oidcConfig);
|
|
67
|
+
|
|
68
|
+
return $oidcClient;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public function authenticate(): bool
|
|
72
|
+
{
|
|
73
|
+
$this->setCodeChallengeMethod('S256');
|
|
74
|
+
$this->addScope(['openid', 'webid', 'offline_access']);
|
|
75
|
+
|
|
76
|
+
return parent::authenticate();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public function setClientCredentials(string $clientName = self::CLIENT_NAME, $clientCredentials): ?self
|
|
80
|
+
{
|
|
81
|
+
$clientId = data_get($clientCredentials, 'client_id');
|
|
82
|
+
$clientSecret = data_get($clientCredentials, 'client_secret');
|
|
83
|
+
|
|
84
|
+
$this->setClientName($clientName);
|
|
85
|
+
$this->setClientID($clientId);
|
|
86
|
+
$this->setClientSecret($clientSecret);
|
|
87
|
+
$this->storeClientCredentials($clientName, $clientCredentials);
|
|
88
|
+
|
|
89
|
+
return $this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private function storeClientCredentials(?string $clientName = self::CLIENT_NAME, $clientCredentials): void
|
|
93
|
+
{
|
|
94
|
+
Redis::set('oidc:client:' . Str::slug($clientName), json_encode($clientCredentials));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public function getClientCredentials(string $clientName = self::CLIENT_NAME)
|
|
98
|
+
{
|
|
99
|
+
$clientCredentialsString = Redis::get('oidc:client:' . Str::slug($clientName));
|
|
100
|
+
if (Utils::isJson($clientCredentialsString)) {
|
|
101
|
+
return json_decode($clientCredentialsString, false);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public function restoreClientCredentials(string $clientName = self::CLIENT_NAME): ?self
|
|
108
|
+
{
|
|
109
|
+
$clientCredentials = $this->getClientCredentials($clientName);
|
|
110
|
+
if ($clientCredentials) {
|
|
111
|
+
return $this->setClientCredentials($clientName, $clientCredentials);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public function verifyJWTsignature($jwt): bool
|
|
118
|
+
{
|
|
119
|
+
$this->decodeToken($jwt);
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public function requestTokens($code, $headers = [])
|
|
125
|
+
{
|
|
126
|
+
$headers[] = 'DPoP: ' . $this->createDPoP('POST', $this->getProviderConfigValue('token_endpoint'), false);
|
|
127
|
+
|
|
128
|
+
return parent::requestTokens($code, $headers);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// https://base64.guru/developers/php/examples/base64url
|
|
132
|
+
private function base64urlEncode(string $data): string
|
|
133
|
+
{
|
|
134
|
+
// First of all you should encode $data to Base64 string
|
|
135
|
+
$b64 = base64_encode($data);
|
|
136
|
+
|
|
137
|
+
// Convert Base64 to Base64URL by replacing “+” with “-” and “/” with “_”
|
|
138
|
+
$url = strtr($b64, '+/', '-_');
|
|
139
|
+
|
|
140
|
+
// Remove padding character from the end of line and return the Base64URL result
|
|
141
|
+
return rtrim($url, '=');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public function createDPoP(string $method, string $url, bool $includeAth = true, string $accessToken = null): string
|
|
145
|
+
{
|
|
146
|
+
if (null === $this->dpopPrivateKey) {
|
|
147
|
+
$this->dpopPrivateKey = JWKFactory::createECKey('P-256', ['use' => 'sig', 'kid' => base64_encode(random_bytes(20))]);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
$jwsBuilder = new JWSBuilder(new AlgorithmManager([new ES256()]));
|
|
151
|
+
|
|
152
|
+
$arrayPayload = [
|
|
153
|
+
'htu' => strtok($url, '?'),
|
|
154
|
+
'htm' => $method,
|
|
155
|
+
'jti' => base64_encode(random_bytes(20)),
|
|
156
|
+
'iat' => time(),
|
|
157
|
+
];
|
|
158
|
+
if ($includeAth) {
|
|
159
|
+
if (!$accessToken) {
|
|
160
|
+
$accessToken = $this->getAccessToken();
|
|
161
|
+
}
|
|
162
|
+
$arrayPayload['ath'] = $this->base64urlEncode(hash('sha256', $accessToken));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
$payload = json_encode($arrayPayload, \JSON_THROW_ON_ERROR);
|
|
166
|
+
|
|
167
|
+
$jws = $jwsBuilder
|
|
168
|
+
->create()
|
|
169
|
+
->withPayload($payload)
|
|
170
|
+
->addSignature(
|
|
171
|
+
$this->dpopPrivateKey,
|
|
172
|
+
[
|
|
173
|
+
'alg' => 'ES256',
|
|
174
|
+
'typ' => 'dpop+jwt',
|
|
175
|
+
'jwk' => $this->dpopPrivateKey->toPublic()->jsonSerialize(),
|
|
176
|
+
]
|
|
177
|
+
)
|
|
178
|
+
->build();
|
|
179
|
+
|
|
180
|
+
return (new CompactSerializer())->serialize($jws, 0);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public function decodeToken(string $jwt): JWS
|
|
184
|
+
{
|
|
185
|
+
try {
|
|
186
|
+
$jwks = JWKSet::createFromJson($this->fetchURL($this->getProviderConfigValue('jwks_uri')));
|
|
187
|
+
} catch (\Exception $e) {
|
|
188
|
+
throw new OpenIDConnectClientException('Invalid JWKS: ' . $e->getMessage(), $e->getCode(), $e);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
$headerCheckerManager = new HeaderCheckerManager(
|
|
192
|
+
[new AlgorithmChecker(['RS256', 'RS384', 'R512', 'HS256', 'HS384', 'HS512', 'ES256', 'ES384', 'ES512'])], // TODO: read this from the provider config
|
|
193
|
+
[new JWSTokenSupport()],
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
$algorithmManager = new AlgorithmManager([
|
|
197
|
+
new RS256(),
|
|
198
|
+
new RS384(),
|
|
199
|
+
new RS512(),
|
|
200
|
+
new HS256(),
|
|
201
|
+
new HS384(),
|
|
202
|
+
new HS512(),
|
|
203
|
+
new ES256(),
|
|
204
|
+
new ES384(),
|
|
205
|
+
new ES512(),
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
$serializerManager = new JWSSerializerManager([new CompactSerializer()]);
|
|
209
|
+
$jws = $serializerManager->unserialize($jwt);
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
$headerCheckerManager->check($jws, 0);
|
|
213
|
+
} catch (\Exception $e) {
|
|
214
|
+
throw new OpenIDConnectClientException('Invalid JWT header: ' . $e->getMessage(), $e->getCode(), $e);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
$jwsVerifier = new JWSVerifier($algorithmManager);
|
|
218
|
+
if (!$jwsVerifier->verifyWithKeySet($jws, $jwks, 0)) {
|
|
219
|
+
throw new OpenIDConnectClientException('Invalid JWT signature.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return $jws;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public function getRedirectURL()
|
|
226
|
+
{
|
|
227
|
+
// If the redirect URL has been set then return it.
|
|
228
|
+
if (property_exists($this, 'redirectURL') && $this->redirectURL) {
|
|
229
|
+
return $this->redirectURL;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// // Get current solid identity
|
|
233
|
+
// $solidIdentity = SolidIdentity::current();
|
|
234
|
+
// return Utils::apiUrl('solid/int/v1/oidc/complete-registration/' . $solidIdentity->request_code, [], 8000);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
public function setDefaultRedirectURL(string $redirectURL)
|
|
238
|
+
{
|
|
239
|
+
$this->setRedirectURL($redirectURL);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public function setAccessToken($accessToken)
|
|
243
|
+
{
|
|
244
|
+
$this->accessToken = $accessToken;
|
|
245
|
+
Redis::set('oidc:client:access_token', $accessToken);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
public function setIdToken($idToken)
|
|
249
|
+
{
|
|
250
|
+
$this->idToken = $idToken;
|
|
251
|
+
Redis::set('oidc:client:id_token', $idToken);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public function setRefreshToken($refreshToken)
|
|
255
|
+
{
|
|
256
|
+
$this->refreshToken = $refreshToken;
|
|
257
|
+
Redis::set('oidc:client:refresh_token', $refreshToken);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public function setTokenResponse($tokenResponse)
|
|
261
|
+
{
|
|
262
|
+
$this->tokenResponse = $tokenResponse;
|
|
263
|
+
Redis::set('oidc:client:token_response', json_encode($tokenResponse));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public function storeTokens()
|
|
267
|
+
{
|
|
268
|
+
$idToken = $this->getIdToken();
|
|
269
|
+
if ($idToken) {
|
|
270
|
+
Redis::set('oidc:client:id_token', $idToken);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
$accessToken = $this->getAccessToken();
|
|
274
|
+
if ($accessToken) {
|
|
275
|
+
Redis::set('oidc:client:access_token', $accessToken);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
$refreshToken = $this->getRefreshToken();
|
|
279
|
+
if ($refreshToken) {
|
|
280
|
+
Redis::set('oidc:client:refresh_token', $refreshToken);
|
|
281
|
+
}
|
|
282
|
+
$tokenResponse = $this->getTokenResponse();
|
|
283
|
+
if ($tokenResponse) {
|
|
284
|
+
Redis::set('oidc:client:token_response', json_encode($tokenResponse));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return $this;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public function getAccessToken(): ?string
|
|
291
|
+
{
|
|
292
|
+
$accessToken = parent::getAccessToken();
|
|
293
|
+
if (!$accessToken) {
|
|
294
|
+
$accessToken = Redis::get('oidc:client:access_token');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return $accessToken;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
public function getRefreshToken(): ?string
|
|
301
|
+
{
|
|
302
|
+
$refreshToken = parent::getRefreshToken();
|
|
303
|
+
if (!$refreshToken) {
|
|
304
|
+
$refreshToken = Redis::get('oidc:client:refresh_token');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return $refreshToken;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public function getIdToken()
|
|
311
|
+
{
|
|
312
|
+
$idToken = parent::getIdToken();
|
|
313
|
+
if (!$idToken) {
|
|
314
|
+
$idToken = Redis::get('oidc:client:id_token');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return $idToken;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
public function getTokenResponse()
|
|
321
|
+
{
|
|
322
|
+
$tokenResponse = parent::getTokenResponse();
|
|
323
|
+
if (!$tokenResponse) {
|
|
324
|
+
$tokenResponse = Redis::get('oidc:client:token_response');
|
|
325
|
+
if (is_string($tokenResponse)) {
|
|
326
|
+
$tokenResponse = json_decode($tokenResponse);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return $tokenResponse;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public function restoreTokens()
|
|
334
|
+
{
|
|
335
|
+
$idToken = Redis::get('oidc:client:id_token');
|
|
336
|
+
$accessToken = Redis::get('oidc:client:access_token');
|
|
337
|
+
$refreshToken = Redis::get('oidc:client:refresh_token');
|
|
338
|
+
$tokenResponse = Redis::get('oidc:client:token_response');
|
|
339
|
+
|
|
340
|
+
$this->setIdToken($idToken);
|
|
341
|
+
$this->setAccessToken($accessToken);
|
|
342
|
+
$this->setRefreshToken($refreshToken);
|
|
343
|
+
$this->setTokenResponse($tokenResponse);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
public function clearStoredClient(?string $clientName = self::CLIENT_NAME)
|
|
347
|
+
{
|
|
348
|
+
Redis::del('oidc:client:' . Str::slug($clientName));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\LegacyClient\Profile;
|
|
4
|
+
|
|
5
|
+
class WebID
|
|
6
|
+
{
|
|
7
|
+
protected function getAltProfileUrlAllFrom(string $webId, string $webIdProfile): array
|
|
8
|
+
{
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
protected function getProfileAll(string $webId, array $options = [])
|
|
12
|
+
{
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected function getPodUrlAll(string $webId, array $options = [])
|
|
16
|
+
{
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected function getPodUrlAllFrom(array $profiles, string $webId)
|
|
20
|
+
{
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected function getWebIdDataset(string $webId)
|
|
24
|
+
{
|
|
25
|
+
}
|
|
26
|
+
}
|