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

Handle "registration_enabled" parameter for CAS #16262

Merged
merged 15 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/16262.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the ability to enable/disable registrations when in the CAS flow. Contributed by Aurélien Grimpard.
7 changes: 7 additions & 0 deletions docs/usage/configuration/config_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3428,6 +3428,12 @@ Has the following sub-options:
and the values must match the given value. Alternately if the given value
is `None` then any value is allowed (the attribute just must exist).
All of the listed attributes must match for the login to be permitted.
* `enable_registration`: set to 'false' to disable automatic registration of new
users. This allows the CAS SSO flow to be limited to sign in only, rather than
automatically registering users that have a valid SSO login but do not have
a pre-registered account. Defaults to true.
clokep marked this conversation as resolved.
Show resolved Hide resolved

*Added in Synapse 1.93.0.*

Example configuration:
```yaml
Expand All @@ -3439,6 +3445,7 @@ cas_config:
required_attributes:
userGroup: "staff"
department: None
enable_registration: true
```
---
### `sso`
Expand Down
3 changes: 3 additions & 0 deletions synapse/config/cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
required_attributes
)

self.cas_enable_registration = cas_config.get("enable_registration", True)

self.idp_name = cas_config.get("idp_name", "CAS")
self.idp_icon = cas_config.get("idp_icon")
self.idp_brand = cas_config.get("idp_brand")
Expand All @@ -67,6 +69,7 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
self.cas_protocol_version = None
self.cas_displayname_attribute = None
self.cas_required_attributes = []
self.cas_enable_registration = False


# CAS uses a legacy required attributes mapping, not the one provided by
Expand Down
2 changes: 2 additions & 0 deletions synapse/handlers/cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__(self, hs: "HomeServer"):
self._cas_protocol_version = hs.config.cas.cas_protocol_version
self._cas_displayname_attribute = hs.config.cas.cas_displayname_attribute
self._cas_required_attributes = hs.config.cas.cas_required_attributes
self._cas_enable_registration = hs.config.cas.cas_enable_registration

self._http_client = hs.get_proxied_http_client()

Expand Down Expand Up @@ -395,4 +396,5 @@ async def grandfather_existing_users() -> Optional[str]:
client_redirect_url,
cas_response_to_user_attributes,
grandfather_existing_users,
registration_enabled=self._cas_enable_registration,
)
17 changes: 17 additions & 0 deletions tests/handlers/test_cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,23 @@ def test_required_attributes(self) -> None:
auth_provider_session_id=None,
)

@override_config({"cas_config": {"enable_registration": False}})
def test_map_cas_user_does_not_register_new_user(self) -> None:
"""Ensures new users are not registered if the enabled registration flag is disabled."""

# stub out the auth handler
auth_handler = self.hs.get_auth_handler()
auth_handler.complete_sso_login = AsyncMock() # type: ignore[method-assign]

cas_response = CasResponse("test_user", {})
request = _mock_request()
self.get_success(
self.handler._handle_cas_response(request, cas_response, "redirect_uri", "")
)

# check that the auth handler was not called as expected
auth_handler.complete_sso_login.assert_not_called()


def _mock_request() -> Mock:
"""Returns a mock which will stand in as a SynapseRequest"""
Expand Down
Loading