From 4f435b6ae669e5d373eac28e529f9f69f48733d1 Mon Sep 17 00:00:00 2001 From: George Fletcher Date: Mon, 30 Nov 2020 12:00:35 -0500 Subject: [PATCH 1/4] Create oidc_first-party-sso.md --- src/scenarios/oidc_first-party-sso.md | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/scenarios/oidc_first-party-sso.md diff --git a/src/scenarios/oidc_first-party-sso.md b/src/scenarios/oidc_first-party-sso.md new file mode 100644 index 0000000..c09cf60 --- /dev/null +++ b/src/scenarios/oidc_first-party-sso.md @@ -0,0 +1,50 @@ +## OpenID Connect - First Party SSO +Web property with multiple services that all use the same identity provider. + +### Summary + +##### Contributor +- Name: George Fletcher +- Organization: Verizon Media +- Email: gffletch@aol.com + +#### Protocol +- Name: OIDC +- Grant/flow (if applicable): AuthCode +- Reference: [aa](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) + +#### Browser Features Required +- 1st party Cookie +- Redirect with link decoration +- Local Storage +- JavaScript + +##### Target Audience +B2C + +#### Adoption +Unknown but I suspect this pattern is widely used. + +### Description Of The Flow +Provide single-sign-on services across a set of web domains managed by the same company. Take for example a company named Acme that runs multiple services in different geographical locations with multiple domains: service1.acme.example, service2.acme., service3.roadrunner.example. To manage the identity services across all these properties Acme runs idp.acme.example. + +Using OpenID Connect (OIDC) Acme can allow each property to request the user to authenticate as needed, and the user's single authentication can be shared across all the different properties. + +Generally, the user will visit a property (service1.acme.example) and either select the login option (or be immediately) redirected to idp.acme.example. As part of the HTTP redirect, service1.acme.example will set a cookie with an encrypted value containing the secret used to generate the OIDC state parameter (SHA256 has of the secret) and the value of the nonce parameter. This cookie should be explicitly set to samesite=lax and written on the service1.acme.example domain. + +When the user arrives at the login page, idp.acme.example will determine if the user is already logged in or not and if so, redirect the user to service1.acme.example with the OIDC authorization code and state values. If the user is not currently logged in, then the browser will display UI requesting the user to login. The UI will use JavaScript to determine if any users have logged into idp.acme.example from this browser in the past and if so present an "account chooser" experience. If not the user will be asked to enter their authentication credentials. Once the user has authenticated, the browser will be redirected to service1.acme.example with the authorization code and state values. + +When service1.example.com receives the redirect from idp.acme.example, it will first look for the encrypted cookie value it wrote when requesting the user to authenticate. It will then validate the state value to ensure this redirect is coming from the same browser where the request was initiated. Service1.example.com will also extrace the nonce value for comparison with the nonce in the id_token when it is retrieved. Note that if the state parameter validation fails, service1.acme.example will abort the authentication with an error. + +Once the state parameter has been validated, service1.acme.example will exchange the authorization code with idp.acme.example presenting it's own client credentials to prove it is the correct entity to be exchanging the authorization code for tokens. idp.acme.example will validate the client credentials and authorization code and if valid return an access token, optionally a refresh token and an id token per the OpenID Connect spec. + +Service1.acme.example will validate the id_token and verify that the nonce in the id_token matches the nonce extracted from the encrypted cookie. Now that service1.acme.example has valid tokens and an authenticated user, it writes a session cookie on the services1.acme.example domain identifying the user who authenticated. This cookie should also be set with the samesite=lax attribute. Note that it is out of scope for this description as to how the authentication session is referenced in the service1 specific cookie. However, it is important to note that just writing the session cookie on the *.acme.example domain may not be desired because the allowed authorization access of the user at service1.acme.com may be different than the allowed authorization access at service4.acme.com. + +### Intended User Experience +The goal of this user experience is to allow the user to share their authentication across all the properties managed by Acme. This scenario does not cover the use cases where the user is "seamlessly" recognized as being signed in and then silently authenticated to the site. That requires it's own use case document:) + +### Privacy Considerations +In order to provide the best user experience, idp.acme.example must be able to remember who has logged in from this browser in the past. This does leave some user data in the browser (i.e. local storage and persistent cookies) that will be used during the user's next visit to streamline the user experience. Most often this knowledge of what has happened in the past can be used by idp.acme.example to increase the concept of trust associated with this authentication event. + +### Miscellaneous +[todo] anything not fitting any of the sections above that is relevant for understanding how the scenario might be affected by browser changes. From 6f4a1ba71d7907329d473941b62b04628fcd1a0d Mon Sep 17 00:00:00 2001 From: George Fletcher Date: Tue, 1 Jun 2021 11:13:58 -0400 Subject: [PATCH 2/4] Shortened the description to just cover the redirect aspects of this flow. --- src/scenarios/oidc_first-party-sso.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/scenarios/oidc_first-party-sso.md b/src/scenarios/oidc_first-party-sso.md index c09cf60..e8531c0 100644 --- a/src/scenarios/oidc_first-party-sso.md +++ b/src/scenarios/oidc_first-party-sso.md @@ -15,6 +15,7 @@ Web property with multiple services that all use the same identity provider. #### Browser Features Required - 1st party Cookie +- 3rd party Cookie (cross-domain use case) - Redirect with link decoration - Local Storage - JavaScript @@ -32,19 +33,17 @@ Using OpenID Connect (OIDC) Acme can allow each property to request the user to Generally, the user will visit a property (service1.acme.example) and either select the login option (or be immediately) redirected to idp.acme.example. As part of the HTTP redirect, service1.acme.example will set a cookie with an encrypted value containing the secret used to generate the OIDC state parameter (SHA256 has of the secret) and the value of the nonce parameter. This cookie should be explicitly set to samesite=lax and written on the service1.acme.example domain. -When the user arrives at the login page, idp.acme.example will determine if the user is already logged in or not and if so, redirect the user to service1.acme.example with the OIDC authorization code and state values. If the user is not currently logged in, then the browser will display UI requesting the user to login. The UI will use JavaScript to determine if any users have logged into idp.acme.example from this browser in the past and if so present an "account chooser" experience. If not the user will be asked to enter their authentication credentials. Once the user has authenticated, the browser will be redirected to service1.acme.example with the authorization code and state values. +When the user arrives at the login page, idp.acme.example will determine if the user is already logged in and if so, immediately redirect the user to service1.acme.example with the OIDC authorization code and state values. If the user is not currently logged in, then the browser will display UI requesting the user to login. This UI uses Javascript to determine elements of the browser and possibly stored state. The user will be asked to enter their authentication credentials. Once the user has authenticated, the browser will be redirected to service1.acme.example with the authorization code and state values. When service1.example.com receives the redirect from idp.acme.example, it will first look for the encrypted cookie value it wrote when requesting the user to authenticate. It will then validate the state value to ensure this redirect is coming from the same browser where the request was initiated. Service1.example.com will also extrace the nonce value for comparison with the nonce in the id_token when it is retrieved. Note that if the state parameter validation fails, service1.acme.example will abort the authentication with an error. -Once the state parameter has been validated, service1.acme.example will exchange the authorization code with idp.acme.example presenting it's own client credentials to prove it is the correct entity to be exchanging the authorization code for tokens. idp.acme.example will validate the client credentials and authorization code and if valid return an access token, optionally a refresh token and an id token per the OpenID Connect spec. - -Service1.acme.example will validate the id_token and verify that the nonce in the id_token matches the nonce extracted from the encrypted cookie. Now that service1.acme.example has valid tokens and an authenticated user, it writes a session cookie on the services1.acme.example domain identifying the user who authenticated. This cookie should also be set with the samesite=lax attribute. Note that it is out of scope for this description as to how the authentication session is referenced in the service1 specific cookie. However, it is important to note that just writing the session cookie on the *.acme.example domain may not be desired because the allowed authorization access of the user at service1.acme.com may be different than the allowed authorization access at service4.acme.com. +The rest of the flow is standard OAuth/OpenID Connect for obtaining tokens and validating them (e.g. id_token nonce validation). Now that service1.acme.example has valid tokens and an authenticated user, it writes a session cookie on the services1.acme.example domain identifying the user who authenticated. This cookie should also be set with the samesite=lax attribute. Note that it is out of scope for this description as to how the authentication session is referenced in the service1 specific cookie. However, it is important to note that just writing the session cookie on the *.acme.example domain may not be desired because the allowed authorization access of the user at service1.acme.com may be different than the allowed authorization access at service4.acme.com. ### Intended User Experience -The goal of this user experience is to allow the user to share their authentication across all the properties managed by Acme. This scenario does not cover the use cases where the user is "seamlessly" recognized as being signed in and then silently authenticated to the site. That requires it's own use case document:) +The goal of this user experience is to allow the user to share their authentication across all the properties managed by Acme. ### Privacy Considerations -In order to provide the best user experience, idp.acme.example must be able to remember who has logged in from this browser in the past. This does leave some user data in the browser (i.e. local storage and persistent cookies) that will be used during the user's next visit to streamline the user experience. Most often this knowledge of what has happened in the past can be used by idp.acme.example to increase the concept of trust associated with this authentication event. +Since all parties involved in this flow are services offered by Acme, the user's privacy is covered under Acme's privacy policy. ### Miscellaneous -[todo] anything not fitting any of the sections above that is relevant for understanding how the scenario might be affected by browser changes. +This flow description is just to cover the redirect aspect of the sign-in experience. Other use cases will cover additional aspect such as how the IDP can associate trust with the user's authentication request, or how to help the user address the NASCAR issue. From cec22a2b6f7a151dc719caa7909b963b38546473 Mon Sep 17 00:00:00 2001 From: George Fletcher Date: Tue, 1 Jun 2021 17:43:27 -0400 Subject: [PATCH 3/4] Seq Diag + fixed typos Added sequence diagram and fixed a typo --- src/scenarios/oidc_first-party-sso.md | 61 ++++++++++++++++++++++++- src/scenarios/oidc_first-party-sso.puml | 27 +++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/scenarios/oidc_first-party-sso.puml diff --git a/src/scenarios/oidc_first-party-sso.md b/src/scenarios/oidc_first-party-sso.md index e8531c0..ba84f34 100644 --- a/src/scenarios/oidc_first-party-sso.md +++ b/src/scenarios/oidc_first-party-sso.md @@ -35,10 +35,69 @@ Generally, the user will visit a property (service1.acme.example) and either sel When the user arrives at the login page, idp.acme.example will determine if the user is already logged in and if so, immediately redirect the user to service1.acme.example with the OIDC authorization code and state values. If the user is not currently logged in, then the browser will display UI requesting the user to login. This UI uses Javascript to determine elements of the browser and possibly stored state. The user will be asked to enter their authentication credentials. Once the user has authenticated, the browser will be redirected to service1.acme.example with the authorization code and state values. -When service1.example.com receives the redirect from idp.acme.example, it will first look for the encrypted cookie value it wrote when requesting the user to authenticate. It will then validate the state value to ensure this redirect is coming from the same browser where the request was initiated. Service1.example.com will also extrace the nonce value for comparison with the nonce in the id_token when it is retrieved. Note that if the state parameter validation fails, service1.acme.example will abort the authentication with an error. +When service1.example.com receives the redirect from idp.acme.example, it will first look for the encrypted cookie value it wrote when requesting the user to authenticate. It will then validate the state value to ensure this redirect is coming from the same browser where the request was initiated. Service1.example.com will also extract the nonce value for comparison with the nonce in the id_token when it is retrieved. Note that if the state parameter validation fails, service1.acme.example will abort the authentication with an error. The rest of the flow is standard OAuth/OpenID Connect for obtaining tokens and validating them (e.g. id_token nonce validation). Now that service1.acme.example has valid tokens and an authenticated user, it writes a session cookie on the services1.acme.example domain identifying the user who authenticated. This cookie should also be set with the samesite=lax attribute. Note that it is out of scope for this description as to how the authentication session is referenced in the service1 specific cookie. However, it is important to note that just writing the session cookie on the *.acme.example domain may not be desired because the allowed authorization access of the user at service1.acme.com may be different than the allowed authorization access at service4.acme.com. +#### Sequence Diagram +``` + ┌───────┐ ┌─────────────────────┐ ┌────────────────┐ ┌───────────────────────────┐ + │browser│ │service1.acme.example│ │idp.acme.example│ │service3.roadrunner.example│ + └───┬───┘ └──────────┬──────────┘ └───────┬────────┘ └─────────────┬─────────────┘ + ╔═════════╧═══════════════════════════╧═════════════════════════════╧═══════════════════════════════════╧═════════╗ + ║Sign-in Process ░║ + ╚═════════╤═══════════════════════════╤═════════════════════════════╤═══════════════════════════════════╤═════════╝ + │ Click Sign-in Button │ │ │ + │──────────────────────────>│ │ │ + │ │ │ │ + │[redirect] set CSRF cookie │ │ │ + │samesite=lax │ │ │ + │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ │ │ + │ │ │ │ + │ Start authentication │ │ + │────────────────────────────────────────────────────────>│ │ + │ │ │ │ + │ │ │────┐ + │ │ │ │ Is the user already logged in? + │ │ │<───┘ + │ │ │ │ + │ │ │ ╔═════════════════════════════╗ │ + │ │ │ ║Validate User AuthN cookies ░║ │ + │ │ │ ╚═════════════════════════════╝ │ + │ │ │ │ + ╔══════╤══════╪═══════════════════════════╪═════════════════════════════╪═══════════════════════════════════╗ + ║ ALT │ User is NOT logged in │ │ ║ + ╟──────┘ │ │ │ ║ + ║ │ Request user to authenticate │ ║ + ║ │<────────────────────────────────────────────────────────│ ║ + ║ │ │ │ ║ + ║ │ User credentials │ ║ + ║ │────────────────────────────────────────────────────────>│ ║ + ║ │ │ │ ║ + ║ │ │ │────┐ ║ + ║ │ │ │ │ Validate User credentials ║ + ║ │ │ │<───┘ ║ + ║ │ │ │ ║ + ║ │ [redirect] Set User AuthN cookies │ ║ + ║ │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ ║ + ╠═════════════╪═══════════════════════════╪═════════════════════════════╪═══════════════════════════════════╣ + ║ │ │ │ ║ + ║ │ [redirect] │ ║ + ║ │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ ║ + ╚═════════════╪═══════════════════════════╪═════════════════════════════╪═══════════════════════════════════╝ + │ │ │ │ + │Authorization Code + state │ │ │ + │──────────────────────────>│ │ │ + │ │ │ │ + │ │ request tokens │ │ + │ │────────────────────────────>│ │ + │ │ │ │ + │ │ access, refresh, id tokens │ │ + │ │<────────────────────────────│ │ + ┌───┴───┐ ┌──────────┴──────────┐ ┌───────┴────────┐ ┌─────────────┴─────────────┐ + │browser│ │service1.acme.example│ │idp.acme.example│ │service3.roadrunner.example│ + └───────┘ └─────────────────────┘ └────────────────┘ └───────────────────────────┘ +``` ### Intended User Experience The goal of this user experience is to allow the user to share their authentication across all the properties managed by Acme. diff --git a/src/scenarios/oidc_first-party-sso.puml b/src/scenarios/oidc_first-party-sso.puml new file mode 100644 index 0000000..4937cd5 --- /dev/null +++ b/src/scenarios/oidc_first-party-sso.puml @@ -0,0 +1,27 @@ +@startuml +Participant "browser" as B +Participant "service1.acme.example" as RP1 +Participant "idp.acme.example" as IDP +Participant "service3.roadrunner.example" as RP2 + +note across +Sign-in Process +end note + +B->RP1: Click Sign-in Button +RP1-->B: [redirect] set CSRF cookie\nsamesite=lax +B->IDP: Start authentication +IDP->IDP: Is the user already logged in? +note right of IDP: Validate User AuthN cookies +alt User is NOT logged in + IDP->B: Request user to authenticate + B->IDP: User credentials + IDP->IDP: Validate User credentials + IDP-->B: [redirect] Set User AuthN cookies +else + IDP-->B: [redirect] +end +B->RP1: Authorization Code + state +RP1->IDP: request tokens +IDP->RP1: access, refresh, id tokens +@enduml \ No newline at end of file From 24da0a01a738be757cf5b3f96ceff48c14a6b0af Mon Sep 17 00:00:00 2001 From: George Fletcher Date: Tue, 20 Jul 2021 17:13:07 -0400 Subject: [PATCH 4/4] Start of seguencew diagram patterns --- src/scenarios/Use Case Patterns.puml | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/scenarios/Use Case Patterns.puml diff --git a/src/scenarios/Use Case Patterns.puml b/src/scenarios/Use Case Patterns.puml new file mode 100644 index 0000000..14b9ffd --- /dev/null +++ b/src/scenarios/Use Case Patterns.puml @@ -0,0 +1,29 @@ +@startuml +'https://plantuml.com/sequence-diagram' + +/' Should all sequence diagrams have a title? '/ +title "Sequence Diagram Patterns" +/' Should we autonumber sequences? '/ +autonumber + +/' Should we encourage use of Participant commands? '/ +participant "Browser" as UA +participant "Relying Party" as RP +participant "Identity Provider" as IDP + +note across: Request/Response Pattern +UA ->o RP: Authentication Request +RP->UA: Authentication Response + +/' Should we be explicit about redirects? '/ +note across: Redirect Pattern +UA->RP: login +RP-->UA: redirect to IDP\nSet-Cookie: CSRF +UA->IDP: /authorize + +group iframe 1 [iframe from IDP] +IDP-->UA: load iframe to RP logout URL +UA->RP: /logout +RP->UA: Set-Cookie: \nreturn empty content +end +@enduml \ No newline at end of file