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

saml: allow specification of the IdP entityid #8630

Merged
merged 10 commits into from
Nov 19, 2020
Merged

Conversation

benbz
Copy link
Contributor

@benbz benbz commented Oct 22, 2020

I'm working with a remote metadata endpoint that contains multiple
IDPSSODescriptor that support Saml2, so entityid needs to be passed into
Saml2Client.prepare_for_authenticate or an error will be thrown when generating a redirect URL:

  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/synapse/rest/client/v1/login.py", line 469, in get_sso_url
    return self._saml_handler.handle_redirect_request(client_redirect_url)
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/synapse/handlers/saml_handler.py", line 128, in handle_redirect_request
    reqid, info = self._saml_client.prepare_for_authenticate(
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/client.py", line 65, in prepare_for_authenticate
    self.prepare_for_negotiated_authenticate(
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/client.py", line 115, in prepare_for_negotiated_authenticate
    destination = self._sso_location(entityid, binding)
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/client_base.py", line 224, in _sso_location
    raise IdpUnspecified("Too many IdPs to choose from: %s" % eids)
saml2.client_base.IdpUnspecified: Too many IdPs to choose from:

My reading of https://pysaml2.readthedocs.io/en/latest/howto/config.html
suggests that service.sp.idp is the setting for this but it doesn't seem
to do anything other than populate the idp attribute in saml2_sp_config.
So I'm populating that configuration option and attempting to use the idp
attribute. saml2_sp_config.getattr('idp') returns None if the config option
isn't set, which is equivalent to what was there previously.

However https://pysaml2.readthedocs.io/en/latest/howto/config.html#idp
suggests this setting should be a list, but Saml2Client._sso_location
appears to require a single entity id. With this PR if I configure idp as a list, as the
docs suggest, i.e:

    service:
      sp:
        idp:
        - https://my-idp-domain/idp/shibboleth

then when attempting to get the redirect URL I get the following:

  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/synapse/rest/client/v1/login.py", line 469, in get_sso_url
    return self._saml_handler.handle_redirect_request(client_redirect_url)
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/synapse/handlers/saml_handler.py", line 127, in handle_redirect_request
    reqid, info = self._saml_client.prepare_for_authenticate(
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/client.py", line 65, in prepare_for_authenticate
    self.prepare_for_negotiated_authenticate(
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/client.py", line 115, in prepare_for_negotiated_authenticate
    destination = self._sso_location(entityid, binding)
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/client_base.py", line 213, in _sso_location
    srvs = self.metadata.single_sign_on_service(entityid, binding)
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/mdstore.py", line 1126, in single_sign_on_service
    return self.service(entity_id, "idpsso_descriptor",
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/mdstore.py", line 1073, in service
    srvs = _md.service(entity_id, typ, service, binding)
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/mdstore.py", line 596, in service
    for t in self[entity_id][typ]:
  File "/home/ben/Work/local/synapse_deploy/deploy/env/lib/python3.8/site-packages/saml2/mdstore.py", line 497, in __getitem__
    return self.entity[item]
TypeError: unhashable type: 'list'

If using this PR, I configure idp as a string, i.e:

    service:
      sp:
        idp: https://my-idp-domain/idp/shibboleth

then I get a valid redirect URL back.

I could configure service.sp.idp as a list and update this PR to only
use the first entry in the Saml2Client.prepare_for_authenticate call
but what's the point of accepting a list then?

In summary this seems to work, but I'm not convinced I'm doing it right.

Changelog entry not added yet until we're happy that a string is fine
rather than a list.

cc @clokep given we were discussing this yesterday.

Pull Request Checklist

  • Pull request is based on the develop branch
  • Pull request includes a changelog file. The entry should:
    • Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from EventStore to EventWorkerStore.".
    • Use markdown where necessary, mostly for code blocks.
    • End with either a period (.) or an exclamation mark (!).
    • Start with a capital letter.
  • Pull request includes a sign off
  • Code style is correct (run the linters)

I'm working with a remote metadata endpoint that contains multiple
IDPSSODescriptor that support Saml2, so entityid needs to be passed into
Saml2Client.prepare_for_authenticate or an error will be thrown saying
"Too many IdPs to choose from".

My reading of https://pysaml2.readthedocs.io/en/latest/howto/config.html
suggests that service.sp.idp is the setting for this but it doesn't seem
to do anything other than populate the `idp` attribute in saml2_sp_config.

Also https://pysaml2.readthedocs.io/en/latest/howto/config.html#idp
suggests this setting should be a list, but Saml2Client._sso_location
wants a single entity id.

In summary this seems to work, but I'm not convinced I'm doing it right.
@clokep clokep requested a review from a team October 22, 2020 14:02
@clokep
Copy link
Member

clokep commented Oct 22, 2020

I'm setting review on this so we remember to come back to it!

@clokep clokep self-assigned this Oct 27, 2020
@clokep
Copy link
Member

clokep commented Oct 27, 2020

My reading of pysaml2.readthedocs.io/en/latest/howto/config.html suggests that service.sp.idp is the setting for this but it doesn't seem to do anything other than populate the idp attribute in saml2_sp_config. So I'm populating that configuration option and attempting to use the idp attribute. saml2_sp_config.getattr('idp') returns None if the config option isn't set, which is equivalent to what was there previously.

Is there a particular section of this document that makes you think the service.sp.idp parameter is meant to be used for redirects? Was it more than just the idp docs:

Defines the set of IdPs that this SP is allowed to use; if unset, all listed IdPs may be used. If set, then the value is expected to be a list with entity identifiers for the allowed IdPs.

Looking through the pyaml2 code this configuration setting seems to be completely unused. The only examples of calling prepare_for_authenticate (or prepare_for_negotiated_authenticate) seem to be in the tests which consistently call the API by providing an entity ID as a string. Those eventually call into Base._sso_location which has comments describing the following:

  1. If an entity ID is provided, ensure that it exists in the metadata provided. If it does not exist, raise an exception. If it exists, return it.
  2. If no entity ID is provided, but it is ambiguous which entity to use (i.e. there is more than one entity in the metadata provided), raise an exception. (This is the "Too many IdPs to choose from" exception we're seeing.)
  3. If no entity ID is provided and there is only a single entity in the metadata, return it.

In summary this seems to work, but I'm not convinced I'm doing it right.

I'm pretty confident the change to call prepare_for_authenticate with a given entity ID is reasonable, I'm not sure I agree that pulling it out from service.sp.idp makes sense. In particular I'm nervous about having people set this to a string if pysaml2 starts using this field for some reason. It might make sense to use a completely separate setting. What do you think?

@benbz
Copy link
Contributor Author

benbz commented Oct 27, 2020

Is there a particular section of this document that makes you think the service.sp.idp parameter is meant to be used for redirects? Was it more than just the idp docs:

Defines the set of IdPs that this SP is allowed to use; if unset, all listed IdPs may be used. If set, then the value is expected to be a list with entity identifiers for the allowed IdPs.

It was just this quoted section above that made me think it should be this setting. But that was before I realised it wasn't being used.

I'm pretty confident the change to call prepare_for_authenticate with a given entity ID is reasonable, I'm not sure I agree that pulling it out from service.sp.idp makes sense. In particular I'm nervous about having people set this to a string if pysaml2 starts using this field for some reason. It might make sense to use a completely separate setting. What do you think?

Options I see:

  • either carry on as now or use a list for service.sp.idp and extract the 1st value only but either way, as you say, pysaml2 could start using it in a way we didn't expect
  • use a parameter under saml2_config but not under sp_config but that feels somewhat wrong given everything else related is under sp_config
  • pick a parameter name under sp_config that isn't used by pysaml2 at present and attempt to find a way to use that here but there's always the risk that then pysaml2 will start using that parameter name in the future. This may or may not even be possible with how pysaml2 does its config, would need to test

I don't have strong feelings about those options other than that they all appear to have risks.

@clokep
Copy link
Member

clokep commented Oct 27, 2020

I filed IdentityPython/pysaml2#739 upstream about the option being unused.

@richvdh and I discussed this and we think the best option is 2:

use a parameter under saml2_config but not under sp_config

I think this will give us the greatest flexibility in the future.

@benbz
Copy link
Contributor Author

benbz commented Oct 27, 2020

Ack, thanks for digging into this and for the steer. I'll update the PR early next week as I'm off for the rest of the week after today

Copy link
Member

@clokep clokep left a comment

Choose a reason for hiding this comment

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

Great! I'm going to mark this as request changes to get it out of the queue. 👍

@benbz benbz requested a review from clokep November 2, 2020 13:56
@erikjohnston erikjohnston requested review from a team and removed request for clokep November 2, 2020 16:04
@erikjohnston
Copy link
Member

@clokep sounds like you were happy with the concept? If so then this PR looks good, otherwise I need to spend a bit of time getting up to speed.

@erikjohnston
Copy link
Member

(You'll need to update the sample config too if you're not already doing that)

@benbz
Copy link
Contributor Author

benbz commented Nov 2, 2020

(You'll need to update the sample config too if you're not already doing that)

Yup, unfortunately doing this from mobile so will have to do it tomorrow

@erikjohnston
Copy link
Member

Ah, then I can do that for you so we can let the tests chuuuuuuuuurn

@clokep
Copy link
Member

clokep commented Nov 2, 2020

@clokep sounds like you were happy with the concept? If so then this PR looks good, otherwise I need to spend a bit of time getting up to speed.

Yep. I think the code changes look fine. The sample config comment could use a once over from someone who didn't do a deep dive of this. It read ok to me though!

@clokep
Copy link
Member

clokep commented Nov 18, 2020

@benbz / @erikjohnston Did this get dropped on the floor? Looks like there's nothing left to do here except sync with develop?

@benbz
Copy link
Contributor Author

benbz commented Nov 19, 2020

@clokep thanks for following up on this. I've resynced with develop. There seem to be some sytest failures, but I don't think they relate to this PR?

@clokep clokep self-requested a review November 19, 2020 13:48
Copy link
Member

@clokep clokep left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks!

@clokep clokep merged commit 53a6f5d into develop Nov 19, 2020
@clokep clokep deleted the bbz/specify-saml-idp branch November 19, 2020 14:57
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Dec 9, 2020
Synapse 1.24.0 (2020-12-09)
===========================

Due to the two security issues highlighted below, server administrators are
encouraged to update Synapse. We are not aware of these vulnerabilities being
exploited in the wild.

Security advisory
-----------------

The following issues are fixed in v1.23.1 and v1.24.0.

- There is a denial of service attack
  ([CVE-2020-26257](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-26257))
  against the federation APIs in which future events will not be correctly sent
  to other servers over federation. This affects all servers that participate in
  open federation. (Fixed in [#8776](matrix-org/synapse#8776)).

- Synapse may be affected by OpenSSL
  [CVE-2020-1971](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-1971).
  Synapse administrators should ensure that they have the latest versions of
  the cryptography Python package installed.

To upgrade Synapse along with the cryptography package:

* Administrators using the [`matrix.org` Docker
  image](https://hub.docker.com/r/matrixdotorg/synapse/) or the [Debian/Ubuntu
  packages from
  `matrix.org`](https://github.com/matrix-org/synapse/blob/master/INSTALL.md#matrixorg-packages)
  should ensure that they have version 1.24.0 or 1.23.1 installed: these images include
  the updated packages.
* Administrators who have [installed Synapse from
  source](https://github.com/matrix-org/synapse/blob/master/INSTALL.md#installing-from-source)
  should upgrade the cryptography package within their virtualenv by running:
  ```sh
  <path_to_virtualenv>/bin/pip install 'cryptography>=3.3'
  ```
* Administrators who have installed Synapse from distribution packages should
  consult the information from their distributions.

Internal Changes
----------------

- Add a maximum version for pysaml2 on Python 3.5. ([\#8898](matrix-org/synapse#8898))


Synapse 1.24.0rc2 (2020-12-04)
==============================

Bugfixes
--------

- Fix a regression in v1.24.0rc1 which failed to allow SAML mapping providers which were unable to redirect users to an additional page. ([\#8878](matrix-org/synapse#8878))


Internal Changes
----------------

- Add support for the `prometheus_client` newer than 0.9.0. Contributed by Jordan Bancino. ([\#8875](matrix-org/synapse#8875))


Synapse 1.24.0rc1 (2020-12-02)
==============================

Features
--------

- Add admin API for logging in as a user. ([\#8617](matrix-org/synapse#8617))
- Allow specification of the SAML IdP if the metadata returns multiple IdPs. ([\#8630](matrix-org/synapse#8630))
- Add support for re-trying generation of a localpart for OpenID Connect mapping providers. ([\#8801](matrix-org/synapse#8801), [\#8855](matrix-org/synapse#8855))
- Allow the `Date` header through CORS. Contributed by Nicolas Chamo. ([\#8804](matrix-org/synapse#8804))
- Add a config option, `push.group_by_unread_count`, which controls whether unread message counts in push notifications are defined as "the number of rooms with unread messages" or "total unread messages". ([\#8820](matrix-org/synapse#8820))
- Add `force_purge` option to delete-room admin api. ([\#8843](matrix-org/synapse#8843))


Bugfixes
--------

- Fix a bug where appservices may be sent an excessive amount of read receipts and presence. Broke in v1.22.0. ([\#8744](matrix-org/synapse#8744))
- Fix a bug in some federation APIs which could lead to unexpected behaviour if different parameters were set in the URI and the request body. ([\#8776](matrix-org/synapse#8776))
- Fix a bug where synctl could spawn duplicate copies of a worker. Contributed by Waylon Cude. ([\#8798](matrix-org/synapse#8798))
- Allow per-room profiles to be used for the server notice user. ([\#8799](matrix-org/synapse#8799))
- Fix a bug where logging could break after a call to SIGHUP. ([\#8817](matrix-org/synapse#8817))
- Fix `register_new_matrix_user` failing with "Bad Request" when trailing slash is included in server URL. Contributed by @angdraug. ([\#8823](matrix-org/synapse#8823))
- Fix a minor long-standing bug in login, where we would offer the `password` login type if a custom auth provider supported it, even if password login was disabled. ([\#8835](matrix-org/synapse#8835))
- Fix a long-standing bug which caused Synapse to require unspecified parameters during user-interactive authentication. ([\#8848](matrix-org/synapse#8848))
- Fix a bug introduced in v1.20.0 where the user-agent and IP address reported during user registration for CAS, OpenID Connect, and SAML were of the wrong form. ([\#8784](matrix-org/synapse#8784))


Improved Documentation
----------------------

- Clarify the usecase for a msisdn delegate. Contributed by Adrian Wannenmacher. ([\#8734](matrix-org/synapse#8734))
- Remove extraneous comma from JSON example in User Admin API docs. ([\#8771](matrix-org/synapse#8771))
- Update `turn-howto.md` with troubleshooting notes. ([\#8779](matrix-org/synapse#8779))
- Fix the example on how to set the `Content-Type` header in nginx for the Client Well-Known URI. ([\#8793](matrix-org/synapse#8793))
- Improve the documentation for the admin API to list all media in a room with respect to encrypted events. ([\#8795](matrix-org/synapse#8795))
- Update the formatting of the `push` section of the homeserver config file to better align with the [code style guidelines](https://github.com/matrix-org/synapse/blob/develop/docs/code_style.md#configuration-file-format). ([\#8818](matrix-org/synapse#8818))
- Improve documentation how to configure prometheus for workers. ([\#8822](matrix-org/synapse#8822))
- Update example prometheus console. ([\#8824](matrix-org/synapse#8824))


Deprecations and Removals
-------------------------

- Remove old `/_matrix/client/*/admin` endpoints which were deprecated since Synapse 1.20.0. ([\#8785](matrix-org/synapse#8785))
- Disable pretty printing JSON responses for curl. Users who want pretty-printed output should use [jq](https://stedolan.github.io/jq/) in combination with curl. Contributed by @tulir. ([\#8833](matrix-org/synapse#8833))


Internal Changes
----------------

- Simplify the way the `HomeServer` object caches its internal attributes. ([\#8565](matrix-org/synapse#8565), [\#8851](matrix-org/synapse#8851))
- Add an example and documentation for clock skew to the SAML2 sample configuration to allow for clock/time difference between the homserver and IdP. Contributed by @localguru. ([\#8731](matrix-org/synapse#8731))
- Generalise `RoomMemberHandler._locally_reject_invite` to apply to more flows than just invite. ([\#8751](matrix-org/synapse#8751))
- Generalise `RoomStore.maybe_store_room_on_invite` to handle other, non-invite membership events. ([\#8754](matrix-org/synapse#8754))
- Refactor test utilities for injecting HTTP requests. ([\#8757](matrix-org/synapse#8757), [\#8758](matrix-org/synapse#8758), [\#8759](matrix-org/synapse#8759), [\#8760](matrix-org/synapse#8760), [\#8761](matrix-org/synapse#8761), [\#8777](matrix-org/synapse#8777))
- Consolidate logic between the OpenID Connect and SAML code. ([\#8765](matrix-org/synapse#8765))
- Use `TYPE_CHECKING` instead of magic `MYPY` variable. ([\#8770](matrix-org/synapse#8770))
- Add a commandline script to sign arbitrary json objects. ([\#8772](matrix-org/synapse#8772))
- Minor log line improvements for the SSO mapping code used to generate Matrix IDs from SSO IDs. ([\#8773](matrix-org/synapse#8773))
- Add additional error checking for OpenID Connect and SAML mapping providers. ([\#8774](matrix-org/synapse#8774), [\#8800](matrix-org/synapse#8800))
- Add type hints to HTTP abstractions. ([\#8806](matrix-org/synapse#8806), [\#8812](matrix-org/synapse#8812))
- Remove unnecessary function arguments and add typing to several membership replication classes. ([\#8809](matrix-org/synapse#8809))
- Optimise the lookup for an invite from another homeserver when trying to reject it. ([\#8815](matrix-org/synapse#8815))
- Add tests for `password_auth_provider`s. ([\#8819](matrix-org/synapse#8819))
- Drop redundant database index on `event_json`. ([\#8845](matrix-org/synapse#8845))
- Simplify `uk.half-shot.msc2778.login.application_service` login handler. ([\#8847](matrix-org/synapse#8847))
- Refactor `password_auth_provider` support code. ([\#8849](matrix-org/synapse#8849))
- Add missing `ordering` to background database updates. ([\#8850](matrix-org/synapse#8850))
- Allow for specifying a room version when creating a room in unit tests via `RestHelper.create_room_as`. ([\#8854](matrix-org/synapse#8854))
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants