Put OIDC callback URI under /_synapse/client. (#9288)

This commit is contained in:
Richard van der Hoff 2021-02-01 22:56:01 +00:00 committed by GitHub
parent d1f13c7485
commit 846b9d3df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 46 additions and 28 deletions

View File

@ -3,6 +3,10 @@ Unreleased
Note that this release includes a change in Synapse to use Redis as a cache ─ as well as a pub/sub mechanism ─ if Redis support is enabled. No action is needed by server administrators, and we do not expect resource usage of the Redis instance to change dramatically. Note that this release includes a change in Synapse to use Redis as a cache ─ as well as a pub/sub mechanism ─ if Redis support is enabled. No action is needed by server administrators, and we do not expect resource usage of the Redis instance to change dramatically.
This release also changes the callback URI for OpenID Connect (OIDC) identity
providers. If your server is configured to use single sign-on via an
OIDC/OAuth2 IdP, you may need to make configuration changes. Please review
[UPGRADE.rst](UPGRADE.rst) for more details on these changes.
Synapse 1.26.0 (2021-01-27) Synapse 1.26.0 (2021-01-27)
=========================== ===========================

View File

@ -88,6 +88,17 @@ for example:
Upgrading to v1.27.0 Upgrading to v1.27.0
==================== ====================
Changes to callback URI for OAuth2 / OpenID Connect
---------------------------------------------------
This version changes the URI used for callbacks from OAuth2 identity providers. If
your server is configured for single sign-on via an OpenID Connect or OAuth2 identity
provider, you will need to add ``[synapse public baseurl]/_synapse/client/oidc/callback``
to the list of permitted "redirect URIs" at the identity provider.
See `docs/openid.md <docs/openid.md>`_ for more information on setting up OpenID
Connect.
Changes to HTML templates Changes to HTML templates
------------------------- -------------------------
@ -235,7 +246,7 @@ shown below:
return {"localpart": localpart} return {"localpart": localpart}
Removal historical Synapse Admin API Removal historical Synapse Admin API
------------------------------------ ------------------------------------
Historically, the Synapse Admin API has been accessible under: Historically, the Synapse Admin API has been accessible under:

1
changelog.d/9288.feature Normal file
View File

@ -0,0 +1 @@
Update the redirect URI for OIDC authentication.

View File

@ -54,7 +54,8 @@ Here are a few configs for providers that should work with Synapse.
### Microsoft Azure Active Directory ### Microsoft Azure Active Directory
Azure AD can act as an OpenID Connect Provider. Register a new application under Azure AD can act as an OpenID Connect Provider. Register a new application under
*App registrations* in the Azure AD management console. The RedirectURI for your *App registrations* in the Azure AD management console. The RedirectURI for your
application should point to your matrix server: `[synapse public baseurl]/_synapse/oidc/callback` application should point to your matrix server:
`[synapse public baseurl]/_synapse/client/oidc/callback`
Go to *Certificates & secrets* and register a new client secret. Make note of your Go to *Certificates & secrets* and register a new client secret. Make note of your
Directory (tenant) ID as it will be used in the Azure links. Directory (tenant) ID as it will be used in the Azure links.
@ -94,7 +95,7 @@ staticClients:
- id: synapse - id: synapse
secret: secret secret: secret
redirectURIs: redirectURIs:
- '[synapse public baseurl]/_synapse/oidc/callback' - '[synapse public baseurl]/_synapse/client/oidc/callback'
name: 'Synapse' name: 'Synapse'
``` ```
@ -140,7 +141,7 @@ Follow the [Getting Started Guide](https://www.keycloak.org/getting-started) to
| Enabled | `On` | | Enabled | `On` |
| Client Protocol | `openid-connect` | | Client Protocol | `openid-connect` |
| Access Type | `confidential` | | Access Type | `confidential` |
| Valid Redirect URIs | `[synapse public baseurl]/_synapse/oidc/callback` | | Valid Redirect URIs | `[synapse public baseurl]/_synapse/client/oidc/callback` |
5. Click `Save` 5. Click `Save`
6. On the Credentials tab, update the fields: 6. On the Credentials tab, update the fields:
@ -168,7 +169,7 @@ oidc_providers:
### [Auth0][auth0] ### [Auth0][auth0]
1. Create a regular web application for Synapse 1. Create a regular web application for Synapse
2. Set the Allowed Callback URLs to `[synapse public baseurl]/_synapse/oidc/callback` 2. Set the Allowed Callback URLs to `[synapse public baseurl]/_synapse/client/oidc/callback`
3. Add a rule to add the `preferred_username` claim. 3. Add a rule to add the `preferred_username` claim.
<details> <details>
<summary>Code sample</summary> <summary>Code sample</summary>
@ -217,7 +218,7 @@ login mechanism needs an attribute to uniquely identify users, and that endpoint
does not return a `sub` property, an alternative `subject_claim` has to be set. does not return a `sub` property, an alternative `subject_claim` has to be set.
1. Create a new OAuth application: https://github.com/settings/applications/new. 1. Create a new OAuth application: https://github.com/settings/applications/new.
2. Set the callback URL to `[synapse public baseurl]/_synapse/oidc/callback`. 2. Set the callback URL to `[synapse public baseurl]/_synapse/client/oidc/callback`.
Synapse config: Synapse config:
@ -262,13 +263,13 @@ oidc_providers:
display_name_template: "{{ user.name }}" display_name_template: "{{ user.name }}"
``` ```
4. Back in the Google console, add this Authorized redirect URI: `[synapse 4. Back in the Google console, add this Authorized redirect URI: `[synapse
public baseurl]/_synapse/oidc/callback`. public baseurl]/_synapse/client/oidc/callback`.
### Twitch ### Twitch
1. Setup a developer account on [Twitch](https://dev.twitch.tv/) 1. Setup a developer account on [Twitch](https://dev.twitch.tv/)
2. Obtain the OAuth 2.0 credentials by [creating an app](https://dev.twitch.tv/console/apps/) 2. Obtain the OAuth 2.0 credentials by [creating an app](https://dev.twitch.tv/console/apps/)
3. Add this OAuth Redirect URL: `[synapse public baseurl]/_synapse/oidc/callback` 3. Add this OAuth Redirect URL: `[synapse public baseurl]/_synapse/client/oidc/callback`
Synapse config: Synapse config:
@ -290,7 +291,7 @@ oidc_providers:
1. Create a [new application](https://gitlab.com/profile/applications). 1. Create a [new application](https://gitlab.com/profile/applications).
2. Add the `read_user` and `openid` scopes. 2. Add the `read_user` and `openid` scopes.
3. Add this Callback URL: `[synapse public baseurl]/_synapse/oidc/callback` 3. Add this Callback URL: `[synapse public baseurl]/_synapse/client/oidc/callback`
Synapse config: Synapse config:
@ -323,7 +324,7 @@ one so requires a little more configuration.
2. Once the app is created, add "Facebook Login" and choose "Web". You don't 2. Once the app is created, add "Facebook Login" and choose "Web". You don't
need to go through the whole form here. need to go through the whole form here.
3. In the left-hand menu, open "Products"/"Facebook Login"/"Settings". 3. In the left-hand menu, open "Products"/"Facebook Login"/"Settings".
* Add `[synapse public baseurl]/_synapse/oidc/callback` as an OAuth Redirect * Add `[synapse public baseurl]/_synapse/client/oidc/callback` as an OAuth Redirect
URL. URL.
4. In the left-hand menu, open "Settings/Basic". Here you can copy the "App ID" 4. In the left-hand menu, open "Settings/Basic". Here you can copy the "App ID"
and "App Secret" for use below. and "App Secret" for use below.

View File

@ -266,7 +266,7 @@ using):
^/_synapse/client/sso_register$ ^/_synapse/client/sso_register$
# OpenID Connect requests. # OpenID Connect requests.
^/_synapse/oidc/callback$ ^/_synapse/client/oidc/callback$
# SAML requests. # SAML requests.
^/_matrix/saml2/authn_response$ ^/_matrix/saml2/authn_response$

View File

@ -53,7 +53,7 @@ class OIDCConfig(Config):
"Multiple OIDC providers have the idp_id %r." % idp_id "Multiple OIDC providers have the idp_id %r." % idp_id
) )
self.oidc_callback_url = self.public_baseurl + "_synapse/oidc/callback" self.oidc_callback_url = self.public_baseurl + "_synapse/client/oidc/callback"
@property @property
def oidc_enabled(self) -> bool: def oidc_enabled(self) -> bool:

View File

@ -102,7 +102,7 @@ class OidcHandler:
) from e ) from e
async def handle_oidc_callback(self, request: SynapseRequest) -> None: async def handle_oidc_callback(self, request: SynapseRequest) -> None:
"""Handle an incoming request to /_synapse/oidc/callback """Handle an incoming request to /_synapse/client/oidc/callback
Since we might want to display OIDC-related errors in a user-friendly Since we might want to display OIDC-related errors in a user-friendly
way, we don't raise SynapseError from here. Instead, we call way, we don't raise SynapseError from here. Instead, we call
@ -643,7 +643,7 @@ class OidcProvider:
- ``client_id``: the client ID set in ``oidc_config.client_id`` - ``client_id``: the client ID set in ``oidc_config.client_id``
- ``response_type``: ``code`` - ``response_type``: ``code``
- ``redirect_uri``: the callback URL ; ``{base url}/_synapse/oidc/callback`` - ``redirect_uri``: the callback URL ; ``{base url}/_synapse/client/oidc/callback``
- ``scope``: the list of scopes set in ``oidc_config.scopes`` - ``scope``: the list of scopes set in ``oidc_config.scopes``
- ``state``: a random string - ``state``: a random string
- ``nonce``: a random string - ``nonce``: a random string
@ -684,7 +684,7 @@ class OidcProvider:
request.addCookie( request.addCookie(
SESSION_COOKIE_NAME, SESSION_COOKIE_NAME,
cookie, cookie,
path="/_synapse/oidc", path="/_synapse/client/oidc",
max_age="3600", max_age="3600",
httpOnly=True, httpOnly=True,
sameSite="lax", sameSite="lax",
@ -705,7 +705,7 @@ class OidcProvider:
async def handle_oidc_callback( async def handle_oidc_callback(
self, request: SynapseRequest, session_data: "OidcSessionData", code: str self, request: SynapseRequest, session_data: "OidcSessionData", code: str
) -> None: ) -> None:
"""Handle an incoming request to /_synapse/oidc/callback """Handle an incoming request to /_synapse/client/oidc/callback
By this time we have already validated the session on the synapse side, and By this time we have already validated the session on the synapse side, and
now need to do the provider-specific operations. This includes: now need to do the provider-specific operations. This includes:

View File

@ -47,9 +47,9 @@ def build_synapse_client_resource_tree(hs: "HomeServer") -> Mapping[str, Resourc
# provider-specific SSO bits. Only load these if they are enabled, since they # provider-specific SSO bits. Only load these if they are enabled, since they
# rely on optional dependencies. # rely on optional dependencies.
if hs.config.oidc_enabled: if hs.config.oidc_enabled:
from synapse.rest.oidc import OIDCResource from synapse.rest.synapse.client.oidc import OIDCResource
resources["/_synapse/oidc"] = OIDCResource(hs) resources["/_synapse/client/oidc"] = OIDCResource(hs)
if hs.config.saml2_enabled: if hs.config.saml2_enabled:
from synapse.rest.saml2 import SAML2Resource from synapse.rest.saml2 import SAML2Resource

View File

@ -12,11 +12,12 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import logging import logging
from twisted.web.resource import Resource from twisted.web.resource import Resource
from synapse.rest.oidc.callback_resource import OIDCCallbackResource from synapse.rest.synapse.client.oidc.callback_resource import OIDCCallbackResource
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -25,3 +26,6 @@ class OIDCResource(Resource):
def __init__(self, hs): def __init__(self, hs):
Resource.__init__(self) Resource.__init__(self)
self.putChild(b"callback", OIDCCallbackResource(hs)) self.putChild(b"callback", OIDCCallbackResource(hs))
__all__ = ["OIDCResource"]

View File

@ -40,7 +40,7 @@ ISSUER = "https://issuer/"
CLIENT_ID = "test-client-id" CLIENT_ID = "test-client-id"
CLIENT_SECRET = "test-client-secret" CLIENT_SECRET = "test-client-secret"
BASE_URL = "https://synapse/" BASE_URL = "https://synapse/"
CALLBACK_URL = BASE_URL + "_synapse/oidc/callback" CALLBACK_URL = BASE_URL + "_synapse/client/oidc/callback"
SCOPES = ["openid"] SCOPES = ["openid"]
AUTHORIZATION_ENDPOINT = ISSUER + "authorize" AUTHORIZATION_ENDPOINT = ISSUER + "authorize"
@ -58,12 +58,6 @@ COMMON_CONFIG = {
} }
# The cookie name and path don't really matter, just that it has to be coherent
# between the callback & redirect handlers.
COOKIE_NAME = b"oidc_session"
COOKIE_PATH = "/_synapse/oidc"
class TestMappingProvider: class TestMappingProvider:
@staticmethod @staticmethod
def parse_config(config): def parse_config(config):
@ -340,8 +334,11 @@ class OidcHandlerTestCase(HomeserverTestCase):
# For some reason, call.args does not work with python3.5 # For some reason, call.args does not work with python3.5
args = calls[0][0] args = calls[0][0]
kwargs = calls[0][1] kwargs = calls[0][1]
self.assertEqual(args[0], COOKIE_NAME)
self.assertEqual(kwargs["path"], COOKIE_PATH) # The cookie name and path don't really matter, just that it has to be coherent
# between the callback & redirect handlers.
self.assertEqual(args[0], b"oidc_session")
self.assertEqual(kwargs["path"], "/_synapse/client/oidc")
cookie = args[1] cookie = args[1]
macaroon = pymacaroons.Macaroon.deserialize(cookie) macaroon = pymacaroons.Macaroon.deserialize(cookie)