From 4cb105178b8c706efbcd30152b2e421a815a15d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 6 May 2020 15:47:19 +0200 Subject: [PATCH 1/2] update login flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- docs/login-flow.md | 80 +++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/docs/login-flow.md b/docs/login-flow.md index 2175206f0..ab450d901 100644 --- a/docs/login-flow.md +++ b/docs/login-flow.md @@ -10,7 +10,7 @@ geekdocFilePath: login-flow.md ## Login Flow -The following sequence diagram describes the [openid connect auth flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth): +The following sequence diagram describes the [openid connect auth code flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth). The eight numbered steps and notes correspond to the [openid connect auth code flow steps](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowSteps). Example requests are based on the spec as well.: {{< mermaid class="text-center">}} sequenceDiagram @@ -21,8 +21,7 @@ sequenceDiagram participant user as User participant client as Client participant proxy as ocis-proxy - participant idp as external IdP - participant konnectd as ocis-konnectd IdP + participant idp as IdP participant glauth as ocis-glauth participant graph as ocis-graph participant accounts as ocis-accounts @@ -31,26 +30,33 @@ sequenceDiagram user->>+client: What is the content of my home? client->>+proxy: PROPFIND
no (or expired) auth - alt proxy can decide which idp to use - Note over client, idp: We may not be able to differentiate guests from users - proxy-->>client: 302 Found - Note over client, idp: HTTP/1.1 302 Found
Location: https://server.example.com/authorize?
response_type=code&
scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb - else client needs to discover the idp - proxy-->>-client: 401 Unauthorized - Note over client, idp: Follow OpenID Connect Discovery protocol - Note over client, idp: Clients might fall back to the ocis server if the discovery failed.
We can provide a webfinger endpoint there to let guests use an idp
that is backed bythe accounts service. - Note over client, idp: For now, always use ocis well known endpoint to discover idp?
We can check the email in the accounts service. - end + Note over client,proxy: ocis needs to know the IdP that is
used to authenticate users. The
proxy will redirect unauthenticated
requests to that IdP. + proxy-->>-client: 302 Found + Note over client, idp: HTTP/1.1 302 Found
Location: https://server.example.com/authorize?
response_type=code&
scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb + + Note over client, idp: We should follow the OpenID Connect Discovery protocol + Note over client, idp: Clients might fall back to the ocis server if the discovery failed.
We can provide a webfinger endpoint there to let guests use an idp
that is backed by the accounts service. + Note over client, idp: For now, clients can only handle one IdP, which is configured in ocis. client-->>client: 1. Client prepares an Authentication Request
containing the desired request parameters. - alt all users authenticated by an external idp - client->>+idp: 2. Client sends the request to the Authorization Server. - Note over client, idp: GET /authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com - Note over user, idp: 3. Authorization Server Authenticates the End-User. + client->>+idp: 2. Client sends the request to the Authorization Server. + Note over client, idp: GET /authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com + Note over user, idp: 3. Authorization Server Authenticates the End-User. + Note over idp,ldap: Either an IdP already exists or a new one is introduced. Since we are not yet using oidc discovery we can only use one IdP. + alt all users managed by konnectd/ocis + idp->>+glauth: LDAP query/bind + glauth->>+graph: GET user with Basic Auth
GraphAPI + graph->>+accounts: internal GRPC + accounts-->>-graph: response + graph-->>-glauth: OData response + glauth-->>-idp: LDAP result + Note over accounts,ldap: In case internal users are managed
in an external ldap they have to be
synced to the accounts service to
show up as recipients during sharing. + else all users authenticated by an external idp idp->>+ldap: LDAP query/bind ldap-->>-idp: LDAP result alt guest accounts managed in ocis / lookup using glauth proxy: + Note over idp,glauth: Idp is configured to use glauth as a
second ldap server. idp->>+glauth: LDAP query/bind glauth->>+graph: GET user with Basic Auth
GraphAPI graph->>+accounts: internal GRPC @@ -58,38 +64,18 @@ sequenceDiagram graph-->>-glauth: OData response glauth-->>-idp: LDAP result else guest account provisioned by other means - Note over idp, ldap: In case guest accounts are stored in an existing ldap they need to be synced to the accounts service to show up as recipients during sharing. + Note over accounts, ldap: In case guest accounts are managed
in an existing ldap they need to be
synced to the accounts service to
be able to login and show up as
recipients during sharing. end - - Note over user, idp: 4. Authorization Server obtains End-User Consent/Authorization. - idp-->>-client: 5. Authorization Server sends the End-User back
to the Client with an Authorization Code. - Note over client, idp: HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj - - client->>+idp: 6. Client requests a response using the
Authorization Code at the Token Endpoint. - Note over client, idp: POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb - idp-->>-client: 7. Client receives a response that contains an
ID Token and Access Token in the response body. - Note over client, idp: HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "a ... b.c ... d.e ... f" // must be a JWT
} - else all users managed by konnectd/ocis - client->>+konnectd: 2. Client sends the request to the Authorization Server. - Note over client, konnectd: GET /authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com - Note over user, konnectd: 3. Authorization Server Authenticates the End-User. - konnectd->>+glauth: LDAP query/bind - glauth->>+graph: GET user with Basic Auth
GraphAPI - graph->>+accounts: internal GRPC - accounts-->>-graph: response - graph-->>-glauth: OData response - glauth-->>-konnectd: LDAP result - Note over konnectd,ldap: In case the internal users come from an external ldap they have to be synced to the accounts service to show up as recipients during sharing. - - Note over user, konnectd: 4. Authorization Server obtains End-User Consent/Authorization. - konnectd-->>-client: 5. Authorization Server sends the End-User back
to the Client with an Authorization Code. - Note over client, konnectd: HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj - - client->>+konnectd: 6. Client requests a response using the
Authorization Code at the Token Endpoint. - Note over client, konnectd: POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb - konnectd-->>-client: 7. Client receives a response that contains an
ID Token and Access Token in the response body. - Note over client, konnectd: HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "a ... b.c ... d.e ... f" // must be a JWT
} end + Note over user, idp: 4. Authorization Server obtains End-User Consent/Authorization. + idp-->>-client: 5. Authorization Server sends the End-User back
to the Client with an Authorization Code. + Note over client, idp: HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj + + client->>+idp: 6. Client requests a response using the
Authorization Code at the Token Endpoint. + Note over client, idp: POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb + idp-->>-client: 7. Client receives a response that contains an
ID Token and Access Token in the response body. + Note over client, idp: HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "a ... b.c ... d.e ... f" // must be a JWT
} + client-->>client: 8. Client validates the ID token and
retrieves the End-User's Subject Identifier. From d7848526c0c7ceb4deeac6a22e30abf1985a0bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 6 May 2020 16:49:34 +0200 Subject: [PATCH 2/2] update request flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- docs/request-flow.md | 84 +++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/docs/request-flow.md b/docs/request-flow.md index 32bb12192..ed2d9a693 100644 --- a/docs/request-flow.md +++ b/docs/request-flow.md @@ -10,7 +10,7 @@ geekdocFilePath: request-flow.md ## Request Flow -The following sequence diagram describes the general request flow: +The following sequence diagram describes the general request flow. It shows where account provisioning and token minting are happening: {{< mermaid class="text-center">}} sequenceDiagram @@ -25,51 +25,71 @@ sequenceDiagram user->>+client: What is the content of my home? client->>+proxy: PROPFIND
Bearer auth using oidc auth token - Note right of client: What is in a bearer token?
The spec recommends opaque tokens.
So it is just random byte noise. + Note over client,proxy: What is in a bearer token?
The spec recommends opaque tokens.
Treat it as random byte noise. + Note over client,proxy: the proxy MUST authenticate users
using ocis-accounts because it needs
to decide where to send the request %% Mention introspection endpoint for opaque tokens %% konnectd uses jwt, so we can save a request %% either way the token can be used to look up the sub and iss of the user %% or is token check enough? proxy->>+idp: GET /userinfo - idp-->>-proxy: JSON response - Note right of proxy: the result contains
the sub of the user - %% see: https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse + alt userinfo succeeds - proxy->>+accounts: TODO API call to exchange sub@iss with account UUID + idp-->>proxy: 200 OK + Note over proxy,accounts: Content-Type: application/json
{
"sub": "248289761001",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe",
"preferred_username": "j.doe",
"email": "janedoe@example.com",
"picture": "http://example.com/janedoe/me.jpg"
} + %% see: https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse - alt internal account - accounts->>+ldap: is user allowed to use ocis - ldap-->>-accounts: yes/no - group based - else guest account - accounts->>accounts: check if is valid guest account - end + else userinfo fails + idp-->>-proxy: 401 Unauthorized + Note over proxy,accounts: WWW-Authenticate: error="invalid_token",
error_description="The Access Token expired" - accounts-->>-proxy: new or existing account UUID / error - Note right of accounts: actually this provisions
the account including
displayname, email and
sub@iss if the user is
allowed to login, based
on group membership
in the ldap server - - - Note right of proxy: the proxy MUST
authenticate users
using ocis-accounts
because it needs to
decide where to
send the request - - Note right of proxy: forward request to
ocis or oc10 - %% what if oc10 does not support a certain request / API - alt user is migrated - - Note right of proxy: mint an internal jwt
token that includes
the UUID and username - proxy->>+reva: PROPFIND
Bearer auth using internal JWT - reva-->>-proxy: Multistatus response - - else user is not migrated - - Note right of proxy: forward existing bearer auth? - proxy->>+oc10: PROPFIND
Bearer auth using internal JWT - %% TODO auth using internal token? - oc10-->>-proxy: Multistatus response + proxy-->>client: 401 Unauthorized or
302 Found with redirect to idp + Note over client: start at login flow
or refresh the token end + proxy->>+accounts: TODO API call to exchange sub@iss with account UUID + Note over proxy,accounts: does not autoprovision users. They are explicitly provsioned later. + alt account exists or has been migrated + + accounts-->>proxy: existing account UUID + else account does not exist + + opt oc10 endpoint is configured + Note over proxy,oc10: Check if user exists in oc10 + proxy->>+oc10: GET /apps/graphapi/v1.0/users/ + opt user exists in oc10 + oc10-->>-proxy: 200 + %% TODO auth using internal token + proxy->>+oc10: PROPFIND + Note over proxy,oc10: forward existing bearer auth + oc10-->>-proxy: Multistatus response + proxy-->>client: Multistatus response + client-->>user: List of Files X, Y, Z ... + end + end + + Note over proxy,accounts: provision a new account including displayname, email and sub@iss
TODO only if the user is allowed to login, based on group
membership in the ldap server + proxy->>proxy: generate new uuid + proxy->>+accounts: TODO create account with new generated uuid + accounts-->>-proxy: OK / error + + else account has been disabled + + accounts-->>-proxy: account is disabled + proxy-->>client: 401 Unauthorized or
302 Found with redirect to idp + Note over client: start at login flow
or refresh the token + + end + proxy->>proxy: store uuid in context + + %% what if oc10 does not support a certain request / API + + proxy->>proxy: mint an internal jwt that includes the UUID and username using revas `x-access-token` header + proxy->>+reva: PROPFIND
Token auth using internal JWT + reva-->>-proxy: Multistatus response proxy-->>-client: Multistatus response client-->>-user: List of Files X, Y, Z ...