diff --git a/packages/overlays/matrix-synapse/patches/0018-Allow-only-requiring-a-field-be-present-in-an-SSO-re.patch b/packages/overlays/matrix-synapse/patches/0018-Allow-only-requiring-a-field-be-present-in-an-SSO-re.patch
new file mode 100644
index 0000000..9aba9cb
--- /dev/null
+++ b/packages/overlays/matrix-synapse/patches/0018-Allow-only-requiring-a-field-be-present-in-an-SSO-re.patch
@@ -0,0 +1,175 @@
+From 1f4ae2f9eb94808f651b683b4650092015ec39e1 Mon Sep 17 00:00:00 2001
+From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
+Date: Mon, 19 May 2025 17:50:02 +0100
+Subject: [PATCH 18/34] Allow only requiring a field be present in an SSO
+ response, rather than specifying a required value (#18454)
+
+---
+ changelog.d/18454.misc | 1 +
+ .../configuration/config_documentation.md | 10 ++-
+ synapse/config/sso.py | 7 +-
+ tests/handlers/test_oidc.py | 77 ++++++++++++++++++-
+ 4 files changed, 86 insertions(+), 9 deletions(-)
+ create mode 100644 changelog.d/18454.misc
+
+diff --git a/changelog.d/18454.misc b/changelog.d/18454.misc
+new file mode 100644
+index 0000000000..892fbd1d94
+--- /dev/null
++++ b/changelog.d/18454.misc
+@@ -0,0 +1 @@
++Allow checking only for the existence of a field in an SSO provider's response, rather than requiring the value(s) to check.
+\ No newline at end of file
+diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md
+index e688bc5cd8..3927b9ca14 100644
+--- a/docs/usage/configuration/config_documentation.md
++++ b/docs/usage/configuration/config_documentation.md
+@@ -3782,17 +3782,23 @@ match particular values in the OIDC userinfo. The requirements can be listed und
+ ```yaml
+ attribute_requirements:
+ - attribute: family_name
+- value: "Stephensson"
++ one_of: ["Stephensson", "Smith"]
+ - attribute: groups
+ value: "admin"
++ # If `value` or `one_of` are not specified, the attribute only needs
++ # to exist, regardless of value.
++ - attribute: picture
+ ```
++
++`attribute` is a required field, while `value` and `one_of` are optional.
++
+ All of the listed attributes must match for the login to be permitted. Additional attributes can be added to
+ userinfo by expanding the `scopes` section of the OIDC config to retrieve
+ additional information from the OIDC provider.
+
+ If the OIDC claim is a list, then the attribute must match any value in the list.
+ Otherwise, it must exactly match the value of the claim. Using the example
+-above, the `family_name` claim MUST be "Stephensson", but the `groups`
++above, the `family_name` claim MUST be either "Stephensson" or "Smith", but the `groups`
+ claim MUST contain "admin".
+
+ Example configuration:
+diff --git a/synapse/config/sso.py b/synapse/config/sso.py
+index 97b85e47ea..cf27a7ee13 100644
+--- a/synapse/config/sso.py
++++ b/synapse/config/sso.py
+@@ -43,8 +43,7 @@ class SsoAttributeRequirement:
+ """Object describing a single requirement for SSO attributes."""
+
+ attribute: str
+- # If neither value nor one_of is given, the attribute must simply exist. This is
+- # only true for CAS configs which use a different JSON schema than the one below.
++ # If neither `value` nor `one_of` is given, the attribute must simply exist.
+ value: Optional[str] = None
+ one_of: Optional[List[str]] = None
+
+@@ -56,10 +55,6 @@ class SsoAttributeRequirement:
+ "one_of": {"type": "array", "items": {"type": "string"}},
+ },
+ "required": ["attribute"],
+- "oneOf": [
+- {"required": ["value"]},
+- {"required": ["one_of"]},
+- ],
+ }
+
+
+diff --git a/tests/handlers/test_oidc.py b/tests/handlers/test_oidc.py
+index e5f31d57ca..ff8e3c5cb6 100644
+--- a/tests/handlers/test_oidc.py
++++ b/tests/handlers/test_oidc.py
+@@ -1453,7 +1453,7 @@ class OidcHandlerTestCase(HomeserverTestCase):
+ }
+ }
+ )
+- def test_attribute_requirements_one_of(self) -> None:
++ def test_attribute_requirements_one_of_succeeds(self) -> None:
+ """Test that auth succeeds if userinfo attribute has multiple values and CONTAINS required value"""
+ # userinfo with "test": ["bar"] attribute should succeed.
+ userinfo = {
+@@ -1475,6 +1475,81 @@ class OidcHandlerTestCase(HomeserverTestCase):
+ auth_provider_session_id=None,
+ )
+
++ @override_config(
++ {
++ "oidc_config": {
++ **DEFAULT_CONFIG,
++ "attribute_requirements": [
++ {"attribute": "test", "one_of": ["foo", "bar"]}
++ ],
++ }
++ }
++ )
++ def test_attribute_requirements_one_of_fails(self) -> None:
++ """Test that auth fails if userinfo attribute has multiple values yet
++ DOES NOT CONTAIN a required value
++ """
++ # userinfo with "test": ["something else"] attribute should fail.
++ userinfo = {
++ "sub": "tester",
++ "username": "tester",
++ "test": ["something else"],
++ }
++ request, _ = self.start_authorization(userinfo)
++ self.get_success(self.handler.handle_oidc_callback(request))
++ self.complete_sso_login.assert_not_called()
++
++ @override_config(
++ {
++ "oidc_config": {
++ **DEFAULT_CONFIG,
++ "attribute_requirements": [{"attribute": "test"}],
++ }
++ }
++ )
++ def test_attribute_requirements_does_not_exist(self) -> None:
++ """OIDC login fails if the required attribute does not exist in the OIDC userinfo response."""
++ # userinfo lacking "test" attribute should fail.
++ userinfo = {
++ "sub": "tester",
++ "username": "tester",
++ }
++ request, _ = self.start_authorization(userinfo)
++ self.get_success(self.handler.handle_oidc_callback(request))
++ self.complete_sso_login.assert_not_called()
++
++ @override_config(
++ {
++ "oidc_config": {
++ **DEFAULT_CONFIG,
++ "attribute_requirements": [{"attribute": "test"}],
++ }
++ }
++ )
++ def test_attribute_requirements_exist(self) -> None:
++ """OIDC login succeeds if the required attribute exist (regardless of value)
++ in the OIDC userinfo response.
++ """
++ # userinfo with "test" attribute and random value should succeed.
++ userinfo = {
++ "sub": "tester",
++ "username": "tester",
++ "test": random_string(5), # value does not matter
++ }
++ request, _ = self.start_authorization(userinfo)
++ self.get_success(self.handler.handle_oidc_callback(request))
++
++ # check that the auth handler got called as expected
++ self.complete_sso_login.assert_called_once_with(
++ "@tester:test",
++ self.provider.idp_id,
++ request,
++ ANY,
++ None,
++ new_user=True,
++ auth_provider_session_id=None,
++ )
++
+ @override_config(
+ {
+ "oidc_config": {
+--
+2.49.0
+
|