@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
package/package.json
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fleetbase/solid-engine",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Solid Protocol Extension to Store and Share Data with Fleetbase",
|
|
5
|
+
"fleetbase": {
|
|
6
|
+
"route": "solid-protocol"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"fleetbase-extension",
|
|
10
|
+
"solid",
|
|
11
|
+
"solid-protocol",
|
|
12
|
+
"decentralized",
|
|
13
|
+
"decentralized-data",
|
|
14
|
+
"fleetbase",
|
|
15
|
+
"fleetbase-pod",
|
|
16
|
+
"rdf",
|
|
17
|
+
"linked-data",
|
|
18
|
+
"ember-addon",
|
|
19
|
+
"ember-engine"
|
|
20
|
+
],
|
|
21
|
+
"repository": "https://github.com/fleetbase/solid",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "Fleetbase Pte Ltd <hello@fleetbase.io>",
|
|
24
|
+
"directories": {
|
|
25
|
+
"app": "app",
|
|
26
|
+
"addon": "addon",
|
|
27
|
+
"tests": "tests"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "ember build --environment=production",
|
|
31
|
+
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
|
32
|
+
"lint:css": "stylelint \"**/*.css\"",
|
|
33
|
+
"lint:css:fix": "concurrently \"npm:lint:css -- --fix\"",
|
|
34
|
+
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
|
35
|
+
"lint:hbs": "ember-template-lint .",
|
|
36
|
+
"lint:hbs:fix": "ember-template-lint . --fix",
|
|
37
|
+
"lint:js": "eslint . --cache",
|
|
38
|
+
"lint:js:fix": "eslint . --fix",
|
|
39
|
+
"start": "ember serve",
|
|
40
|
+
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
|
|
41
|
+
"test:ember": "ember test",
|
|
42
|
+
"test:ember-compatibility": "ember try:each",
|
|
43
|
+
"publish:npm": "npm config set registry https://registry.npmjs.org/ && npm publish",
|
|
44
|
+
"publish:github": "npm config set '@fleetbase:registry' https://npm.pkg.github.com/ && npm publish"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@babel/core": "^7.23.2",
|
|
48
|
+
"@fleetbase/ember-core": "^0.2.8",
|
|
49
|
+
"@fleetbase/ember-ui": "^0.2.12",
|
|
50
|
+
"@fleetbase/fleetops-data": "^0.1.14",
|
|
51
|
+
"@fortawesome/ember-fontawesome": "^0.4.1",
|
|
52
|
+
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
|
53
|
+
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
|
54
|
+
"broccoli-funnel": "^3.0.8",
|
|
55
|
+
"ember-cli-babel": "^8.2.0",
|
|
56
|
+
"ember-cli-htmlbars": "^6.3.0",
|
|
57
|
+
"ember-intl": "6.3.2",
|
|
58
|
+
"ember-radio-button": "^3.0.0-beta.1",
|
|
59
|
+
"ember-wormhole": "^0.6.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@babel/eslint-parser": "^7.22.15",
|
|
63
|
+
"@babel/plugin-proposal-decorators": "^7.23.2",
|
|
64
|
+
"@ember/optional-features": "^2.0.0",
|
|
65
|
+
"@ember/test-helpers": "^3.2.0",
|
|
66
|
+
"@embroider/test-setup": "^3.0.2",
|
|
67
|
+
"@glimmer/component": "^1.1.2",
|
|
68
|
+
"@glimmer/tracking": "^1.1.2",
|
|
69
|
+
"broccoli-asset-rev": "^3.0.0",
|
|
70
|
+
"concurrently": "^8.2.2",
|
|
71
|
+
"ember-auto-import": "^2.6.3",
|
|
72
|
+
"ember-cli": "~5.4.1",
|
|
73
|
+
"ember-cli-clean-css": "^3.0.0",
|
|
74
|
+
"ember-cli-dependency-checker": "^3.3.2",
|
|
75
|
+
"ember-cli-inject-live-reload": "^2.1.0",
|
|
76
|
+
"ember-cli-sri": "^2.1.1",
|
|
77
|
+
"ember-cli-terser": "^4.0.2",
|
|
78
|
+
"ember-composable-helpers": "^5.0.0",
|
|
79
|
+
"ember-concurrency": "^2.3.7",
|
|
80
|
+
"ember-concurrency-decorators": "^2.0.3",
|
|
81
|
+
"ember-data": "~5.3.0",
|
|
82
|
+
"ember-engines": "^0.9.0",
|
|
83
|
+
"ember-load-initializers": "^2.1.2",
|
|
84
|
+
"ember-math-helpers": "^4.0.0",
|
|
85
|
+
"ember-page-title": "^8.0.0",
|
|
86
|
+
"ember-qunit": "^8.0.1",
|
|
87
|
+
"ember-resolver": "^11.0.1",
|
|
88
|
+
"ember-source": "~5.4.0",
|
|
89
|
+
"ember-source-channel-url": "^3.0.0",
|
|
90
|
+
"ember-template-lint": "^5.11.2",
|
|
91
|
+
"ember-try": "^3.0.0",
|
|
92
|
+
"eslint": "^8.52.0",
|
|
93
|
+
"eslint-config-prettier": "^9.0.0",
|
|
94
|
+
"eslint-plugin-ember": "^11.11.1",
|
|
95
|
+
"eslint-plugin-n": "^16.2.0",
|
|
96
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
97
|
+
"eslint-plugin-qunit": "^8.0.1",
|
|
98
|
+
"loader.js": "^4.7.0",
|
|
99
|
+
"prettier": "^3.0.3",
|
|
100
|
+
"qunit": "^2.20.0",
|
|
101
|
+
"qunit-dom": "^2.0.0",
|
|
102
|
+
"stylelint": "^15.11.0",
|
|
103
|
+
"stylelint-config-standard": "^34.0.0",
|
|
104
|
+
"stylelint-prettier": "^4.0.2",
|
|
105
|
+
"webpack": "^5.89.0"
|
|
106
|
+
},
|
|
107
|
+
"peerDependencies": {
|
|
108
|
+
"ember-engines": "^0.9.0"
|
|
109
|
+
},
|
|
110
|
+
"engines": {
|
|
111
|
+
"node": ">= 18"
|
|
112
|
+
},
|
|
113
|
+
"ember": {
|
|
114
|
+
"edition": "octane"
|
|
115
|
+
},
|
|
116
|
+
"ember-addon": {
|
|
117
|
+
"configPath": "tests/dummy/config"
|
|
118
|
+
},
|
|
119
|
+
"prettier": {
|
|
120
|
+
"trailingComma": "es5",
|
|
121
|
+
"tabWidth": 4,
|
|
122
|
+
"semi": true,
|
|
123
|
+
"singleQuote": true,
|
|
124
|
+
"printWidth": 190,
|
|
125
|
+
"overrides": [
|
|
126
|
+
{
|
|
127
|
+
"files": "*.hbs",
|
|
128
|
+
"options": {
|
|
129
|
+
"singleQuote": false
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
}
|
package/phpunit.xml.dist
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
3
|
+
xsi:noNamespaceSchemaLocation="./server_vendor/phpunit/phpunit/phpunit.xsd"
|
|
4
|
+
colors="true"
|
|
5
|
+
>
|
|
6
|
+
<testsuites>
|
|
7
|
+
<testsuite name="default">
|
|
8
|
+
<directory suffix=".php">./server/tests</directory>
|
|
9
|
+
</testsuite>
|
|
10
|
+
</testsuites>
|
|
11
|
+
<filter>
|
|
12
|
+
<whitelist processUncoveredFilesFromWhitelist="true">
|
|
13
|
+
<directory suffix=".php">./server/src</directory>
|
|
14
|
+
</whitelist>
|
|
15
|
+
</filter>
|
|
16
|
+
</phpunit>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* -------------------------------------------
|
|
5
|
+
* Fleetbase Core API Configuration
|
|
6
|
+
* -------------------------------------------
|
|
7
|
+
*/
|
|
8
|
+
return [
|
|
9
|
+
'api' => [
|
|
10
|
+
'version' => '0.0.1',
|
|
11
|
+
'routing' => [
|
|
12
|
+
'prefix' => 'solid',
|
|
13
|
+
'internal_prefix' => 'int'
|
|
14
|
+
],
|
|
15
|
+
],
|
|
16
|
+
'server' => [
|
|
17
|
+
'host' => env('SOLID_HOST', 'http://solid'),
|
|
18
|
+
'port' => (int) env('SOLID_PORT', 3000),
|
|
19
|
+
'secure' => (bool) env('SOLID_SECURE', false)
|
|
20
|
+
]
|
|
21
|
+
];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Illuminate\Database\Migrations\Migration;
|
|
4
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
return new class extends Migration
|
|
8
|
+
{
|
|
9
|
+
/**
|
|
10
|
+
* Run the migrations.
|
|
11
|
+
*/
|
|
12
|
+
public function up(): void
|
|
13
|
+
{
|
|
14
|
+
Schema::create('solid_identities', function (Blueprint $table) {
|
|
15
|
+
$table->id();
|
|
16
|
+
$table->uuid('uuid')->nullable()->index();
|
|
17
|
+
$table->foreignUuid('company_uuid')->nullable()->index()->references('uuid')->on('companies');
|
|
18
|
+
$table->foreignUuid('user_uuid')->nullable()->index()->references('uuid')->on('users');
|
|
19
|
+
$table->string('identifier')->nullable();
|
|
20
|
+
$table->json('token_response')->nullable();
|
|
21
|
+
$table->timestamps();
|
|
22
|
+
$table->softDeletes();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reverse the migrations.
|
|
28
|
+
*/
|
|
29
|
+
public function down(): void
|
|
30
|
+
{
|
|
31
|
+
Schema::dropIfExists('solid_identities');
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\Client;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Solid\Models\SolidIdentity;
|
|
6
|
+
use Illuminate\Http\Client\Response;
|
|
7
|
+
use Illuminate\Support\Facades\Redis;
|
|
8
|
+
use Illuminate\Support\Str;
|
|
9
|
+
use Jumbojett\OpenIDConnectClient as BaseOpenIDConnectClient;
|
|
10
|
+
use Jumbojett\OpenIDConnectClientException;
|
|
11
|
+
|
|
12
|
+
const CLIENT_NAME = 'Fleetbase';
|
|
13
|
+
final class OpenIDConnectClient extends BaseOpenIDConnectClient
|
|
14
|
+
{
|
|
15
|
+
private ?SolidClient $solid;
|
|
16
|
+
private ?SolidIdentity $identity;
|
|
17
|
+
private ?\stdClass $openIdConfig;
|
|
18
|
+
|
|
19
|
+
public function __construct(array $options = [])
|
|
20
|
+
{
|
|
21
|
+
$this->solid = data_get($options, 'solid');
|
|
22
|
+
$this->identity = data_get($options, 'identity');
|
|
23
|
+
if ($this->identity instanceof SolidIdentity) {
|
|
24
|
+
$this->setRedirectURL($this->identity->getRedirectUri());
|
|
25
|
+
}
|
|
26
|
+
$this->setCodeChallengeMethod('S256');
|
|
27
|
+
$this->setClientName(data_get($options, 'clientName', CLIENT_NAME));
|
|
28
|
+
$this->setClientID(data_get($options, 'clientID'));
|
|
29
|
+
$this->setClientSecret(data_get($options, 'clientSecret'));
|
|
30
|
+
|
|
31
|
+
// Restore client credentials
|
|
32
|
+
if (isset($options['restore'])) {
|
|
33
|
+
$this->restoreClientCredentials();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public static function create(array $options = []): OpenIDConnectClient
|
|
38
|
+
{
|
|
39
|
+
$client = new static($options);
|
|
40
|
+
$openIdConfig = $client->getOpenIdConfiguration();
|
|
41
|
+
$client->setProviderURL($openIdConfig->issuer);
|
|
42
|
+
$client->setIssuer($openIdConfig->issuer);
|
|
43
|
+
$client->providerConfigParam((array) $openIdConfig);
|
|
44
|
+
|
|
45
|
+
return $client;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public function register(array $options = []): OpenIDConnectClient
|
|
49
|
+
{
|
|
50
|
+
// Get registration options
|
|
51
|
+
$clientName = (string) data_get($options, 'clientName', CLIENT_NAME);
|
|
52
|
+
$requestParams = (array) data_get($options, 'requestParams', []);
|
|
53
|
+
$requestOptions = (array) data_get($options, 'requestOptions', []);
|
|
54
|
+
$redirectUri = (string) data_get($options, 'redirectUri', $this->identity ? $this->identity->getRedirectUri() : null);
|
|
55
|
+
$saveCredentials = (bool) data_get($options, 'saveCredentials', false);
|
|
56
|
+
$withCredentials = data_get($options, 'withCredentials');
|
|
57
|
+
|
|
58
|
+
// Get OIDC Config and Registration URL
|
|
59
|
+
$openIdConfig = $this->getOpenIdConfiguration();
|
|
60
|
+
|
|
61
|
+
// Setup OIDC Client
|
|
62
|
+
$this->setIssuer($openIdConfig->issuer);
|
|
63
|
+
$this->providerConfigParam((array) $openIdConfig);
|
|
64
|
+
$this->setRedirectURL($redirectUri);
|
|
65
|
+
|
|
66
|
+
// Get Registration URL
|
|
67
|
+
$registrationUrl = $openIdConfig->registration_endpoint;
|
|
68
|
+
|
|
69
|
+
// Request registration for Client which should handle authentication
|
|
70
|
+
$registrationResponse = $this->solid->post($registrationUrl, ['client_name' => $clientName, 'redirect_uris' => [$redirectUri], ...$requestParams], $requestOptions);
|
|
71
|
+
if ($registrationResponse->successful()) {
|
|
72
|
+
$clientCredentials = (object) $registrationResponse->json();
|
|
73
|
+
$this->setClientCredentials($clientName, $clientCredentials, $saveCredentials, $withCredentials);
|
|
74
|
+
} else {
|
|
75
|
+
throw new OpenIDConnectClientException('Error registering: Please contact the OpenID Connect provider and obtain a Client ID and Secret directly from them');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return $this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public function authenticate(): bool
|
|
82
|
+
{
|
|
83
|
+
$this->setCodeChallengeMethod('S256');
|
|
84
|
+
$this->addScope(['openid', 'webid', 'offline_access']);
|
|
85
|
+
|
|
86
|
+
return parent::authenticate();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private function setClientCredentials(string $clientName = CLIENT_NAME, $clientCredentials, bool $save = false, \Closure $callback = null): OpenIDConnectClient
|
|
90
|
+
{
|
|
91
|
+
$this->setClientID($clientCredentials->client_id);
|
|
92
|
+
$this->setClientName($clientCredentials->client_name);
|
|
93
|
+
$this->setClientSecret($clientCredentials->client_secret);
|
|
94
|
+
|
|
95
|
+
// Save the client credentials
|
|
96
|
+
if ($save) {
|
|
97
|
+
$this->saveClientCredentials($clientName, $clientCredentials);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Run callback if provided
|
|
101
|
+
if (is_callable($callback)) {
|
|
102
|
+
$callback($clientCredentials);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return $this;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private function saveClientCredentials(string $clientName = CLIENT_NAME, $clientCredentials): OpenIDConnectClient
|
|
109
|
+
{
|
|
110
|
+
$key = $this->getClientCredentialsKey($clientName);
|
|
111
|
+
|
|
112
|
+
return $this->save($key, $clientCredentials);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public function restoreClientCredentials(string $clientName = CLIENT_NAME, array $overwrite = []): OpenIDConnectClient
|
|
116
|
+
{
|
|
117
|
+
$key = $this->getClientCredentialsKey($clientName);
|
|
118
|
+
$savedClientCredentials = $this->retrieve($key);
|
|
119
|
+
if (!$savedClientCredentials) {
|
|
120
|
+
throw new \Exception('No saved client credentials to restore.');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
$restoredClientCredentials = (object) array_merge((array) $savedClientCredentials, $overwrite);
|
|
124
|
+
$this->setClientCredentials($clientName, $restoredClientCredentials);
|
|
125
|
+
|
|
126
|
+
return $this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private function getClientCredentialsKey(string $clientName = CLIENT_NAME): string
|
|
130
|
+
{
|
|
131
|
+
if ($this->identity instanceof SolidIdentity) {
|
|
132
|
+
return 'oidc:client_credentials:' . Str::slug($clientName) . ':' . $this->identity->uuid;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return 'oidc:client_credentials:' . Str::slug($clientName);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private function save(string $key, $value): OpenIDConnectClient
|
|
139
|
+
{
|
|
140
|
+
if (is_object($value) || is_array($value)) {
|
|
141
|
+
$value = json_encode($value);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Redis::set($key, $value);
|
|
145
|
+
|
|
146
|
+
return $this;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private function retrieve(string $key)
|
|
150
|
+
{
|
|
151
|
+
$value = Redis::get($key);
|
|
152
|
+
if (Str::isJson($value)) {
|
|
153
|
+
$value = (object) json_decode($value);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return $value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public function getOpenIdConfiguration(string $key = null)
|
|
160
|
+
{
|
|
161
|
+
$openIdConfigResponse = $this->solid->get('.well-known/openid-configuration');
|
|
162
|
+
if ($openIdConfigResponse instanceof Response) {
|
|
163
|
+
$openIdConfig = (object) $openIdConfigResponse->json();
|
|
164
|
+
if ($key) {
|
|
165
|
+
return $openIdConfig->{$key};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
$this->openIdConfig = $openIdConfig;
|
|
169
|
+
|
|
170
|
+
return $openIdConfig;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected function getSessionKey($key)
|
|
177
|
+
{
|
|
178
|
+
if (Redis::exists('oidc:session' . Str::slug($key))) {
|
|
179
|
+
return $this->retrieve('oidc:session' . Str::slug($key));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
protected function setSessionKey($key, $value)
|
|
186
|
+
{
|
|
187
|
+
$this->save('oidc:session' . Str::slug($key), $value);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
protected function unsetSessionKey($key)
|
|
191
|
+
{
|
|
192
|
+
Redis::del('oidc:session' . Str::slug($key));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
protected function getAllSessionKeysWithValues()
|
|
196
|
+
{
|
|
197
|
+
$pattern = 'oidc:session*'; // Pattern to match keys
|
|
198
|
+
$keys = [];
|
|
199
|
+
$cursor = 0;
|
|
200
|
+
|
|
201
|
+
do {
|
|
202
|
+
// Use the SCAN command to find keys matching the pattern
|
|
203
|
+
[$cursor, $results] = Redis::scan($cursor, 'MATCH', $pattern);
|
|
204
|
+
|
|
205
|
+
foreach ($results as $key) {
|
|
206
|
+
// Retrieve each value and add it to the keys array
|
|
207
|
+
$keys[$key] = Redis::get($key);
|
|
208
|
+
}
|
|
209
|
+
} while ($cursor);
|
|
210
|
+
|
|
211
|
+
return $keys;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// public static function createDPoP(string $method, string $url, string $accessToken = null): string
|
|
215
|
+
// {
|
|
216
|
+
// }
|
|
217
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\Client;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Solid\Models\SolidIdentity;
|
|
6
|
+
use Illuminate\Http\Client\Response;
|
|
7
|
+
use Illuminate\Support\Facades\Http;
|
|
8
|
+
use Illuminate\Support\Str;
|
|
9
|
+
|
|
10
|
+
class SolidClient
|
|
11
|
+
{
|
|
12
|
+
private string $host = 'localhost';
|
|
13
|
+
private int $port = 3000;
|
|
14
|
+
private bool $secure = true;
|
|
15
|
+
public ?SolidIdentity $solidIdentity;
|
|
16
|
+
public ?OpenIDConnectClient $oidc;
|
|
17
|
+
private const DEFAULT_MIME_TYPE = 'text/turtle';
|
|
18
|
+
private const LDP_BASIC_CONTAINER = 'http://www.w3.org/ns/ldp#BasicContainer';
|
|
19
|
+
private const LDP_RESOURCE = 'http://www.w3.org/ns/ldp#Resource';
|
|
20
|
+
private const OIDC_ISSUER = 'http://www.w3.org/ns/solid/terms#oidcIssuer';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Constructor for the SolidClient.
|
|
24
|
+
*
|
|
25
|
+
* Initializes the client with the provided options or defaults.
|
|
26
|
+
*
|
|
27
|
+
* @param array $options configuration options for the client
|
|
28
|
+
*/
|
|
29
|
+
public function __construct(array $options = [])
|
|
30
|
+
{
|
|
31
|
+
$this->identity = data_get($options, 'identity');
|
|
32
|
+
$this->host = config('solid.server.host', data_get($options, 'host'));
|
|
33
|
+
$this->port = (int) config('solid.server.port', data_get($options, 'port'));
|
|
34
|
+
$this->secure = (bool) config('solid.server.secure', data_get($options, 'secure'));
|
|
35
|
+
$this->oidc = OpenIDConnectClient::create(['solid' => $this, ...$options]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Factory method to create a new instance of the SolidClient.
|
|
40
|
+
*
|
|
41
|
+
* @param array $options configuration options for the client
|
|
42
|
+
*
|
|
43
|
+
* @return static a new instance of SolidClient
|
|
44
|
+
*/
|
|
45
|
+
public static function create(array $options = []): self
|
|
46
|
+
{
|
|
47
|
+
return new static($options);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Constructs the URL to the Solid server based on the configured host, port, and security.
|
|
52
|
+
*
|
|
53
|
+
* @return string the fully constructed URL
|
|
54
|
+
*/
|
|
55
|
+
public function getServerUrl(): string
|
|
56
|
+
{
|
|
57
|
+
$protocol = $this->secure ? 'https' : 'http';
|
|
58
|
+
$host = preg_replace('#^.*://#', '', $this->host);
|
|
59
|
+
|
|
60
|
+
return "{$protocol}://{$host}:{$this->port}";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates a full request URL based on the server URL and the provided URI.
|
|
65
|
+
*
|
|
66
|
+
* This function constructs a complete URL by appending the given URI to the base server URL.
|
|
67
|
+
* It ensures that there is exactly one slash between the base URL and the URI.
|
|
68
|
+
*
|
|
69
|
+
* @param string|null $uri The URI to append to the server URL. If null, only the server URL is returned.
|
|
70
|
+
*
|
|
71
|
+
* @return string the fully constructed URL
|
|
72
|
+
*/
|
|
73
|
+
private function createRequestUrl(string $uri = null): string
|
|
74
|
+
{
|
|
75
|
+
if (Str::startsWith($uri, 'http')) {
|
|
76
|
+
return $uri;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
$url = $this->getServerUrl();
|
|
80
|
+
if (is_string($uri)) {
|
|
81
|
+
$uri = '/' . ltrim($uri, '/');
|
|
82
|
+
$url .= $uri;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return $url;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Set the identity to use for authenticated request.
|
|
90
|
+
*/
|
|
91
|
+
public function withIdentity(SolidIdentity $identity): SolidClient
|
|
92
|
+
{
|
|
93
|
+
$this->identity = $identity;
|
|
94
|
+
|
|
95
|
+
return $this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Make a HTTP request to the Solid server.
|
|
100
|
+
*
|
|
101
|
+
* @param string $method The HTTP method (GET, POST, etc.)
|
|
102
|
+
* @param string $uri The URI to send the request to
|
|
103
|
+
* @param array $options Options for the request
|
|
104
|
+
*/
|
|
105
|
+
protected function request(string $method, string $uri, array $data = [], array $options = []): Response
|
|
106
|
+
{
|
|
107
|
+
$url = $this->createRequestUrl($uri);
|
|
108
|
+
|
|
109
|
+
return Http::withOptions($options)->{$method}($url, $data);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Send an authenticated request with the current identity.
|
|
114
|
+
*/
|
|
115
|
+
public function authenticatedRequest(string $method, string $uri, array $data = [], array $options = []): Response
|
|
116
|
+
{
|
|
117
|
+
if (!$this->identity) {
|
|
118
|
+
throw new \Exception('Solid Identity required to make an authenticated request.');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
$url = $this->createRequestUrl($uri);
|
|
122
|
+
$accessToken = $this->identity->getAccessToken();
|
|
123
|
+
if ($accessToken) {
|
|
124
|
+
$options['headers'] = is_array($options['headers']) ? $options['headers'] : [];
|
|
125
|
+
$options['headers']['Authorization'] = 'DPoP ' . $accessToken;
|
|
126
|
+
$options['headers']['DPoP'] = OpenIDConnectClient::createDPoP($method, $url, $accessToken);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return Http::withOptions($options)->{$method}($url, $data);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Send a GET request to the Solid server.
|
|
134
|
+
*
|
|
135
|
+
* @param string $uri The URI to send the request to
|
|
136
|
+
* @param array $options Options for the request
|
|
137
|
+
*/
|
|
138
|
+
public function get(string $uri, array $data = [], array $options = []): Response
|
|
139
|
+
{
|
|
140
|
+
return $this->request('get', $uri, $data, $options);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Send a POST request to the Solid server.
|
|
145
|
+
*
|
|
146
|
+
* @param string $uri The URI to send the request to
|
|
147
|
+
* @param array $data Data to be sent in the request body
|
|
148
|
+
*/
|
|
149
|
+
public function post(string $uri, array $data = [], array $options = []): Response
|
|
150
|
+
{
|
|
151
|
+
return $this->request('post', $uri, $data, $options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Send a PUT request to the Solid server.
|
|
156
|
+
*
|
|
157
|
+
* @param string $uri The URI to send the request to
|
|
158
|
+
* @param array $data Data to be sent in the request body
|
|
159
|
+
*/
|
|
160
|
+
public function put(string $uri, array $data = [], array $options = []): Response
|
|
161
|
+
{
|
|
162
|
+
return $this->request('put', $uri, $data, $options);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Send a PATCH request to the Solid server.
|
|
167
|
+
*
|
|
168
|
+
* @param string $uri The URI to send the request to
|
|
169
|
+
* @param array $data Data to be sent in the request body
|
|
170
|
+
*/
|
|
171
|
+
public function patch(string $uri, array $data = [], array $options = []): Response
|
|
172
|
+
{
|
|
173
|
+
return $this->request('patch', $uri, $data, $options);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Send a DELETE request to the Solid server.
|
|
178
|
+
*
|
|
179
|
+
* @param string $uri The URI to send the request to
|
|
180
|
+
* @param array $options Options for the request
|
|
181
|
+
*/
|
|
182
|
+
public function delete(string $uri, array $data = [], array $options = []): Response
|
|
183
|
+
{
|
|
184
|
+
return $this->request('delete', $uri, $data, $options);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\Http\Controllers;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Controllers\Controller as BaseController;
|
|
6
|
+
use Fleetbase\Solid\Client\SolidClient;
|
|
7
|
+
use Fleetbase\Solid\Models\SolidIdentity;
|
|
8
|
+
use Fleetbase\Support\Utils;
|
|
9
|
+
use Illuminate\Http\Request;
|
|
10
|
+
|
|
11
|
+
class OIDCController extends BaseController
|
|
12
|
+
{
|
|
13
|
+
public function completeRegistration(string $identifier, Request $request)
|
|
14
|
+
{
|
|
15
|
+
if ($request->has('code') && $identifier) {
|
|
16
|
+
try {
|
|
17
|
+
$identity = SolidIdentity::where('identifier', $identifier)->first();
|
|
18
|
+
if ($identity) {
|
|
19
|
+
$solid = SolidClient::create(['identity' => $identity, 'restore' => true]);
|
|
20
|
+
$solid->oidc->authenticate();
|
|
21
|
+
$identity->update(['token_response' => $solid->oidc->getTokenResponse()]);
|
|
22
|
+
}
|
|
23
|
+
} catch (\Throwable $e) {
|
|
24
|
+
return redirect(Utils::consoleUrl('solid-protocol', ['error' => $e->getMessage()]));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return redirect(Utils::consoleUrl('solid-protocol', $request->all()));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return redirect(Utils::consoleUrl('solid-protocol', ['error' => 'Unable to authenticate with provider']));
|
|
31
|
+
}
|
|
32
|
+
}
|