Skip to content

Commit 3fc83f4

Browse files
committed
feat: Support PAT using client credentials
1 parent ef386bc commit 3fc83f4

File tree

71 files changed

+2547
-518
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2547
-518
lines changed

documentation/getting-started.md

Lines changed: 109 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,26 +63,114 @@ You can see the AS working by going to <http://localhost:4000/uma/.well-known/um
6363
This page contains all the relevant APIs of the UMA server,
6464
which are used in the next steps.
6565

66-
## Authenticating the Resource Server
67-
68-
Throughout this guide, there are several instances where the RS has to send an HTTP request to the AS.
69-
The AS needs some way to verify if the request comes from the RS.
70-
The current implementation makes use of [HTTP signatures](https://datatracker.ietf.org/doc/html/rfc9421).
71-
To enable this, the RS needs to expose a [JSON Web Key](https://datatracker.ietf.org/doc/html/rfc7517).
72-
This key can be found at <http://localhost:3000/.well-known/jwks.json>.
73-
The RS uses that same key to sign its messages as described in the RFC,
74-
using the [http-message-signatures](https://www.npmjs.com/package/http-message-signatures) library.
75-
This is done for every HTTP request the RS sends to the AS in the following sections.
76-
77-
## Locating the Authorization Server
78-
79-
To be able to communicate with it, the RS needs to know where to find the AS.
80-
The current implementation of the RS knows this through server configuration.
81-
This can be seen in the startup script in the [RS package.json](../packages/css/package.json)
82-
when looking at the `start` script.
83-
It uses the CLI parameter `-a http://localhost:4000/` to inform the RS where it can find the relevant AS,
84-
which internally sets the Components.js variable `urn:solid-server:uma:variable:AuthorizationServer`
85-
to the provided value.
66+
## Authenticating as Resource Owner
67+
68+
There are some APIs on the AS where a Resource Owner (RO) has to identify themself.
69+
Specifically, the policy APIs, as described in the [policy management documentation](policy-management.md),
70+
and the client credentials API described further below.
71+
Two authentication methods are supported: OIDC tokens, both Solid and standard, and unsafe WebID strings.
72+
73+
To use OIDC, the `Bearer` authorization scheme needs to be used, followed by the token.
74+
For example, `Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI...`.
75+
76+
To directly pass a WebID, the `WebID` scheme can be used together with a URL encoded WebID.
77+
For example, `Authorization: WebID http%3A%2F%2Fexample.com%2Fprofile%2Fcard%23me`.
78+
No validation is performed in this case, so this should only be used for development and debugging purposes.
79+
80+
## Authenticating as Resource Server
81+
82+
The RS has to send several requests to the AS, as described below.
83+
Generally, these requests are done for a specific user,
84+
e.g., registering a resource for its owner,
85+
or requesting access on an owner's resource.
86+
To identify both itself and the owner,
87+
the RS has to send a Personal Access Token (PAT) in the authorization header
88+
when making such a request.
89+
As the UMA specification does not have strong requirements on how such a token should be generated,
90+
the specific implementation of our AS is described here.
91+
92+
The following steps need to be taken:
93+
1. The owner requests client credentials from the AS for a specific RS, which is the client here,
94+
as described in RFC 7591.
95+
2. The AS returns an id/secret combination which uniquely identifies this owner/RS combination.
96+
3. The owner provides this id/secret combination to the RS, together with the URL of the corresponding AS.
97+
4. Before making a request, the RS uses this id/secret combination to request an access token from that AS
98+
with scope `uma_protection`, as described in RFC 6749 and RFC 7617.
99+
This token is the PAT.
100+
5. The RS uses this bearer token for the request.
101+
102+
### Requesting client credentials
103+
104+
To register a RS, the owner should find the `registration_endpoint` API in the AS' UMA configuration.
105+
They should then POST a request there with a body as follows:
106+
```json
107+
{
108+
"client_name": "descriptive name for the RS (optional)",
109+
"client_uri": "http://localhost:3000"
110+
}
111+
```
112+
113+
The AS will then respond with client credentials such as
114+
```json
115+
{
116+
"client_uri": "http://localhost:3000",
117+
"client_name": "descriptive name for the RS (optional)",
118+
"client_id": "1be8b63f-29c2-4d2c-9932-8784a28de5cf",
119+
"client_secret": "184984651984...",
120+
"client_secret_expires_at": "0",
121+
"grant_types": [ "client_credentials", "refresh_token" ],
122+
"token_endpoint_auth_method": "client_secret_basic"
123+
}
124+
```
125+
126+
This response, or at least the `client_id` and `client_secret` should then be passed along to the RS.
127+
128+
### Sending the credentials to the RS (CSS specific)
129+
130+
This section is specific for our CSS implementation of the RS
131+
and is irrelevant if you have your own custom RS.
132+
133+
The implementation makes use of the
134+
[CSS account API](https://communitysolidserver.github.io/CommunitySolidServer/latest/usage/account/json-api/).
135+
A new `pat` entry has been added to the account controls after authenticating.
136+
This API expects a POST request with the following body:
137+
```json
138+
{
139+
"id": "1be8b63f-29c2-4d2c-9932-8784a28de5cf",
140+
"secret": "184984651984...",
141+
"issuer": "http://localhost:4000/uma"
142+
}
143+
```
144+
Sending this request will update the stored credentials for the authenticated user.
145+
146+
### Requesting a PAT as RS
147+
148+
To request a PAT, the RS needs to find the `token_endpoint` API in the AS UMA config.
149+
A PAT can then be requested by sending a POST request with a `application/x-www-form-urlencoded` body as follows:
150+
```
151+
grant_type=client_credentials&scope=uma_protection
152+
```
153+
A JSON body containing the same information would also work.
154+
155+
The important thing is that the `Authorization` header needs to be set using the Basic id/secret combination
156+
as described in RFC 7617.
157+
Specifically, that means you generate a string `$MY_ID:$MY_secret` and generating the base 64 encoding of this result.
158+
The Authorization header should then contain `Basic $ENCODED_RESULT`.
159+
160+
The AS will then respond with a body containing the generated access token:
161+
```json
162+
{
163+
"access_token": "eyJhbGciOi...",
164+
"refresh_token": "efe2dea0-9cb4-4ffd-9dbe-a581a249202b",
165+
"token_type": "Bearer",
166+
"expires_in": 3600,
167+
"scope": "uma_protection"
168+
}
169+
```
170+
171+
This access token then needs to be sent along in a Bearer Authorization header when making the necessary requests.
172+
The current implementation of the AS allows the PAT to be reused until it is expired,
173+
which can be useful when doing bulk resource registration.
86174

87175
## Resource registration
88176

@@ -185,7 +273,7 @@ and the requested scopes, which looks as follows:
185273

186274
### Generating a ticket
187275

188-
The first thing the AS has to do when receiving any HTTP request is to validate the signature, as discussed above.
276+
The first thing the AS has to do when receiving any HTTP request is to validate the PAT, as discussed above.
189277
Afterward, it creates a ticket identifier, links it with the request body,
190278
and responds to the RS request with a 201 status code.
191279
The location header of the response contains the ticket identifier.

documentation/policy-management.md

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,12 @@ The current implementation supports the following requests on the UMA server:
1616
These requests comply with some restrictions:
1717

1818
- When the URL contains a policy ID, it must be URI encoded.
19-
- Every request requires a valid Authorization header, which is detailed below.
19+
- Every request requires a valid Authorization header.
2020

21-
### Authorization
22-
23-
The policy API supports similar authentication tokens as the UMA API,
24-
but expects them in the Authorization header,
25-
as the body is already used for other purposes.
26-
Two authorization methods are supported: OIDC tokens, both Solid and standard, and unsafe WebID strings.
27-
28-
To use OIDC, the `Bearer` authorization scheme needs to be used, followed by the token.
29-
For example, `Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI...`.
21+
### Authentication
3022

31-
To directly pass a WebID, the `WebID` scheme can be used together with a URL encoded WebID.
32-
For example, `Authorization: WebID http%3A%2F%2Fexample.com%2Fprofile%2Fcard%23me`.
33-
No validation is performed in this case, so this should only be used for development and debugging purposes.
23+
The client is expected to use the authentication method
24+
described in the [getting started documentation](getting-started.md).
3425

3526
### Creating policies
3627

packages/css/config/init-pat.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"@context": [
3+
"https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld",
4+
"https://linkedsoftwaredependencies.org/bundles/npm/@solidlab/uma-css/^0.0.0/components/context.jsonld",
5+
"https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/context.jsonld"
6+
],
7+
"@graph": [
8+
{
9+
"comment": "Automatically registers a PAT for every account on server start"
10+
},
11+
{
12+
"@id": "urn:solid-server:default:PatSeedRegistrar",
13+
"@type": "PatSeedRegistrar",
14+
"accountStorage": { "@id": "urn:solid-server:default:AccountStorage" },
15+
"accountStore": { "@id": "urn:solid-server:default:AccountStore" },
16+
"umaClient": { "@id": "urn:solid-server:default:UmaClient" },
17+
"patUpdater": { "@id": "urn:solid-server:default:PatUpdater" }
18+
},
19+
{
20+
"comment": "The PatSeedRegistrar is added to the list of Initializers so Components.js finds and instantiate it.",
21+
"@id": "urn:solid-server:default:PrimaryParallelInitializer",
22+
"@type": "ParallelHandler",
23+
"handlers": [{ "@id": "urn:solid-server:default:PatSeedRegistrar" }]
24+
},
25+
{
26+
"@id": "urn:solid-server:default:StatusDependantServerConfigurator",
27+
"@type": "StatusDependantServerConfigurator",
28+
"dependants": [
29+
{ "@id": "urn:solid-server:default:PatSeedRegistrar" }
30+
]
31+
}
32+
]
33+
}

packages/css/config/seed.json

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
"password": "abc123",
55
"pods": [{
66
"name": "alice"
7-
}]
7+
}],
8+
"authz": {
9+
"server": "http://localhost:4000/uma"
10+
}
811
},
912
{
1013
"email": "[email protected]",
@@ -13,7 +16,10 @@
1316
{
1417
"name": "bob"
1518
}
16-
]
19+
],
20+
"authz": {
21+
"server": "http://localhost:4000/uma"
22+
}
1723
},
1824
{
1925
"email": "[email protected]",
@@ -22,7 +28,10 @@
2228
{
2329
"name": "demo"
2430
}
25-
]
31+
],
32+
"authz": {
33+
"server": "http://localhost:4000/uma"
34+
}
2635
},
2736
{
2837
"email": "[email protected]",
@@ -31,6 +40,9 @@
3140
{
3241
"name": "resources"
3342
}
34-
]
43+
],
44+
"authz": {
45+
"server": "http://localhost:4000/uma"
46+
}
3547
}
3648
]

