From 4237caa755dd4bf1e2c9d02993ab42bb2bd55716 Mon Sep 17 00:00:00 2001 From: eikek <eike.kettner@posteo.de> Date: Mon, 6 Sep 2021 11:41:40 +0200 Subject: [PATCH] Add some documentation for OIDC --- .../src/main/resources/docspell-openapi.yml | 53 ++++++++++++ .../src/main/resources/reference.conf | 2 +- website/site/content/docs/api/intro.md | 8 ++ website/site/content/docs/configure/_index.md | 85 +++++++++++++++++++ website/site/content/docs/features/_index.md | 7 +- 5 files changed, 152 insertions(+), 3 deletions(-) diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index c6523a95..b6d5112c 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -42,6 +42,7 @@ paths: application/json: schema: $ref: "#/components/schemas/VersionInfo" + /open/auth/login: post: operationId: "open-auth-login" @@ -93,6 +94,51 @@ paths: application/json: schema: $ref: "#/components/schemas/AuthResult" + /open/auth/openid/{providerId}: + get: + operationId: "open-auth-openid" + tags: [ Authentication ] + summary: Authenticates via OIDC at the external provider given by its id + description: | + Initiates the ["Authorization Code + Flow"](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) + as described in the OpenID Connect specification. This only is + enabled, if an external provider has been configured correctly + in the config file. + + This will redirect to the external provider to authenticate + the user. Once authenticated, the user is redirected back to + the `/resume` endpoint. + parameters: + - $ref: "#/components/parameters/providerId" + responses: + 302: + description: Found. Redirect to external authentication provider + 200: + description: Not used, is only here because openid requires it + /open/auth/openid/{providerId}/resume: + get: + operationId: "open-auth-openid-resume" + tags: [ Authentication ] + summary: The callback URL for the authentication provider + description: | + This URL is used to redirect the user back to the application + by the authentication provider after login is completed. + + This will then try to find (or create) the account at docspell + using information about the user provided by the + authentication provider. If the required information cannot be + found, the user cannot be logged into the application. + + If the process completed successfully, this endpoint redirects + into the web application which will take over from here. + parameters: + - $ref: "#/components/parameters/providerId" + responses: + 303: + description: See Other. Redirect to the webapp + 200: + description: Not used, is only here because openid requires it /open/checkfile/{id}/{checksum}: get: @@ -6269,3 +6315,10 @@ components: some identifier for a client application schema: type: string + providerId: + name: providerId + in: path + required: true + schema: + type: string + format: ident diff --git a/modules/restserver/src/main/resources/reference.conf b/modules/restserver/src/main/resources/reference.conf index be13766a..2929f68d 100644 --- a/modules/restserver/src/main/resources/reference.conf +++ b/modules/restserver/src/main/resources/reference.conf @@ -134,7 +134,7 @@ docspell.server { provider-id = "keycloak", client-id = "docspell", client-secret = "example-secret-439e-bf06-911e4cdd56a6", - scope = "docspell", # scope is required for OIDC + scope = "profile", # scope is required for OIDC authorize-url = "http://localhost:8080/auth/realms/home/protocol/openid-connect/auth", token-url = "http://localhost:8080/auth/realms/home/protocol/openid-connect/token", #User URL is not used when signature key is set. diff --git a/website/site/content/docs/api/intro.md b/website/site/content/docs/api/intro.md index c6359ab0..cb232f53 100644 --- a/website/site/content/docs/api/intro.md +++ b/website/site/content/docs/api/intro.md @@ -44,6 +44,14 @@ must be `docspell_auth` and a custom header must be named The admin route (see below) `/admin/user/resetPassword` can be used to reset a password of a user. +### OpenID Connect + +Docspell can be configured to be a relying party for OpenID Connect. +Please see [the config +section](@/docs/configure/_index.md#openid-connect-oauth2) for +details. + + ## Admin There are some endpoints available for adminstration tasks, for diff --git a/website/site/content/docs/configure/_index.md b/website/site/content/docs/configure/_index.md index 4a8f14ea..9651f81a 100644 --- a/website/site/content/docs/configure/_index.md +++ b/website/site/content/docs/configure/_index.md @@ -342,6 +342,91 @@ The `session-valid` determines how long a token is valid. This can be just some minutes, the web application obtains new ones periodically. So a rather short time is recommended. +### OpenID Connect / OAuth2 + +You can integrate Docspell into your SSO solution via [OpenID +Connect](https://openid.net/connect/) (OIDC). This requires to set up +an OpenID Provider (OP) somewhere and to configure Docspell +accordingly to act as the relying party. + +You can define multiple OPs to use. For some examples, please see the +default configuration file [below](#rest-server). + +The configuration of a provider highly depends on how it is setup. +Here is an example for a setup using +[keycloak](https://www.keycloak.org): + +``` conf +provider = { + provider-id = "keycloak", + client-id = "docspell", + client-secret = "example-secret-439e-bf06-911e4cdd56a6", + scope = "profile", # scope is required for OIDC + authorize-url = "http://localhost:8080/auth/realms/home/protocol/openid-connect/auth", + token-url = "http://localhost:8080/auth/realms/home/protocol/openid-connect/token", + #User URL is not used when signature key is set. + #user-url = "http://localhost:8080/auth/realms/home/protocol/openid-connect/userinfo", + sign-key = "b64:MII…ZYL09vAwLn8EAcSkCAwEAAQ==", + sig-algo = "RS512" +} +``` + +The `provider-id` is some identifier that is used in the URL to +distinguish between possibly multiple providers. The `client-id` and +`client-secret` define the two parameters required for a "confidential +client". The different URLs are best explained at the [keycloak +docs](https://www.keycloak.org/docs/latest/server_admin/#_oidc-endpoints). +They are available for all OPs in some way. The `user-url` is not +required, if the access token is already containing the necessary +data. If not, then docspell performs another request to the +`user-url`, which must be the user-info endpoint, to obtain the +required user data. + +If the data is taken from the token directly and not via a request to +the user-info endpoint, then the token must be validated using the +given `sign-key` and `sig-algo`. These two values are then required to +specify! However, if the user-info endpoint should be used, then leave +the `sign-key` empty and specify the correct url in `user-url`. When +specifying the `sign-key` use a prefix of `b64:` if it is Base64 +encoded or `hex:` if it is hex encoded. Otherwise the unicode bytes +are used, which is most probably not wanted for this setting. + +Once the user is authenticated, docspell tries to setup an account and +does some checks. For this it must get to the username and collective +name somehow. How it does this, can be specified by the `user-key` and +`collective-key` settings: + +``` conf +# The collective of the user is given in the access token as +# property `docspell_collective`. +collective-key = "lookup:docspell_collective", +# The username to use for the docspell account +user-key = "preferred_username" +``` + +The `user-key` is some string that is used to search the JSON response +from the OP for an object with that key. The search happens +recursively, so the field can be in a nested object. The found value +is used as the user name. Keycloak transmits the `preferred_username` +when asking for the `profile` scope. This can be used as the user +name. + +The collective name can be obtained by different ways. For example, +you can instruct your OP (like keycloak) to provide a collective name +in the token and/or user-info responses. If you do this, then use the +`lookup:` prefix as in the example above. This instructs docspell to +search for a value the same way as the `user-key`. You can also set a +fixed collective, using `fixed:` prefix; in this case all users are in +the same collective! A third option is to prefix it with `account:` - +then the value that is looked up is interpreted as the full account +name, like `collective/user` and the `user-key` setting is ignored. If +you want to put each user in its own collective, you can just use the +same value as in `user-key`, only prefixed with `lookup:`. In the +example it would be `lookup:preferred_username`. + +If you find that these methods do not suffice for your case, please +open an issue. + ## File Processing diff --git a/website/site/content/docs/features/_index.md b/website/site/content/docs/features/_index.md index c1a6c1d0..029647c6 100644 --- a/website/site/content/docs/features/_index.md +++ b/website/site/content/docs/features/_index.md @@ -31,8 +31,11 @@ description = "A list of features and limitations." jobs, set priorities - Everything available via a [documented](https://www.openapis.org/) [REST Api](@/docs/api/_index.md); allows to [generate - clients](https://openapi-generator.tech/docs/generators) for - (almost) any language + clients](https://openapi-generator.tech/docs/generators) for many + languages +- [OpenID Connect](@/docs/configure/_index.md#openid-connect-oauth2) + support allows Docspell to integrate into your SSO setup, for + example with keycloak. - mobile-friendly Web-UI with dark and light theme - [Create anonymous “upload-urls”](@/docs/webapp/uploading.md#anonymous-upload) to