Skip to content

Commit add12cd

Browse files
committed
chore: restructure startup and demo scripts
Signed-off-by: Wouter Termont <wouter.termont@ugent.be>
1 parent 89a19c3 commit add12cd

7 files changed

Lines changed: 265 additions & 106 deletions

File tree

demo/flow.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/* eslint-disable max-len */
2+
3+
import { fetch } from 'cross-fetch';
4+
import { Parser, Store } from 'n3';
5+
6+
const terms = {
7+
solid: {
8+
umaServer: 'http://www.w3.org/ns/solid/terms#umaServer',
9+
viewIndex: 'http://www.w3.org/ns/solid/terms#viewIndex',
10+
entry: 'http://www.w3.org/ns/solid/terms#entry',
11+
filter: 'http://www.w3.org/ns/solid/terms#filter',
12+
location: 'http://www.w3.org/ns/solid/terms#location',
13+
},
14+
filters: {
15+
bday: 'http://localhost:3000/catalog/public/filters/bday',
16+
age: 'http://localhost:3000/catalog/public/filters/age',
17+
}
18+
}
19+
20+
const parser = new Parser();
21+
22+
const privateRequest = async (resource_id: string, tokenEndpoint: string) => {
23+
const claim_token = "http://localhost:3000/demo/public/bday-app"
24+
25+
const content = {
26+
grant_type: 'urn:ietf:params:oauth:grant-type:uma-ticket',
27+
claim_token: encodeURIComponent(claim_token),
28+
claim_token_format: 'urn:solidlab:uma:claims:formats:webid',
29+
// ticket,
30+
permissions: [{
31+
resource_id,
32+
resource_scopes: [ 'urn:example:css:modes:read', 'urn:example:css:modes:write' ],
33+
}]
34+
};
35+
36+
const asRequestResponse = await fetch(tokenEndpoint, {
37+
method: "POST",
38+
headers: {
39+
"content-type":"application/json"
40+
},
41+
body: JSON.stringify(content),
42+
});
43+
44+
const asResponse = await asRequestResponse.json();
45+
const tokenResponse = await fetch(resource_id, {
46+
headers: { 'Authorization': `${asResponse.token_type} ${asResponse.access_token}` }
47+
});
48+
}
49+
50+
const log = (msg: string, obj?: any) => {
51+
console.log('');
52+
console.log(msg);
53+
if (obj) {
54+
console.log('\n');
55+
console.log(obj);
56+
}
57+
}
58+
59+
function parseJwt (token:string) {
60+
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
61+
}
62+
63+
async function main() {
64+
65+
log(`Alright, so, for the demo ...`);
66+
67+
const webId = 'http://localhost:3000/ruben/profile/card#me';
68+
69+
log(`Ruben V., a.k.a. <${webId}>, has some private data in <http://localhost:3000/ruben/private/data>.`);
70+
71+
log(`Of course, he does not want everyone to be able to see all of his private data when they need just one aspect of it. Therefore, Ruben has installed two Views on his data, based on SPARQL filters from a public Catalog. (When and how this is done is out-of-scope for now.)`);
72+
73+
const webIdData = new Store(parser.parse(await (await fetch(webId)).text()));
74+
const viewIndex = webIdData.getObjects(webId, terms.solid.viewIndex, null)[0].value;
75+
const views = Object.fromEntries(webIdData.getObjects(viewIndex, terms.solid.entry, null).map(entry => {
76+
const filter = webIdData.getObjects(entry, terms.solid.filter, null)[0].value;
77+
const location = webIdData.getObjects(entry, terms.solid.location, null)[0].value;
78+
return [filter, location];
79+
}));
80+
81+
log(`Discovery of views is currently a very crude mechanism based on a public index in the WebID document. (A cleaner mechanism using the UMA server as central hub is being devised.) Using the discovery mechanism, we find the following views on Ruben's private data.`)
82+
83+
log(`(1) <${views[terms.filters.bday]}> filters out his birth date, according to the <${terms.filters.bday}> filter`);
84+
log(`(2) <${views[terms.filters.age]}> derives his age, according to the <${terms.filters.bday}> filter`);
85+
86+
const policyDir = 'http://localhost:3000/ruben/settings/policies/';
87+
88+
log(`Access to Ruben's data is based on policies he manages through his Authz Companion app, and which are stored in <${policyDir}>. (This is, of course, not publicly known.)`);
89+
90+
const umaServer = webIdData.getObjects(webId, terms.solid.umaServer, null)[0].value;
91+
const configUrl = new URL('.well-known/uma2-configuration', umaServer);
92+
const umaConfig = await (await fetch(configUrl)).json();
93+
const tokenEndpoint = umaConfig.token_endpoint;
94+
95+
log(`To request access to Ruben's data, an agent will need to negotiate with Ruben's Authorization Server, which his WebID document identifies as <${umaServer}>.`);
96+
log(`Via the Well-Known endpoint <${configUrl.href}>, we can discover the Token Endpoint <${tokenEndpoint}>.`);
97+
98+
log(`Now, having discovered both the location of the UMA server and of the desired data, an agent can request the former for access to the latter.`);
99+
100+
log(`...`);
101+
102+
log(`Having been notified in some way of the access request, Ruben could go to his Authz Companion app, and add a policy allowing the requested access.`);
103+
104+
const privateResource = "http://localhost:3000/ruben/private/derived/age"
105+
const claim_token = "http://localhost:3000/demo/public/bday-app"
106+
107+
const content = {
108+
grant_type: 'urn:ietf:params:oauth:grant-type:uma-ticket',
109+
claim_token: encodeURIComponent(claim_token),
110+
claim_token_format: 'urn:solidlab:uma:claims:formats:webid',
111+
// ticket,
112+
permissions: [{
113+
resource_id: privateResource,
114+
resource_scopes: [ 'urn:example:css:modes:read' ],
115+
}]
116+
};
117+
118+
console.log(`=== Requesting token at ${tokenEndpoint} with ticket body:\n`);
119+
console.log(content);
120+
console.log('');
121+
122+
const asRequestResponse = await fetch(tokenEndpoint, {
123+
method: "POST",
124+
headers: {
125+
"content-type":"application/json"
126+
},
127+
body: JSON.stringify(content),
128+
})
129+
130+
// For debugging:
131+
// console.log("Authorization Server response:", await asRequestResponse.text());
132+
// throw 'stop'
133+
134+
const asResponse = await asRequestResponse.json();
135+
136+
const decodedToken = parseJwt(asResponse.access_token);
137+
138+
console.log(`= Status: ${asRequestResponse.status}\n`);
139+
console.log(`= Body (decoded):\n`);
140+
console.log({ ...asResponse, access_token: asResponse.access_token.slice(0,10).concat('...') });
141+
console.log('\n');
142+
143+
// for (const permission of decodedToken.permissions) {
144+
// console.log(`Permissioned scopes for resource ${permission.resource_id}:`, permission.resource_scopes)
145+
// }
146+
147+
console.log(`=== Trying to create private resource <${privateResource}> WITH access token.\n`);
148+
149+
const tokenResponse = await fetch(privateResource, {
150+
headers: { 'Authorization': `${asResponse.token_type} ${asResponse.access_token}` }
151+
});
152+
153+
console.log(`= Status: ${tokenResponse.status}\n`);
154+
console.log(`= Body:\n`);
155+
console.log(`= Body: ${await tokenResponse.text()}`);
156+
console.log(`\n`);
157+
}
158+
159+
main();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"test:all": "yarn workspaces foreach --exclude . -A -pi run test",
5858
"start:all": "yarn workspaces foreach --exclude . -A -pi run start",
5959
"start:demo": "yarn workspaces foreach --exclude . -A -pi run demo",
60-
"script:demo": "yarn exec ts-node ./scripts/test-demo.ts",
60+
"script:demo": "yarn exec ts-node ./demo/flow.ts",
6161
"script:public": "yarn exec ts-node ./scripts/test-public.ts",
6262
"script:private": "yarn exec ts-node ./scripts/test-private.ts",
6363
"script:registration": "yarn exec ts-node ./scripts/test-registration.ts",