packages/css/config/uma/default.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
"uma-css:config/uma/overrides/token-extractor.json",
1313
"uma-css:config/uma/overrides/www-auth.json",
1414

15-
"uma-css:config/uma/parts/cli.json",
1615
"uma-css:config/uma/parts/client.json",
1716
"uma-css:config/uma/parts/fetcher.json",
1817
"uma-css:config/uma/parts/owner-util.json",
18+
"uma-css:config/uma/parts/pat.json",
1919
"uma-css:config/uma/parts/resource-registrar.json",
2020
"uma-css:config/uma/parts/server-configurator.json"
2121
]

packages/css/config/uma/parts/cli.json

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

packages/css/config/uma/parts/client.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"@id": "urn:solid-server:default:UmaFetcher"
1717
},
1818
"identifierStrategy": { "@id": "urn:solid-server:default:IdentifierStrategy" },
19-
"resourceSet": { "@id": "urn:solid-server:default:CachedResourceSet" }
19+
"resourceSet": { "@id": "urn:solid-server:default:CachedResourceSet" },
20+
"baseUrl":{ "@id": "urn:solid-server:default:variable:baseUrl" }
2021
}
2122
]
2223
}

packages/css/config/uma/parts/fetcher.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,11 @@
1010
"fetcher": {
1111
"@type": "RetryingFetcher",
1212
"fetcher": {
13-
"@type": "SignedFetcher",
14-
"fetcher": {
15-
"@type": "BaseFetcher"
16-
},
17-
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
18-
"keyGen": { "@id": "urn:solid-server:default:JwkGenerator" }
13+
"@type": "BaseFetcher"
1914
},
2015
"retries": 150,
2116
"exponent": 3,
22-
"retryOn": [401, 500]
17+
"retryOn": [500]
2318
}
2419
}
2520
]

packages/css/config/uma/parts/owner-util.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
"comment": "Provides utility for interacting with pod owner metadata",
99
"@id": "urn:solid-server:default:OwnerUtil",
1010
"@type": "OwnerUtil",
11+
"accountStorage": {
12+
"@id": "urn:solid-server:default:AccountStorage"
13+
},
14+
"accountStore": {
15+
"@id": "urn:solid-server:default:AccountStore"
16+
},
1117
"podStore": {
1218
"@id": "urn:solid-server:default:PodStore"
1319
},
1420
"storageStrategy": {
1521
"@id": "urn:solid-server:default:StorageLocationStrategy"
16-
},
17-
"umaServerURL": {
18-
"@id": "urn:solid-server:uma:variable:AuthorizationServer"
1922
}
2023
}
2124
]

0 commit comments

Comments
 (0)