mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-29 20:33:55 +02:00
516 lines
16 KiB
Markdown
516 lines
16 KiB
Markdown
# OAuth2
|
|
|
|
OAuth is a web authorisation protocol that allows "single sign on". It's key to note OAuth only
|
|
provides authorisation, as the protocol in its default forms do not provide identity or
|
|
authentication information. All that OAuth can provide is information that an entity is authorised
|
|
for the requested resources.
|
|
|
|
OAuth can tie into extensions allowing an identity provider to reveal information about authorised
|
|
sessions. This extends OAuth from an authorisation only system to a system capable of identity and
|
|
authorisation. Two primary methods of this exist today: RFC7662 token introspection, and OpenID
|
|
connect.
|
|
|
|
## Resource Server and Clients
|
|
|
|
This is the resource that a user wants to access. Common [examples](oauth2/examples.md) could be
|
|
Nextcloud, a Wiki, or a chat service. In these cases the service is both the _client_ and the
|
|
_resource server_ within the OAuth2 workflow. We will refer to the combination of both client and
|
|
resource server as a service.
|
|
|
|
It's important for you to know _how_ your service will interact with OAuth2. For example, does it
|
|
rely on OpenID connect for identity information, or does it support RFC7662 token introspection?
|
|
|
|
In general, Kanidm **requires** that your service supports three things:
|
|
|
|
* HTTP basic authentication to the authorisation server (Kanidm)
|
|
|
|
* PKCE `S256` code verification (`code_challenge_methods_supported`)
|
|
|
|
* If it uses OIDC, `ES256` for token signatures
|
|
(`id_token_signing_alg_values_supported`)
|
|
|
|
If your service doesn't support PKCE or only supports `RS256` token signatures,
|
|
see [extended options for legacy clients](#extended-options-for-legacy-clients).
|
|
|
|
Kanidm issues tokens which are
|
|
[RFC 9068 JWTs](https://datatracker.ietf.org/doc/html/rfc9068), allowing service
|
|
introspection.
|
|
|
|
> [!NOTE]
|
|
>
|
|
> Previous versions of this document incorrectly described "clients" as
|
|
> "resource servers" due to clarity issues in the OAuth2 RFC.
|
|
|
|
## Kanidm's OAuth2 URLs
|
|
|
|
Kanidm will expose its OAuth2 APIs at the following URLs, substituting
|
|
`:client_id:` with an OAuth2 client ID.
|
|
<!-- markdownlint-disable MD033 -->
|
|
|
|
<dl>
|
|
|
|
<dt>
|
|
|
|
[OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)
|
|
URL **(recommended)**
|
|
|
|
</dt>
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/openid/:client_id:/.well-known/openid-configuration`
|
|
|
|
This document includes all the URLs and attributes an app needs to be able to
|
|
authenticate using OIDC with Kanidm, _except_ for the `client_id` and
|
|
`client_secret`.
|
|
|
|
Use this document wherever possible, as it will allow you to easily build and/or
|
|
configure an interoperable OIDC client without needing to code or configure
|
|
anything special for Kanidm (or another provider).
|
|
|
|
**Note:** some apps automatically append `/.well-known/openid-configuration` to
|
|
the end of an OIDC Discovery URL, so you may need to omit that.
|
|
|
|
<dt>
|
|
|
|
[RFC 8414 OAuth 2.0 Authorisation Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414)
|
|
URL **(recommended)**
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/openid/:client_id:/.well-known/oauth-authorization-server`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
[WebFinger URL **(discouraged)**](#webfinger)
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/openid/:client_id:/.well-known/webfinger`
|
|
|
|
See [the WebFinger section](#webfinger) for more details, as there a number of
|
|
caveats for WebFinger clients.
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
User auth
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/ui/oauth2`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
API auth
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/authorise`
|
|
|
|
**Note:** "authorise" is spelled the British English (non-OED) way.
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
Token endpoint
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/token`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
[RFC 7662 Token Introspection](https://datatracker.ietf.org/doc/html/rfc7662) URL
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/token/introspect`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
[RFC 7662 token revocation](https://datatracker.ietf.org/doc/html/rfc7009) URL
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/token/revoke`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
OpenID Connect issuer URI
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/openid/:client_id:`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
OpenID Connect user info
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/openid/:client_id:/userinfo`
|
|
|
|
</dd>
|
|
|
|
<dt>
|
|
|
|
Token signing public key
|
|
|
|
</dt>
|
|
|
|
<dd>
|
|
|
|
`https://idm.example.com/oauth2/openid/:client_id:/public_key.jwk`
|
|
|
|
</dd>
|
|
|
|
</dl>
|
|
|
|
<!-- markdownlint-enable MD037 -->
|
|
|
|
## Configuration
|
|
|
|
### Create the Kanidm Configuration
|
|
|
|
By default, members of the `idm_admins` or `idm_oauth2_admins` groups are able to create
|
|
or manage OAuth2 client integrations.
|
|
|
|
You can create a new client by specifying its client name, application display name and the landing
|
|
page (home page) of the client. The landing page is where users will be redirected to from the
|
|
Kanidm application portal.
|
|
|
|
```bash
|
|
kanidm system oauth2 create <name> <displayname> <landing page url>
|
|
kanidm system oauth2 create nextcloud "Nextcloud Production" https://nextcloud.example.com
|
|
```
|
|
|
|
You must now configure the redirect URL where the application expects OAuth2 requests to be sent.
|
|
|
|
```bash
|
|
kanidm system oauth2 add-redirect-url <name> <redirect url>
|
|
kanidm system oauth2 add-redirect-url nextcloud https://nextcloud.example.com/oauth2/handler
|
|
```
|
|
|
|
You can create a scope map with:
|
|
|
|
```bash
|
|
kanidm system oauth2 update-scope-map <name> <kanidm_group_name> [scopes]...
|
|
kanidm system oauth2 update-scope-map nextcloud nextcloud_users email profile openid
|
|
```
|
|
|
|
> [!TIP]
|
|
>
|
|
> OpenID connect allows a number of scopes that affect the content of the resulting authorisation
|
|
> token. If one of the following scopes are requested by the OpenID client, then the associated
|
|
> claims may be added to the authorisation token. It is not guaranteed that all of the associated
|
|
> claims will be added.
|
|
>
|
|
> * **profile** - name, family_name, given_name, middle_name, nickname, preferred_username, profile,
|
|
> picture, website, gender, birthdate, zoneinfo, locale, and updated_at
|
|
> * **email** - email, email_verified
|
|
> * **address** - address
|
|
> * **phone** - phone_number, phone_number_verified
|
|
> * **groups** - groups
|
|
>
|
|
> In addition Kanidm supports some vendor specific scopes that can include additional claims.
|
|
>
|
|
> * **ssh_publickeys** - array of ssh_publickey of the user
|
|
|
|
<!-- this is just to split the templates up -->
|
|
|
|
> [!WARNING]
|
|
>
|
|
> If you are creating an OpenID Connect (OIDC) client you **MUST** provide a scope map containing
|
|
> `openid`. Without this, OpenID Connect clients **WILL NOT WORK**!
|
|
>
|
|
> ```bash
|
|
> kanidm system oauth2 update-scope-map nextcloud nextcloud_users openid
|
|
> ```
|
|
|
|
You can create a supplemental scope map with:
|
|
|
|
```bash
|
|
kanidm system oauth2 update-sup-scope-map <name> <kanidm_group_name> [scopes]...
|
|
kanidm system oauth2 update-sup-scope-map nextcloud nextcloud_admins admin
|
|
```
|
|
|
|
Once created you can view the details of the client.
|
|
|
|
```bash
|
|
kanidm system oauth2 get nextcloud
|
|
---
|
|
name: nextcloud
|
|
class: oauth2_resource_server
|
|
class: oauth2_resource_server_basic
|
|
class: object
|
|
displayname: Nextcloud Production
|
|
oauth2_rs_basic_secret: hidden
|
|
oauth2_rs_origin_landing: https://nextcloud.example.com
|
|
oauth2_rs_token_key: hidden
|
|
```
|
|
|
|
You can see the value of `oauth2_rs_basic_secret` with:
|
|
|
|
```bash
|
|
kanidm system oauth2 show-basic-secret nextcloud
|
|
---
|
|
<secret>
|
|
```
|
|
|
|
### Configure the Client/Resource Server
|
|
|
|
On your client, you should configure the client ID as the `name` from Kanidm, and the password to be
|
|
the value shown in `oauth2_rs_basic_secret`. Ensure that the code challenge/verification method is
|
|
set to S256.
|
|
|
|
You should now be able to test authorisation to the client.
|
|
|
|
## Scope Relationships
|
|
|
|
For an authorisation to proceed, the client will request a list of scopes. For example, when a user
|
|
wishes to login to the admin panel of the resource server, it may request the "admin" scope from
|
|
Kanidm for authorisation. But when a user wants to login, it may only request "access" as a scope
|
|
from Kanidm.
|
|
|
|
As each service may have its own scopes and understanding of these, Kanidm isolates scopes to each
|
|
service connected to Kanidm. Kanidm has two methods of granting scopes to accounts (users).
|
|
|
|
The first is scope mappings. These provide a set of scopes if a user is a member of a specific group
|
|
within Kanidm. This allows you to create a relationship between the scopes of a service, and the
|
|
groups/roles in Kanidm which can be specific to that service.
|
|
|
|
For an authorisation to proceed, all scopes requested by the client must be available in the final
|
|
scope set that is granted to the account.
|
|
|
|
The second part is supplemental scope mappings. These function the same as scope maps where
|
|
membership of a group provides a set of scopes to the account. However these scopes are NOT
|
|
consulted during authorisation decisions made by Kanidm. These scopes exist to allow optional
|
|
properties to be provided (such as personal information about a subset of accounts to be revealed)
|
|
or so that the service may make its own authorisation decisions based on the provided scopes.
|
|
|
|
This use of scopes is the primary means to control who can access what resources. These access
|
|
decisions can take place either on Kanidm or the service.
|
|
|
|
For example, if you have a client that always requests a scope of "read", then users with scope maps
|
|
that supply the read scope will be allowed by Kanidm to proceed to the service. Kanidm can then
|
|
provide the supplementary scopes into provided tokens, so that the service can use these to choose
|
|
if it wishes to display UI elements. If a user has a supplemental "admin" scope, then that user may
|
|
be able to access an administration panel of the service. In this way Kanidm is still providing the
|
|
authorisation information, but the control is then exercised by the service.
|
|
|
|
## Public Client Configuration
|
|
|
|
Some applications are unable to provide client authentication. A common example is single page web
|
|
applications that act as the OAuth2 client and its corresponding webserver is the resource server.
|
|
In this case, the SPA is unable to act as a confidential client since the basic secret would need to
|
|
be embedded in every client.
|
|
|
|
For this reason, public clients require PKCE to bind a specific browser session to its OAuth2
|
|
exchange. PKCE can not be disabled for public clients for this reason.
|
|
|
|
To create an OAuth2 public client:
|
|
|
|
```bash
|
|
kanidm system oauth2 create-public <name> <displayname> <origin>
|
|
kanidm system oauth2 create-public mywebapp "My Web App" https://webapp.example.com
|
|
```
|
|
|
|
## Native Applications
|
|
|
|
Some applications will run a local web server on the user's device which directs users to the IDP for
|
|
authentication, then back to the local server. [BCP212](https://www.rfc-editor.org/info/bcp212)
|
|
"OAuth 2.0 for Native Apps" specifies the rules for this.
|
|
|
|
First allow localhost redirects:
|
|
|
|
```bash
|
|
kanidm system oauth2 enable-localhost-redirects <name>
|
|
kanidm system oauth2 disable-localhost-redirects <name>
|
|
kanidm system oauth2 enable-localhost-redirects mywebapp
|
|
```
|
|
|
|
> [!WARNING]
|
|
>
|
|
> Kanidm only allows these to be enabled on public clients where PKCE is enforced.
|
|
|
|
## Alternate Redirect URLs
|
|
|
|
> [!WARNING]
|
|
>
|
|
> Security Risk!
|
|
>
|
|
> You **MUST NOT** share a single OAuth2 client definition between multiple applications.
|
|
>
|
|
> The ability to configure multiple redirect URLs is **NOT** intended to allow you to share a single
|
|
> Kanidm client definition between multiple OAuth2 clients.
|
|
>
|
|
> Sharing OAuth2 client configurations between applications **FUNDAMENTALLY BREAKS** the OAuth2
|
|
> security model and is **NOT SUPPORTED** as a configuration. The Kanidm Project **WILL NOT**
|
|
> support you if you attempt this.
|
|
>
|
|
> Multiple origins are **ONLY** to allow supplemental redirects within the _same_ client
|
|
> application.
|
|
|
|
Some services may have a website URL as well as native applications with opaque origins. These
|
|
native applications require alternate redirection URLs to be configured so that after an OAuth2
|
|
exchange, the system can redirect to the native application.
|
|
|
|
To support this Kanidm allows supplemental opaque origins to be configured on clients.
|
|
|
|
```bash
|
|
kanidm system oauth2 add-redirect-url <name> <url>
|
|
kanidm system oauth2 remove-redirect-url <name> <url>
|
|
|
|
kanidm system oauth2 add-redirect-url nextcloud app://ios-nextcloud
|
|
```
|
|
|
|
Supplemental URLs are shown in the OAuth2 client configuration in the `oauth2_rs_origin` attribute.
|
|
|
|
### Strict Redirect URLs
|
|
|
|
Kanidm previously enforced that redirection targets only matched by _origin_, not the full URL. In
|
|
1.4.0 these URLs will enforce a full URL match instead.
|
|
|
|
To indicate your readiness for this transition, all OAuth2 clients must have the field
|
|
`strict-redirect-url` enabled. Once enabled, the client will begin to enforce the 1.4.0 strict
|
|
validation behaviour.
|
|
|
|
> [!WARNING]
|
|
>
|
|
> If you have not enabled `strict-redirect-url` on all OAuth2 clients the upgrade to 1.4.0 will refuse
|
|
> to proceed.
|
|
|
|
To enable or disable strict validation:
|
|
|
|
```bash
|
|
kanidm system oauth2 enable-strict-redirect-url <name>
|
|
kanidm system oauth2 disable-strict-redirect-url <name>
|
|
```
|
|
|
|
## Extended Options for Legacy Clients
|
|
|
|
Not all clients support modern standards like PKCE or ECDSA. In these situations it may be necessary
|
|
to disable these on a per-client basis. Disabling these on one client will not affect others. These
|
|
settings are explained in detail in [our FAQ](../frequently_asked_questions.html#oauth2)
|
|
|
|
> [!WARNING]
|
|
>
|
|
> Changing these settings MAY have serious consequences on the security of your services. You should
|
|
> avoid changing these if at all possible!
|
|
|
|
To disable PKCE for a confidential client:
|
|
|
|
```bash
|
|
kanidm system oauth2 warning-insecure-client-disable-pkce <client name>
|
|
```
|
|
|
|
To use the legacy RSA PKCS1-5 SHA256 cryptographic algorithm
|
|
(`id_token_signing_alg_values_supported` = `RS256`):
|
|
|
|
```bash
|
|
kanidm system oauth2 warning-enable-legacy-crypto <client name>
|
|
```
|
|
|
|
In this mode, Kanidm will not offer `ES256` support for the client at all.
|
|
|
|
## Resetting Client Security Material
|
|
|
|
In the case of disclosure of the basic secret or some other security event where you may wish to
|
|
invalidate a services active sessions/tokens. You can reset the secret material of the server with:
|
|
|
|
```bash
|
|
kanidm system oauth2 reset-secrets
|
|
```
|
|
|
|
Each client has unique signing keys and access secrets, so this is limited to each service.
|
|
|
|
## WebFinger
|
|
|
|
[WebFinger](https://datatracker.ietf.org/doc/html/rfc7033) provides a mechanism
|
|
for discovering information about people or other entities. It can be used by an
|
|
identity provider to supply OpenID Connect discovery information.
|
|
|
|
Kanidm provides
|
|
[an Identity Provider Discovery for OIDC URL](https://datatracker.ietf.org/doc/html/rfc7033#section-3.1)
|
|
response to all incoming WebFinger requests, using a user's SPN as their account
|
|
ID. This does not match on email addresses as they are not guaranteed to be
|
|
unique.
|
|
|
|
However, WebFinger has a number of flaws which make it difficult to use with
|
|
Kanidm:
|
|
|
|
* WebFinger assumes that the identity provider will give the same `iss`
|
|
(Issuer) for every OAuth 2.0/OIDC client, and there is no standard way for a
|
|
WebFinger client to report its client ID.
|
|
|
|
Kanidm uses a *different* `iss` (Issuer) value for each client.
|
|
|
|
* WebFinger requires that this be served at the *root* of the domain of a user's
|
|
SPN (ie: information about the user with SPN `user@idm.example.com` is at
|
|
`https://idm.example.com/.well-known/webfinger`).
|
|
|
|
Kanidm *does not* provide a WebFinger endpoint at its root URL, because it has
|
|
no way to know *which* OAuth 2.0/OIDC client a WebFinger request is associated
|
|
with, so could report an incorrect `iss` (Issuer).
|
|
|
|
You will need a load balancer in front of Kanidm's HTTPS server to redirect
|
|
requests to the appropriate `/oauth2/openid/:client_id:/.well-known/webfinger`
|
|
URL. If the client does not follow redirects, you may need to rewrite the
|
|
request in the load balancer instead.
|
|
|
|
If you have *multiple* WebFinger clients, it will need to map some other
|
|
property of the request (such as a source IP address or `User-Agent` header)
|
|
to a client ID, and redirect to the appropriate WebFinger URL for that client.
|
|
|
|
* Kanidm responds to *all* WebFinger queries with
|
|
[an Identity Provider Discovery for OIDC URL](https://datatracker.ietf.org/doc/html/rfc7033#section-3.1),
|
|
**regardless** of what
|
|
[`rel` parameter](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4.1)
|
|
was specified.
|
|
|
|
This is to work around
|
|
[a broken client](https://tailscale.com/kb/1240/sso-custom-oidc) which doesn't
|
|
send a `rel` parameter, but expects an Identity Provider Discovery issuer URL
|
|
in response.
|
|
|
|
If you want to use WebFinger in any *other* context on Kanidm's hostname,
|
|
you'll need a load balancer in front of Kanidm which matches on some property
|
|
of the request.
|
|
|
|
Because of the flaws of the WebFinger specification and the deployment
|
|
difficulties they introduce, we recommend that applications use OpenID Connect
|
|
Discovery or OAuth 2.0 Authorisation Server Metadata for client configuration
|
|
instead of WebFinger.
|