This repository was archived by the owner on Apr 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Various Documentation improvements #27
Merged
dmitrizagidulin
merged 17 commits into
solid:master
from
jaxoncreed:various-documentation
Aug 12, 2019
Merged
Changes from 5 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
a30c4c5
PoP tokens documentation
jaxoncreed c64b85b
Fix dmitri and michiel issues
jaxoncreed c10527b
Replaced wrongly identified RP with RS
jaxoncreed cf229ee
In depth documentation up to auth request
jaxoncreed 7bff76a
Update sequence Diagram
jaxoncreed 6e50af8
Finish the detailed application workflow
jaxoncreed 0f24e25
Change photo filename
jaxoncreed 0fa853b
Ruben fixes
jaxoncreed a7896c1
Fix typos and add more steps
jaxoncreed 481d930
Added steps for clarification
jaxoncreed d389c3e
Updated numbers
jaxoncreed 9237fdc
Fixed spellin/grammar
jaxoncreed 4990732
Capitalize OIDC
jaxoncreed ece65c9
Fix WebID Capitalization
jaxoncreed e1725a1
Small corrections
a54c0b4
Added link to Application Workflow Detailed
ed1aaaf
Changed file name to avoid confusion
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,7 @@ See also: [Motivation for WebID-OIDC](motivation.md). | |
### Benefits and Capabilities | ||
|
||
* Fully decentralized cross-domain authentication (any peer node can serve as | ||
an identity provider as well as a relying party to any other node) | ||
an identity provider as well as a relying party to any other node) made possible by [PoP Tokens](https://tools.ietf.org/html/rfc7800). | ||
* Builds on decades of real-world authentication industry experience | ||
* Incorporates lessons from, and fixes to threat models of: SAML, OpenID and | ||
OpenID 2, OAuth and OAuth 2. See, for example, [RFC 6819 - OAuth 2.0 Threat | ||
|
@@ -99,6 +99,8 @@ WebID-OIDC makes the following changes to the base OpenID Connect protocol | |
* Specifies the [Authorized OIDC Issuer | ||
Discovery](#authorized-oidc-issuer-discovery) process (used as part of | ||
Provider Confirmation, and during Provider Selection steps). | ||
* Utilizes [PoP tokens](https://tools.ietf.org/html/rfc7800) as a means to | ||
access a wide array of resource providers. | ||
|
||
It's also worth mentioning that while traditional OpenID Connect use cases are | ||
concerned with retrieving user-related claims from [UserInfo | ||
|
@@ -300,6 +302,24 @@ that profile, she would add the following triple to her profile: | |
<#me> solid:oidcIssuer <https://provider.com> . | ||
``` | ||
|
||
## Securing tokens for multiple resource servers | ||
|
||
#### The Problem | ||
|
||
Unlike standard implementations of OIDC, WebID-OIDC must deal with a number of RSs many of which the OP will not know about. OIDC defines the `aud` claim which defines the RSs for which a token can be used. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But we are using a standard, right? Important that people understand this is not a custom extension. |
||
|
||
However, given Solid's use case, a token should be usable for any RS so the user may federate a query across multiple Pods, so the `aud`ience cannot be constrained. Yet, an unconstrained `aud`ience opens up the possibility of token stealing. In this case, a user sends a request to `evilPod.example`. The Pod returns the requested information, but now has the user's token and may pretend to be the user on any other Pod in the world. | ||
|
||
#### The Solution | ||
|
||
The solution employs [Proof of Possession (PoP) tokens](https://tools.ietf.org/html/rfc7800) changing the way the Bearer token is constructed: | ||
|
||
1. A client application generates a short-lived public and private key. | ||
2. The client generates a request `JWT` just as it would under normal OIDC with the addition of a `key` field containing the public key. | ||
3. Authentication proceeds normally and yields a signed `id_token` where the `aud`ience is the client application (represented by the `origin` of the provided `redirect_uri`) and an additional field `cnf` is provided containing the client's public key. | ||
4. Before sending requests to any RSs, the client generates a new signed JWT PoP token containing the RS's uri as the `aud`ience and an `id_token` feild containing the `id_token` provided by the OP. | ||
5. When an RS receives the PoP token, it MUST reject any tokens containing a mismatched audience or a signature that is not associated with the public key in the `cnf` claim. | ||
|
||
## Detailed Sign In Workflow Example | ||
|
||
To walk through a more detailed example for WebID-OIDC login, refer to the | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
# Detailed Application Authentication | ||
|
||
This document outlines, in detail, the login and request process for an application using WebId-OIDC. In general, our user, *Alice* will be using a thrid-party application at `https://www.decentphotos.example` to access data on both her pod at `https://alice.example` and her friend, Bob's pod at `https://bob.example`. | ||
|
||
## Actors | ||
|
||
In this example a multitude of actors are at play: | ||
|
||
**Alice** - Alice will be providing consent for decentphotos to use her pod. Let's assume that Alice is using a standard web browser. | ||
|
||
**Bob's Pod (RS)** - We will be trying to access photos Bob's Pod, known in the OIDC world as a Resource Server (RS). Bob is a friend of Alice. For this use case, let's assume that Bob has previously indicated via access control that Alice may access his photo using any app. You can read more about access control [here](https://github.com/solid/web-access-control-spec#referring-to-origins-ie-web-apps). For this example, bob's pod is at `bob.solid.example`. | ||
justinwb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
**Alice's OP** - Alice's OpenID Provider (OP), also known as an IDP (Identity Provider), is the service responsible for authorizing our thrid-party app by providing it with the tokens necessary to gain access to any pod. In this demo, alice's OP is at `secureauth.example`. | ||
justinwb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
**Alice's Pod (RS)** - Alice's Pod is hosted at `alice.coolpod.example`, giving Alice the webId of `https://alice.coolpod.example/profile/card#me`. | ||
|
||
**Decent Photos (RP)** - decentphotos is a third party photo viewing application hosted at `https://www.decentphotos.example`. This app allows you to view your photos as well as your friend's photos. It will also perform cron jobs on the photos to detect faces. In the OIDC world this is known as the Relying Party (RP). | ||
|
||
## Application Flow | ||
|
||
 | ||
|
||
### Authorization | ||
|
||
Before any requests can be made, Alice must log in: | ||
|
||
#### 1. Alice naviages to www.decentphotos.example | ||
justinwb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Alice has heard of a great new site that allows her to view her friend's photos and tag faces. She navigates to `www.decentphotos.example` via he web browser which returns and html page. This page contains JavaScript that will help with the authorization process. | ||
|
||
#### 2. Alice clicks the "Connect" button | ||
|
||
Before decentphotos can start displaying images, Alice needs to start the process of providing consent. To do so, she must either provider her webId (`https://alice.coolpod.example/profile/card#me`) or the service the url of her OP (`https://secureauth.example`) | ||
justinwb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
While it is not the case with Alice, a user's Pod and OP can be hosted at the same domain. For example, Bob's pod could be `bob.solid.example` with a webId of `https://bob.solid.example/profile/card#me`, but his OP is at `https://solid.example`. | ||
|
||
#### 3. Request OP Configuration | ||
|
||
Now that Alice has indicated either her webId or her OP's url, the RP must make a request to retrieve the OP's configuration. | ||
|
||
If Alice entered her webId the request would be her webId's origin plus a path for the OIDC configuration: | ||
```bash | ||
GET https://alice.coolpod.example/.well-known/openid-configuration | ||
``` | ||
|
||
If Alice entered her OP's url, the RP would simply append the OIDC configuration to the end. | ||
|
||
``` | ||
GET https://secureauth.example/.well-known/openid-configuration | ||
``` | ||
|
||
#### 4. Returns OP Configuration | ||
|
||
Regardless of the what Alice entered, the response body should be the same. The [openid-configuration](https://auth0.com/docs/protocols/oidc/openid-connect-discovery) describes everything the client will need to know to authorize with Alice's specific OP. | ||
|
||
Response Body: | ||
```json | ||
{ | ||
"issuer":"https://secureauth.example", | ||
"authorization_endpoint":"https://secureauth.example/authorize", | ||
"token_endpoint":"https://secureauth.example/token", | ||
"userinfo_endpoint":"https://secureauth.example/userinfo", | ||
"jwks_uri":"https://secureauth.example/jwks", | ||
"registration_endpoint":"https://secureauth.example/register", | ||
"response_types_supported":[ | ||
"code", | ||
"code token", | ||
"code id_token", | ||
"id_token", | ||
"id_token token", | ||
"code id_token token", | ||
"none" | ||
], | ||
"response_modes_supported":[ | ||
"query", | ||
"fragment" | ||
], | ||
"grant_types_supported":[ | ||
"authorization_code", | ||
"implicit", | ||
"refresh_token", | ||
"client_credentials" | ||
], | ||
"subject_types_supported":[ | ||
"public" | ||
], | ||
"id_token_signing_alg_values_supported":[ | ||
"RS256", | ||
"RS384", | ||
"RS512", | ||
"none" | ||
], | ||
"token_endpoint_auth_methods_supported":[ | ||
"client_secret_basic" | ||
], | ||
"token_endpoint_auth_signing_alg_values_supported":[ | ||
"RS256" | ||
], | ||
"display_values_supported":[ | ||
|
||
], | ||
"claim_types_supported":[ | ||
"normal" | ||
], | ||
"claims_supported":[ | ||
|
||
], | ||
"claims_parameter_supported":false, | ||
"request_parameter_supported":true, | ||
"request_uri_parameter_supported":false, | ||
"require_request_uri_registration":false, | ||
"check_session_iframe":"https://secureauth.example/session", | ||
"end_session_endpoint":"https://secureauth.example/logout" | ||
} | ||
``` | ||
|
||
*RECOMMENDATION: It is recommended that this configuration is saved to local storage so that it does not need to be retrieved every time the RP needs to make a request to the OP* | ||
|
||
Currently in local storage: | ||
``` | ||
OPENID_CONFIGURATION | ||
``` | ||
|
||
|
||
#### 5. Generates a Private/Public key pair | ||
|
||
WebId-OIDC depends on [Proof of Posession (PoP) tokens](README.md#securing-tokens-for-multiple-resource-servers). PoP tokens ensure that third-party applications can send requests to any number of Pods, while ensuring that evil pods can't steal a user's token. | ||
|
||
The first step to generating a PoP token is generating a public and private key pair on the third-party RP. In our example, the private key is generated using `RSA256` and looks like: | ||
|
||
```json | ||
{ | ||
"alg":"RS256", | ||
"d":"UA69ET5dNnBYs1lbtNKEjozUXa3S5XYAjTkCcop1hxYAP4gM52iAkEQ0Jgs6CuVs74MxQM9vL__tMjH6KQ0sBvKTF_asnGYitftxBkABySwa-9bsDKtSrYO3F33Ctsiqp1WmZaT0eZi6rqjibm5ByYJRbyf9NDUI_farEaKoN6fTYGnIajNzzTKVm3PChbT4VyiOAADPGyJGOq5PX0oIbOHRG817NXYSZq8ZtDbm2_HoQwXjkSqz31d1UL8HKyghPWU4gBrkPyo_JWaoxbYlV5FGGXXUKBIvoaETf2-w5c7xNtpKJA7IS9IIKvZx-pVXP0nl5FjVC-I4ksQRY-FceQ", | ||
"dp":"Sa70sh4J65bbcDBEuHtx4wjxcsgDJjNHTbWc2B9HaZw49QF-sEI63SYezhF9DgR5oF_opEwjISAIv6bruHcb7Um7lxyxFV-iczR8NfO_wMhP9_EP8PyodBkX0YYQt2pBAizPwM_knKlRJOL3Dw5G2lnBDlzg6bWnA8oEM1UFvFk", | ||
"dq":"AmLtOjwwJPjt80yHGZc_OoFlKGDnm5m-5U8aS_kfIGbAFADYPuXacnMeOCVCthg8avCBgS68rC3hfNZeWkPnG2vXIiZqFLMPblQu6sjnlcvJS3peNQrJMs46ah6NJeUfLtniIcbveRu_CaosLwH_au5sPzpyStgELWiX5yV-bw", | ||
"e":"AQAB", | ||
"ext":true, | ||
"key_ops":[ | ||
"sign" | ||
], | ||
"kty":"RSA", | ||
"n":"qpm6eDf1JvcOmhX1icr--xrD2_mx-SxpqIDArguhEcnhVsA6usKjttars25H8fpc_rtN6qvdhHCRHxIafLZ0PtWeZ9-CCKNgMnYViBW-F5j70RXSBfJI8zal2UrQQycbBhmPi6ATTLHaQyVfDM_rFpRmR99wh4h6QR2fBRAX2_J9_lPvFMofmjcYcfaOT9l3TIoghfW2ma3oLkIG4La0MSScfwzPFuAjqr7xO-sRGYB9OQDbOHJpuXOw0FYb8wxuMZjBRzFsudjaxlzlpr1eR6a5sTA8tAIs0f3j0oZQts358mMxp4oRPstUuExvrZcIQ7XODi3AvMwjbbqd5b1How", | ||
"p":"1nWyuXZpF7DcAXOxGzsod-itCTEI1hYv4CGXQ5daSvbasF0tqs9LuRzpTEGokLlzPINNjTPqo-lUElLIhdMkQsdbeYdIwI6FqmxjHx30V1yQqhhCsTT8RKRaHoN53EQsqb1r1RyEzGT6mhll7M0fMVxMuHnHTBPhrvMM5Yj6C_k", | ||
"q":"y6U0YyN1uFukE34iCh2bQDU4l1qpgHN_r1UzsSOzLKAo6vlqlLMdbzA5Fn5JHlDWZE7QkBSeTi845_O64MB1G6YvVIQTtGFgdom_p_DKO8pdFo3lIv9p3SRoHafBe2xb_bBT4wXAA71hzbydug95pJ0PN5CBw2-seZcalHcxf3s", | ||
"qi":"ZK7ILqxNETFmBOA3xiBZiT7pylUqUCjbnxc_Jv_1I8QyiCwO5WPjPuCeclZiPPVSf7IlA3mY9hB7HB72d33zIeL8Esd95iFj_rr4SiiQ9V5sS_vo1roAbfApTNx2uT7Jdcp5Td_362971qbvZbj8kvrrvgi7Dv7jffIhKx9ez4w" | ||
} | ||
``` | ||
From now on we will refer to this as `RP_PRIVATE_KEY`. The public key looks like: | ||
|
||
```json | ||
{ | ||
"jwk":{ | ||
"alg":"RS256", | ||
"e":"AQAB", | ||
"ext":true, | ||
"key_ops":[ | ||
"verify" | ||
], | ||
"kty":"RSA", | ||
"n":"mVnn-HwEQi5mZR3Z0Wc7TBrJouOb7acKiseVSkjrj4mWCSEw21VTGNfovzUS71WYKoxFAd8zfkI9-lsAn3tkL8ppcMuI3F8KxsO86nNHSKrxZIlk-bP7RDFfpI9KWyifulKdipEmRit4iN-EFI2mK9KREscPWG083vqn4D81Xe4s0-gmRsBrVanwwu-mTwEKy8RFomV8CXOTcTNntdR3krluXZ38_uKBB1qg6_phBQwZ_sDMXWs8E90eCXhd_EQ6S8PGzCDPT2vg9wCB57ifAXt_8e4ZnqySmFPxegy7j3GcMuyhHzdpvv2fX5DvOxsgkjhsBzby9LD0bxStdBCSFQ" | ||
} | ||
} | ||
``` | ||
From now on we will refer to this as `RP_PUBLIC_KEY`. | ||
|
||
#### 6. Saves the Public/Private key to local storage | ||
|
||
The public/private key pair must be saved so that it can be referenced once the OP redirects back to the RP. It is recommended to save it to local storage, but that is not required. | ||
|
||
Currently in local storage: | ||
``` | ||
OPENID_CONFIGURATION | ||
RP_PRIVATE_KEY | ||
RP_PUBLIC_KEY | ||
``` | ||
|
||
#### 7. Requests OP JWKs | ||
|
||
Now that the RP's Public/Private keys are generated. The RP needs to be aware of the OP's public key. To do so a request should be made to the `jwks_uri` from the openid-configuration: | ||
|
||
``` | ||
GET https://secureauth.example/jwks | ||
``` | ||
|
||
#### 8. Returns OP JWKs | ||
|
||
The [JSON Web Key Set (JWKS)](https://auth0.com/docs/jwks) is returned. These will eventually be used to validate the signature of the token the OP will eventually issue. It is recommended that the result of this request should be saved to local storage. | ||
|
||
Response body: | ||
```json | ||
{ | ||
"keys":[ | ||
{ | ||
"kty":"RSA", | ||
"kid":"xeOjes9u3AcU4LBzcanEM7pZLwSlxaN7U62ZzOBDQuw", | ||
"alg":"RS256", | ||
"key_ops":[ | ||
"verify" | ||
], | ||
"e":"AQAB", | ||
"n":"oB2LgkiZZ5iLAz1d4ua7sVxdbzY2nIRkDtf4UE08mWsD6UYRzLR98_gMAfnKB8i9yPCQkxfA5w_SZq6Y7odG1qSwLHM2mb_O2GSvY9kaG00UpeeEJCR19c7Jkcmq3GXh4yujnm2TFQ6YAzYNgrXkHlusaFUApJaQN6zr4AvmR_vX_5i__Ku7nuU-GbaV75LSr8o0QANdYFF0ooz5DJvydPplF8mO9_oD7ceSNLWP1AXlFs5JH6MEhH02dELb4-zeLcVzhoqON60cABTpbYSf1lLbYZsVUQ3cYE9CxXaByY2YNuQgc0k29mSmUvwEs0hNA5xUcE3-y_qKpYKniErb9Q" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
Currently in local storage: | ||
``` | ||
OPENID_CONFIGURATION | ||
RP_PRIVATE_KEY | ||
RP_PUBLIC_KEY | ||
OP_JWKS | ||
``` | ||
|
||
#### 9. Sends Dynamic Registration Parameters | ||
|
||
Now we have everything we need to perform [dynamic client registration](https://openid.net/specs/openid-connect-registration-1_0.html). Because each Solid user could have a different OP, it is not feasible to expect the developers of RPs to manually register with every OP. Therefore, the client (RP) is registered dynamically. A request is sent to the OP's `registration_endpoint`: | ||
|
||
``` | ||
POST https://secureauth.example/register | ||
``` | ||
Data: | ||
```json | ||
{ | ||
grant_types: ["implicit"] | ||
issuer: "https://secureauth.example" | ||
redirect_uris: ["https://www.decentphotos.example/"] | ||
response_types: ["id_token token"] | ||
scope: "openid profile" | ||
} | ||
jaxoncreed marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
Each of these communicates something about the new client to the OP: | ||
- `grant_types`: A list of [OIDC grant types](http://docs.identityserver.io/en/latest/topics/grant_types.html) this client will use. `implicit` is great for web applications. | ||
- `issuer`: Alice's OP | ||
- `redirect_uris`: Redirect uris provided at the client registration stage state which redirect uris are valid during the authorization stage. | ||
- `response_types`: A list of [OIDC response types](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html) the client can use. `id_token token` means that // TODO: Ask Dmitri about wrapping an id_token in a pop token. Should it not be the access token? | ||
- `scope`: OIDC uses scope as a way of defining what a client can have acces to. However, Solid has it's own access control system, so scope will always be `openid profile` | ||
justinwb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#### 10: Saves Client Information | ||
|
||
The OP saves the client information to read later. | ||
|
||
#### 11: Returns successful registration | ||
|
||
The OP responds confirming the request, and with some new data. | ||
|
||
Response Body: | ||
```json | ||
{ | ||
"client_id":"7243fd594bdcf9c71a9b902274afaa30", | ||
"redirect_uris":[ | ||
"https://chat.o.team/" | ||
], | ||
"response_types":[ | ||
"id_token token" | ||
], | ||
"grant_types":[ | ||
"implicit" | ||
], | ||
"application_type":"web", | ||
"id_token_signed_response_alg":"RS256", | ||
"token_endpoint_auth_method":"client_secret_basic", | ||
"frontchannel_logout_session_required":false, | ||
"registration_access_token":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3NvbGlkLmNvbW11bml0eSIsInN1YiI6IjcyNDNmZDU5NGJkY2Y5YzcxYTliOTAyMjc0YWZhYTMwIiwiYXVkIjoiNzI0M2ZkNTk0YmRjZjljNzFhOWI5MDIyNzRhZmFhMzAifQ.gypiiq3K5_oRpEN7e1KaobI5CwWdrr7ZpwhdjUMneSEOEUVOwE0qeWlzu44j24eOIGeX8PzTc-f5ca0cRk22HSSRZIcAVo-GmGlZ4oAA5uGOuiEdncaF3ZKDv-0q1WXiyUFD_2hiiUrQwLtt-iSo3ZQOlCMP3opC6A73-b6UpOJTc9Q-V-sNTtOZ5IHpgOSkQZbgSuQr_vTGRLjoHl_v_8-AarjUIytbf_6h9iEFuPOyqugMUFALeNPBHSN8CTgJI3jcvx4HZtM9ByHNGGPjZv4TJrXy1sJIHokJkwdg1Pv_3mkUKVwtO4zxKAOu5MlspaZo6c-Oku__9S2mnu88xQ", | ||
"registration_client_uri":"https://solid.community/register/7243fd594bdcf9c71a9b902274afaa30", | ||
"client_id_issued_at":1557964995 | ||
} | ||
``` | ||
|
||
The main one to keep note of is the `client_id` which will be used to tie subsequent requests back to this registered client. | ||
|
||
This information should be saved to local storage. | ||
|
||
Currently in local storage: | ||
``` | ||
OPENID_CONFIGURATION | ||
RP_PRIVATE_KEY | ||
RP_PUBLIC_KEY | ||
OP_JWKS | ||
CLIENT_REGISTRATION_RESPONSE | ||
``` | ||
|
||
#### 12. Authorization Request | ||
|
||
// TODO complete explanation | ||
|
||
#### |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps say a word about what they are, or at least expand acronym?