packages/uma/bin/demo.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as path from 'path';
2+
import { ComponentsManager } from 'componentsjs';
3+
import { NodeHttpServer } from '../src/util/http/server/NodeHttpServer';
4+
import { setLogger } from '../src/util/logging/LoggerUtils';
5+
import { WinstonLogger } from '../src/util/logging/WinstonLogger';
6+
7+
const protocol = 'http';
8+
const host = 'localhost';
9+
const port = 4000;
10+
11+
const baseUrl = `${protocol}://${host}:${port}/uma`;
12+
const rootDir = path.join(__dirname, '../');
13+
14+
export const launch: () => Promise<void> = async () => {
15+
16+
const variables: Record<string, any> = {};
17+
18+
variables['urn:uma:variables:port'] = port;
19+
variables['urn:uma:variables:host'] = host;
20+
variables['urn:uma:variables:protocol'] = protocol;
21+
variables['urn:uma:variables:baseUrl'] = baseUrl;
22+
23+
// variables['urn:uma:variables:policyDir'] = path.join(rootDir, './config/rules/policy');
24+
25+
variables['urn:uma:variables:mainModulePath'] = rootDir;
26+
variables['urn:uma:variables:customConfigPath'] = path.join(rootDir, './config/demo.json');
27+
28+
const mainModulePath = variables['urn:uma:variables:mainModulePath'];
29+
const configPath = variables['urn:uma:variables:customConfigPath'];
30+
31+
setLogger(new WinstonLogger('test-logger', 60, 30));
32+
33+
const manager = await ComponentsManager.build({
34+
mainModulePath,
35+
logLevel: 'silly',
36+
typeChecking: false,
37+
});
38+
39+
await manager.configRegistry.register(configPath);
40+
41+
const umaServer: NodeHttpServer = await manager.instantiate('urn:uma:default:NodeHttpServer',{variables});
42+
umaServer.start();
43+
44+
};
45+
46+
launch();
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
import * as fs from 'fs';
21
import * as path from 'path';
32
import { ComponentsManager } from 'componentsjs';
4-
import { NodeHttpServer } from './util/http/server/NodeHttpServer';
5-
import { setLogger } from './util/logging/LoggerUtils';
6-
import { WinstonLogger } from './util/logging/WinstonLogger';
7-
import { ResponseType } from './routes/Config';
8-
import { ASYMMETRIC_CRYPTOGRAPHIC_ALGORITHM }
9-
from '@solid/access-token-verifier/dist/constant/ASYMMETRIC_CRYPTOGRAPHIC_ALGORITHM';
3+
import { NodeHttpServer } from '../src/util/http/server/NodeHttpServer';
4+
import { setLogger } from '../src/util/logging/LoggerUtils';
5+
import { WinstonLogger } from '../src/util/logging/WinstonLogger';
106

