-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
1,588 additions
and
33 deletions.
There are no files selected for viewing
This file contains 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,101 @@ | ||
# Keycloak | ||
|
||
This guide shows how to setup Papermerge + [Keyloak](https://keycloak.org) as OIDC identity | ||
provider. It was tested with Keycloak 24.0.2. | ||
|
||
To follow this guide you need one {{ extra.project }} and one Keycloak instance. | ||
For this guide we have: | ||
|
||
- http://keycloak.trusel.net:8080/ (Keycloak instance) | ||
- http://demo.trusel.net:12000/ ({{extra.project}} instance) | ||
|
||
Of course for your specific deployment you'll want to serve both apps over | ||
https, with valid certificates and without featuring ports in URLs, but for | ||
our guide we will skip those parts. | ||
|
||
First we will configure Keycloak, and then we will start {{ extra.project }} | ||
with correct environment variables. | ||
|
||
## Step 1 - Create Realm | ||
|
||
Create a new realm in Keycloak as described [here](https://www.keycloak.org/getting-started/getting-started-docker#_create_a_realm). We will name it "myrealm". | ||
|
||
|
||
## Step 2 - Create User | ||
|
||
In "myrealm" create a user, as described [here](https://www.keycloak.org/getting-started/getting-started-docker#_create_a_user) with following details: | ||
|
||
- username: bender | ||
- email: [email protected] | ||
- password: benderpass | ||
|
||
User "bender" will be administrative user in {{ extra.project }}. | ||
Let's create OIDC client. | ||
|
||
## Step 3 - Create OIDC Client | ||
|
||
Make sure you are currently in "myrealm". | ||
Click Clients -> Create client. | ||
Choose: | ||
|
||
- Client type: OpenID Connect | ||
- Client ID: papermerge | ||
- Client authentication: "ON" | ||
- Home URL: http://demo.trusel.net:12000 | ||
- Valid redirect URIs: http://demo.trusel.net:12000/oidc/callback | ||
|
||
Click "Save" | ||
|
||
Now, with OIDC Client saved, you can go to it's "Credentials" tab and | ||
note its "Client Secret". You will need it in next step. | ||
For this guide, the Client Secret is: | ||
|
||
- Client Secret: OHGMBgyAjcvDtn4PAu8w8vE9yf06aHn1 | ||
|
||
|
||
## Step 4 - Configure "username" Claim | ||
|
||
... by default JWT token does not contain "username" claim ... | ||
|
||
|
||
## Step 5 - Start Papermerge | ||
|
||
Now, start {{ extra.project }} with OIDC enabled, with following docker compose: | ||
|
||
```yaml | ||
version: "3.9" | ||
|
||
x-backend: &common | ||
image: papermerge/papermerge:{{extra.docker_image_version}} | ||
environment: | ||
PAPERMERGE__SECURITY__SECRET_KEY: super-secret-12345 | ||
PAPERMERGE__AUTH__USERNAME: bender | ||
PAPERMERGE__AUTH__EMAIL: [email protected] | ||
PAPERMERGE__AUTH__PASSWORD: 1234-not-relevant-but-still-needs-to-be-here | ||
PAPERMERGE__AUTH__OIDC_CLIENT_SECRET: OHGMBgyAjcvDtn4PAu8w8vE9yf06aHn1 | ||
PAPERMERGE__AUTH__OIDC_CLIENT_ID: papermerge | ||
PAPERMERGE__AUTH__OIDC_AUTHORIZE_URL: http://keycloak.trusel.net:8080/realms/myrealm/protocol/openid-connect/auth | ||
PAPERMERGE__AUTH__OIDC_ACCESS_TOKEN_URL: http://keycloak.trusel.net:8080/realms/myrealm/protocol/openid-connect/token | ||
PAPERMERGE__AUTH__OIDC_USER_INFO_URL: http://keycloak.trusel.net:8080/realms/myrealm/protocol/openid-connect/userinfo | ||
PAPERMERGE__AUTH__OIDC_LOGOUT_URL: http://keycloak.trusel.net:8080/realms/myrealm/protocol/openid-connect/logout | ||
PAPERMERGE__AUTH__OIDC_REDIRECT_URL: http://demo.trusel.net:12000/oidc/callback | ||
services: | ||
web: | ||
<<: *common | ||
ports: | ||
- "12000:80" | ||
worker: | ||
<<: *common | ||
command: worker | ||
``` | ||
Note that `PAPERMERGE__AUTH__OIDC_CLIENT_SECRET`, `PAPERMERGE__AUTH__OIDC_CLIENT_ID` should match | ||
their counterpart from step 3. | ||
|
||
`PAPERMERGE__AUTH__USERNAME` and `PAPERMERGE__AUTH__EMAIL` should match the user we created in step 2. As it was | ||
mentioned, we will use "bender" as administrative user in {{extra.project}}. | ||
Note that you need to specify `PAPERMERGE__AUTH__PASSWORD`, but whatever you put there is completely irrelevant | ||
because administrative user will login with password managed in Keyloak (in our example it is "benderpass"). | ||
|
||
`PAPERMERGE__AUTH__OIDC_REDIRECT_URL` should match "Valid redirect URIs" from Step 3 and it should be of | ||
format: `[http|https]://<papermerge-instance-domain>/oidc/callback`. |
This file contains 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,110 @@ | ||
# Overview | ||
|
||
OpenID Connect (OIDC) is an interoperable authentication protocol based on the OAuth | ||
2.0 framework of specifications. | ||
|
||
It is usual for organizations to use multiple software applications. Even a | ||
small home lab features dozens of different apps. | ||
|
||
Imagine a small home lab with 7 apps and each of those app uses separate | ||
authentication system. This means that the user of the home lab will need to | ||
keep 7 separate accounts: 7 separate users and 7 different passwords! | ||
|
||
Of course users will use various tricks to make their life easier, like register | ||
in all 7 accounts with same username and password. But still, they will need | ||
to sign in daily - 7 times :). | ||
|
||
Sticking with same home lab example, wouldn't it be great to have one | ||
single account with which user can sign in once and it will | ||
take effect across all 7 apps? In other words, wouldn't it be great | ||
to use single account for all application within home lab/organization/company ? | ||
|
||
Enter OIDC. | ||
|
||
OIDC solves above mentioned problem of multiple accounts hell. | ||
|
||
With OIDC, the accounts registration, authentication, accounts management | ||
(e.g. password management), is offloaded from the shoulders of the app to | ||
separate entity - **identity provider**. | ||
|
||
 | ||
|
||
!!! Note | ||
|
||
"Authenticate" means same as "sign in", "login". | ||
Verbs "authenticate", "sign in", "login" are used interchangeably | ||
|
||
|
||
With OIDC, instead of authenticating in each individual app, user | ||
authenticates with on identity provider (IP) side. To authenticate users, | ||
identity provider can employ various schemes like 2FA (two factor | ||
authentication). Once authentication is successful on the identity provider | ||
side, IP sends {{ extra.project }} a digitally signed token. All the | ||
subsequent requests to {{extra.project}} need to have that token, or otherwise | ||
they will be denied as not authorized. | ||
|
||
It may sounds abstract, because it is abstract. | ||
I think couple of illustration will clear the waters. | ||
|
||
|
||
First, in order to authenticate, OIDC enabled app ({{ extra.project }}) will | ||
redirect user to OIDC provider sign in page. On successful authentication | ||
{{ extra.project }} receives a token - so called jwt token. | ||
|
||
 | ||
|
||
In above illustration, for step 1 -> 2 to work `PAPERMERGE__AUTH__OIDC_AUTHORIZE_URL` setting | ||
is employed. For step 2 -> 3 to work `PAPERMERGE__AUTH__OIDC_REDIRECT_URL` is used. | ||
|
||
The trophy, which {{ extra.project }} receives from identity provider for | ||
successful sign in, is so call called [JWT token](https://jwt.io/). Users | ||
have no idea (and rightfully so) about JWT tokens, as all token business | ||
happens behind the scenes. | ||
|
||
|
||
!!! Note | ||
|
||
All processes described from here on, are not visible to the users. It all | ||
happens behind the scenes for them. Information which follows is | ||
meant for devs, DevOps, SREs. | ||
|
||
Your OIDC application needs JWT token as prove of | ||
successful authentication. As you may guess, JWt token will be carried inside | ||
each subsequent http requsts as http header. | ||
|
||
All incoming http requests are proved for validity of JWT token. If http request | ||
has valid JWT token - request is permitted to reach app. If http request does not | ||
contain valid JWT token - it is denied access to the app. | ||
|
||
|
||
!!! Note | ||
|
||
By "valid JWT token" is usually meant that it contain valid digital signature, | ||
it is not expired and maybe some other checks specific to identity provider. | ||
|
||
|
||
Following illustrations depict what happens with incoming requests: | ||
|
||
|
||
 | ||
|
||
 | ||
|
||
Inside {{ extra.project }} there is a "guard" which, for every incoming | ||
request, asks identity provider if respective HTTP request is valid or not. | ||
If identity provider says that JWT token is valid - request is permitted to pass, | ||
otherwise access is denied. | ||
This step is possible due to `PAPERMERGE__AUTH__OIDC_INTROSPECT_URL` setting. | ||
OIDC introspect endpoint is go to endpoint to inquiry for validity | ||
of the JWT token. | ||
|
||
The last technical detail to clarify, with high risk of diving in too many details, | ||
is: what is this "guard" thingy? | ||
"Guard" is nginx's | ||
[authorization based on sub-request result](https://nginx.org/en/docs/http/ngx_http_auth_request_module.html). | ||
In other words, there is nginx's "auth_request" for every incoming HTTP request and | ||
depending on it's response's status code the request is allowed to pass or not. | ||
|
||
|
||
That's all with OIDC theory. Now it is time to jump into | ||
specific examples. First example is [Papermerge + Keycloak](keycloak.md) as identity provider. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.