Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Support OIDC backchannel logouts #11414

Merged
merged 20 commits into from Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/11414.feature
@@ -0,0 +1 @@
Support back-channel logouts from OpenID Connect providers.
14 changes: 14 additions & 0 deletions docs/openid.md
Expand Up @@ -49,6 +49,13 @@ setting in your configuration file.
See the [configuration manual](usage/configuration/config_documentation.md#oidc_providers) for some sample settings, as well as
the text below for example configurations for specific providers.

## OIDC Back-Channel Logout

Synapse supports receiving [OpenID Connect Back-Channel Logout](https://openid.net/specs/openid-connect-backchannel-1_0.html) notifications.

This lets the OpenID Connect Provider notify Synapse when a user logs out, so that Synapse can end that user session.
This feature can be enabled by setting the `backchannel_logout_enabled` property to `true` in the provider configuration, and setting the following URL as destination for Back-Channel Logout notifications in your OpenID Connect Provider: `[synapse public baseurl]/_synapse/client/oidc/backchannel_logout`

## Sample configs

Here are a few configs for providers that should work with Synapse.
Expand Down Expand Up @@ -123,6 +130,9 @@ oidc_providers:

[Keycloak][keycloak-idp] is an opensource IdP maintained by Red Hat.

Keycloak supports OIDC Back-Channel Logout, which sends logout notification to Synapse, so that Synapse users get logged out when they log out from Keycloak.
This can be optionally enabled by setting `backchannel_logout_enabled` to `true` in the Synapse configuration, and by setting the "Backchannel Logout URL" in Keycloak.

Follow the [Getting Started Guide](https://www.keycloak.org/getting-started) to install Keycloak and set up a realm.

1. Click `Clients` in the sidebar and click `Create`
Expand All @@ -144,6 +154,8 @@ Follow the [Getting Started Guide](https://www.keycloak.org/getting-started) to
| Client Protocol | `openid-connect` |
| Access Type | `confidential` |
| Valid Redirect URIs | `[synapse public baseurl]/_synapse/client/oidc/callback` |
| Backchannel Logout URL (optional) | `[synapse public baseurl]/_synapse/client/oidc/backchannel_logout` |
| Backchannel Logout Session Required (optional) | `On` |

5. Click `Save`
6. On the Credentials tab, update the fields:
Expand All @@ -167,7 +179,9 @@ oidc_providers:
config:
localpart_template: "{{ user.preferred_username }}"
display_name_template: "{{ user.name }}"
backchannel_logout_enabled: true # Optional
```

### Auth0

[Auth0][auth0] is a hosted SaaS IdP solution.
Expand Down
7 changes: 7 additions & 0 deletions docs/usage/configuration/config_documentation.md
Expand Up @@ -3014,6 +3014,13 @@ Options for each entry include:
which is set to the claims returned by the UserInfo Endpoint and/or
in the ID Token.

* `backchannel_logout_enabled`: set to `true` to process OIDC Back-Channel Logout notifications.
Those notifications are expected to be received on `/_synapse/client/oidc/backchannel_logout`.
Defaults to `false`.

* `backchannel_logout_ignore_sub`: by default, the OIDC Back-Channel Logout feature checks that the
`sub` claim matches the subject claim received during login. This check can be disabled by setting
this to `true`. Defaults to `false`.
sandhose marked this conversation as resolved.
Show resolved Hide resolved

It is possible to configure Synapse to only allow logins if certain attributes
match particular values in the OIDC userinfo. The requirements can be listed under
Expand Down
12 changes: 12 additions & 0 deletions synapse/config/oidc.py
Expand Up @@ -123,6 +123,8 @@ def oidc_enabled(self) -> bool:
"userinfo_endpoint": {"type": "string"},
"jwks_uri": {"type": "string"},
"skip_verification": {"type": "boolean"},
"backchannel_logout_enabled": {"type": "boolean"},
"backchannel_logout_ignore_sub": {"type": "boolean"},
"user_profile_method": {
"type": "string",
"enum": ["auto", "userinfo_endpoint"],
Expand Down Expand Up @@ -292,6 +294,10 @@ def _parse_oidc_config_dict(
token_endpoint=oidc_config.get("token_endpoint"),
userinfo_endpoint=oidc_config.get("userinfo_endpoint"),
jwks_uri=oidc_config.get("jwks_uri"),
backchannel_logout_enabled=oidc_config.get("backchannel_logout_enabled", False),
backchannel_logout_ignore_sub=oidc_config.get(
"backchannel_logout_ignore_sub", False
),
skip_verification=oidc_config.get("skip_verification", False),
user_profile_method=oidc_config.get("user_profile_method", "auto"),
allow_existing_users=oidc_config.get("allow_existing_users", False),
Expand Down Expand Up @@ -368,6 +374,12 @@ class OidcProviderConfig:
# "openid" scope is used.
jwks_uri: Optional[str]

# Whether Synapse should react to backchannel logouts
backchannel_logout_enabled: bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes me slightly sad to add another configuration option here, but I don't think there's much we can do here to avoid it?

The metadata seems to include whether this feature is supported or not. Can we auto-enable it in those cases?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, we could probably completely skip the configuration parameter. The only real benefit right now are warnings when the config enables backchannel logouts, but the OP does not advertise proper support.

Right now the behaviour is to delete the device, which does a "hard" logout. From a client perspective, it means it won't keep E2EE data, so you can't get back the deleted device. Maybe that's not the right behaviour, maybe that should be configurable.

Would it make sense to have instead a config parameter backchannel_logout_behaviour with the following values: logout (the default), soft_logout, nothing, and maybe implement soft_logout/other behaviours later?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the behaviour is to delete the device, which does a "hard" logout. From a client perspective, it means it won't keep E2EE data, so you can't get back the deleted device. Maybe that's not the right behaviour, maybe that should be configurable.

Would it make sense to have instead a config parameter backchannel_logout_behaviour with the following values: logout (the default), soft_logout, nothing, and maybe implement soft_logout/other behaviours later?

I don't think doing a hard logout makes sense, actually. It likely makes more sense to do a soft-logout? I'm not really sure what a backchannel-logout is supposed to represent, but logging out of the IdP causing Synapse to destroy a session, causing a user to lose decryption keys sounds not great.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't really found a good way to soft-logout a user :(
It looks like soft-logouts are only sent when the token expired.

but logging out of the IdP causing Synapse to destroy a session, causing a user to lose decryption keys sounds not great.

I agree, but on the other hand leaving 'dead' devices on the account doesn't seem great either. Would you be fine with leaving this behaviour for now, see how it feels with whatever customer is asking for this change, and iterate on it later if it makes more sense to do a soft-logout?


# Whether Synapse should ignore the `sub` claim in backchannel logouts or not.
backchannel_logout_ignore_sub: bool

# Whether to skip metadata verification
skip_verification: bool

Expand Down