117
const protocol = 'http';
128
const host = 'localhost';

packages/uma/config/demo.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"@context": [
3+
"https://linkedsoftwaredependencies.org/bundles/npm/@solidlab/uma/^0.0.0/components/context.jsonld",
4+
"https://linkedsoftwaredependencies.org/bundles/npm/@solidlab/ucp/^0.0.0/components/context.jsonld"
5+
],
6+
"import": [
7+
"sai-uma:config/default.json"
8+
],
9+
"@graph": [
10+
{
11+
"@id": "urn:uma:demo:Authorizer",
12+
"@type": "Override",
13+
"overrideInstance": { "@id": "urn:uma:default:Authorizer" },
14+
"overrideParameters": {
15+
"@type": "NamespacedAuthorizer",
16+
"authorizers": [
17+
{
18+
"NamespacedAuthorizer:_authorizers_key": "profile",
19+
"NamespacedAuthorizer:_authorizers_value": {
20+
"@id": "urn:uma:default:AllAuthorizer",
21+
"@type": "AllAuthorizer"
22+
}
23+
},
24+
{
25+
"NamespacedAuthorizer:_authorizers_key": "public",
26+
"NamespacedAuthorizer:_authorizers_value": {
27+
"@id": "urn:uma:default:AllAuthorizer"
28+
}
29+
},
30+
{
31+
"NamespacedAuthorizer:_authorizers_key": "settings",
32+
"NamespacedAuthorizer:_authorizers_value": {
33+
"@id": "urn:uma:default:AllAuthorizer"
34+
}
35+
}
36+
],
37+
"fallback": {
38+
"@id": "urn:uma:default:PolicyBasedAuthorizer"
39+
}
40+
}
41+
},
42+
{
43+
"@id": "urn:uma:demo:RulesStorage",
44+
"@type": "Override",
45+
"overrideInstance": {
46+
"@id": "urn:uma:default:RulesStorage"
47+
},
48+
"overrideParameters": {
49+
"@type": "ContainerUCRulesStorage",
50+
"containerURL": "http://localhost:3000/ruben/settings/policies/"
51+
}
52+
}
53+
]
54+
}

packages/uma/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@
5656
"build:ts": "yarn run -T tsc",
5757
"build:components": "yarn run -T componentsjs-generator -r sai-uma -s src -c dist/components -i .componentsignore --lenient",
5858
"test": "yarn run -T jest --coverage",
59-
"start": "node dist/main.js",
60-
"demo": "node dist/main.js"
59+
"start": "ts-node bin/main.ts",
60+
"demo": "ts-node bin/demo.ts"
6161
},
6262
"dependencies": {
6363
"@httpland/authorization-parser": "^1.1.0",

scripts/test-demo.ts

Lines changed: 0 additions & 96 deletions
This file was deleted.

0 commit comments

Comments
 (0)