diff --git a/changelog.d/17098.feature b/changelog.d/17098.feature new file mode 100644 index 00000000000..43e06481b2c --- /dev/null +++ b/changelog.d/17098.feature @@ -0,0 +1 @@ +Add the ability to allow numeric user IDs with a specific prefix when in the CAS flow. Contributed by Aurélien Grimpard. diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 2257318bcc4..f4edbdcc3e6 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3558,6 +3558,15 @@ Has the following sub-options: 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. +* `allow_numeric_ids`: set to 'true' allow numeric user IDs (default false). + This allows CAS SSO flow to provide user IDs composed of numbers only. + These identifiers will be prefixed by the letter "u" by default. + The prefix can be configured using the "numeric_ids_prefix" option. + Be careful to choose the prefix correctly to avoid any possible conflicts + (e.g. user 1234 becomes u1234 when a user u1234 already exists). +* `numeric_ids_prefix`: the prefix you wish to add in front of a numeric user ID + when the "allow_numeric_ids" option is set to "true". + By default, the prefix is the letter "u" and only alphanumeric characters are allowed. *Added in Synapse 1.93.0.* @@ -3572,6 +3581,8 @@ cas_config: userGroup: "staff" department: None enable_registration: true + allow_numeric_ids: true + numeric_ids_prefix: "numericuser" ``` --- ### `sso` diff --git a/synapse/config/cas.py b/synapse/config/cas.py index d23dcf96b20..fa59c350c15 100644 --- a/synapse/config/cas.py +++ b/synapse/config/cas.py @@ -66,6 +66,17 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None: self.cas_enable_registration = cas_config.get("enable_registration", True) + self.cas_allow_numeric_ids = cas_config.get("allow_numeric_ids") + self.cas_numeric_ids_prefix = cas_config.get("numeric_ids_prefix") + if ( + self.cas_numeric_ids_prefix is not None + and self.cas_numeric_ids_prefix.isalnum() is False + ): + raise ConfigError( + "Only alphanumeric characters are allowed for numeric IDs prefix", + ("cas_config", "numeric_ids_prefix"), + ) + 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") @@ -77,6 +88,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None: self.cas_displayname_attribute = None self.cas_required_attributes = [] self.cas_enable_registration = False + self.cas_allow_numeric_ids = False + self.cas_numeric_ids_prefix = "u" # CAS uses a legacy required attributes mapping, not the one provided by diff --git a/synapse/handlers/cas.py b/synapse/handlers/cas.py index 153123ee831..cc3d641b7d8 100644 --- a/synapse/handlers/cas.py +++ b/synapse/handlers/cas.py @@ -78,6 +78,8 @@ def __init__(self, hs: "HomeServer"): 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._cas_allow_numeric_ids = hs.config.cas.cas_allow_numeric_ids + self._cas_numeric_ids_prefix = hs.config.cas.cas_numeric_ids_prefix self._http_client = hs.get_proxied_http_client() @@ -188,6 +190,9 @@ def _parse_cas_response(self, cas_response_body: bytes) -> CasResponse: for child in root[0]: if child.tag.endswith("user"): user = child.text + # if numeric user IDs are allowed and username is numeric then we add the prefix so Synapse can handle it + if self._cas_allow_numeric_ids and user is not None and user.isdigit(): + user = f"{self._cas_numeric_ids_prefix}{user}" if child.tag.endswith("attributes"): for attribute in child: # ElementTree library expands the namespace in