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

Commit 273b686

Browse files
authored
Remove unstable MSC2858 API, including experimental.msc2858_enabled config option (#10693)
Signed-off-by: Sean Quah <seanq@element.io>
1 parent a621ba0 commit 273b686

File tree

9 files changed

+19
-127
lines changed

9 files changed

+19
-127
lines changed

changelog.d/10693.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove [unstable MSC2858 API](https://github.com/matrix-org/matrix-doc/blob/master/proposals/2858-Multiple-SSO-Identity-Providers.md#unstable-prefix), including the undocumented `experimental.msc2858_enabled` config option. The unstable API has been deprecated since Synapse 1.35. Client authors should update their clients to use the stable API introduced in Synapse 1.30 if they have not already done so.

synapse/config/experimental.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ class ExperimentalConfig(Config):
2424
def read_config(self, config: JsonDict, **kwargs):
2525
experimental = config.get("experimental_features") or {}
2626

27-
# MSC2858 (multiple SSO identity providers)
28-
self.msc2858_enabled: bool = experimental.get("msc2858_enabled", False)
29-
3027
# MSC3026 (busy presence state)
3128
self.msc3026_enabled: bool = experimental.get("msc3026_enabled", False)
3229

synapse/config/oidc.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,6 @@ def generate_config_section(self, config_dir_path, server_name, **kwargs):
277277
"maxLength": 255,
278278
"pattern": "^[a-z][a-z0-9_.-]*$",
279279
},
280-
"idp_unstable_brand": {
281-
"type": "string",
282-
"minLength": 1,
283-
"maxLength": 255,
284-
"pattern": "^[a-z][a-z0-9_.-]*$",
285-
},
286280
"discover": {"type": "boolean"},
287281
"issuer": {"type": "string"},
288282
"client_id": {"type": "string"},
@@ -483,7 +477,6 @@ def _parse_oidc_config_dict(
483477
idp_name=oidc_config.get("idp_name", "OIDC"),
484478
idp_icon=idp_icon,
485479
idp_brand=oidc_config.get("idp_brand"),
486-
unstable_idp_brand=oidc_config.get("unstable_idp_brand"),
487480
discover=oidc_config.get("discover", True),
488481
issuer=oidc_config["issuer"],
489482
client_id=oidc_config["client_id"],
@@ -531,9 +524,6 @@ class OidcProviderConfig:
531524
# Optional brand identifier for this IdP.
532525
idp_brand = attr.ib(type=Optional[str])
533526

534-
# Optional brand identifier for the unstable API (see MSC2858).
535-
unstable_idp_brand = attr.ib(type=Optional[str])
536-
537527
# whether the OIDC discovery mechanism is used to discover endpoints
538528
discover = attr.ib(type=bool)
539529

synapse/handlers/cas.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ def __init__(self, hs: "HomeServer"):
8282
# the SsoIdentityProvider protocol type.
8383
self.idp_icon = None
8484
self.idp_brand = None
85-
self.unstable_idp_brand = None
8685

8786
self._sso_handler = hs.get_sso_handler()
8887

synapse/handlers/oidc.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,9 +338,6 @@ def __init__(
338338
# optional brand identifier for this auth provider
339339
self.idp_brand = provider.idp_brand
340340

341-
# Optional brand identifier for the unstable API (see MSC2858).
342-
self.unstable_idp_brand = provider.unstable_idp_brand
343-
344341
self._sso_handler = hs.get_sso_handler()
345342

346343
self._sso_handler.register_identity_provider(self)

synapse/handlers/saml.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ def __init__(self, hs: "HomeServer"):
8080
# the SsoIdentityProvider protocol type.
8181
self.idp_icon = None
8282
self.idp_brand = None
83-
self.unstable_idp_brand = None
8483

8584
# a map from saml session id to Saml2SessionData object
8685
self._outstanding_requests_dict: Dict[str, Saml2SessionData] = {}

synapse/handlers/sso.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,6 @@ def idp_brand(self) -> Optional[str]:
104104
"""Optional branding identifier"""
105105
return None
106106

107-
@property
108-
def unstable_idp_brand(self) -> Optional[str]:
109-
"""Optional brand identifier for the unstable API (see MSC2858)."""
110-
return None
111-
112107
@abc.abstractmethod
113108
async def handle_redirect_request(
114109
self,

synapse/rest/client/login.py

Lines changed: 11 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ def __init__(self, hs: "HomeServer"):
7979
self.saml2_enabled = hs.config.saml2_enabled
8080
self.cas_enabled = hs.config.cas_enabled
8181
self.oidc_enabled = hs.config.oidc_enabled
82-
self._msc2858_enabled = hs.config.experimental.msc2858_enabled
8382
self._msc2918_enabled = hs.config.access_token_lifetime is not None
8483

8584
self.auth = hs.get_auth()
@@ -111,7 +110,7 @@ def __init__(self, hs: "HomeServer"):
111110
_load_sso_handlers(hs)
112111

113112
def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
114-
flows = []
113+
flows: List[JsonDict] = []
115114
if self.jwt_enabled:
116115
flows.append({"type": LoginRestServlet.JWT_TYPE})
117116
flows.append({"type": LoginRestServlet.JWT_TYPE_DEPRECATED})
@@ -122,25 +121,15 @@ def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
122121
flows.append({"type": LoginRestServlet.CAS_TYPE})
123122

124123
if self.cas_enabled or self.saml2_enabled or self.oidc_enabled:
125-
sso_flow: JsonDict = {
126-
"type": LoginRestServlet.SSO_TYPE,
127-
"identity_providers": [
128-
_get_auth_flow_dict_for_idp(
129-
idp,
130-
)
131-
for idp in self._sso_handler.get_identity_providers().values()
132-
],
133-
}
134-
135-
if self._msc2858_enabled:
136-
# backwards-compatibility support for clients which don't
137-
# support the stable API yet
138-
sso_flow["org.matrix.msc2858.identity_providers"] = [
139-
_get_auth_flow_dict_for_idp(idp, use_unstable_brands=True)
140-
for idp in self._sso_handler.get_identity_providers().values()
141-
]
142-
143-
flows.append(sso_flow)
124+
flows.append(
125+
{
126+
"type": LoginRestServlet.SSO_TYPE,
127+
"identity_providers": [
128+
_get_auth_flow_dict_for_idp(idp)
129+
for idp in self._sso_handler.get_identity_providers().values()
130+
],
131+
}
132+
)
144133

145134
# While it's valid for us to advertise this login type generally,
146135
# synapse currently only gives out these tokens as part of the
@@ -433,27 +422,20 @@ async def _do_jwt_login(
433422
return result
434423

435424

436-
def _get_auth_flow_dict_for_idp(
437-
idp: SsoIdentityProvider, use_unstable_brands: bool = False
438-
) -> JsonDict:
425+
def _get_auth_flow_dict_for_idp(idp: SsoIdentityProvider) -> JsonDict:
439426
"""Return an entry for the login flow dict
440427
441428
Returns an entry suitable for inclusion in "identity_providers" in the
442429
response to GET /_matrix/client/r0/login
443430
444431
Args:
445432
idp: the identity provider to describe
446-
use_unstable_brands: whether we should use brand identifiers suitable
447-
for the unstable API
448433
"""
449434
e: JsonDict = {"id": idp.idp_id, "name": idp.idp_name}
450435
if idp.idp_icon:
451436
e["icon"] = idp.idp_icon
452437
if idp.idp_brand:
453438
e["brand"] = idp.idp_brand
454-
# use the stable brand identifier if the unstable identifier isn't defined.
455-
if use_unstable_brands and idp.unstable_idp_brand:
456-
e["brand"] = idp.unstable_idp_brand
457439
return e
458440

459441

@@ -504,25 +486,8 @@ def __init__(self, hs: "HomeServer"):
504486
# register themselves with the main SSOHandler.
505487
_load_sso_handlers(hs)
506488
self._sso_handler = hs.get_sso_handler()
507-
self._msc2858_enabled = hs.config.experimental.msc2858_enabled
508489
self._public_baseurl = hs.config.public_baseurl
509490

510-
def register(self, http_server: HttpServer) -> None:
511-
super().register(http_server)
512-
if self._msc2858_enabled:
513-
# expose additional endpoint for MSC2858 support: backwards-compat support
514-
# for clients which don't yet support the stable endpoints.
515-
http_server.register_paths(
516-
"GET",
517-
client_patterns(
518-
"/org.matrix.msc2858/login/sso/redirect/(?P<idp_id>[A-Za-z0-9_.~-]+)$",
519-
releases=(),
520-
unstable=True,
521-
),
522-
self.on_GET,
523-
self.__class__.__name__,
524-
)
525-
526491
async def on_GET(
527492
self, request: SynapseRequest, idp_id: Optional[str] = None
528493
) -> None:

tests/rest/client/test_login.py

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -445,26 +445,9 @@ def test_get_login_flows(self):
445445
[f["type"] for f in channel.json_body["flows"]], expected_flow_types
446446
)
447447

448-
@override_config({"experimental_features": {"msc2858_enabled": True}})
449-
def test_get_msc2858_login_flows(self):
450-
"""The SSO flow should include IdP info if MSC2858 is enabled"""
451-
channel = self.make_request("GET", "/_matrix/client/r0/login")
452-
self.assertEqual(channel.code, 200, channel.result)
453-
454-
# stick the flows results in a dict by type
455-
flow_results: Dict[str, Any] = {}
456-
for f in channel.json_body["flows"]:
457-
flow_type = f["type"]
458-
self.assertNotIn(
459-
flow_type, flow_results, "duplicate flow type %s" % (flow_type,)
460-
)
461-
flow_results[flow_type] = f
462-
463-
self.assertIn("m.login.sso", flow_results, "m.login.sso was not returned")
464-
sso_flow = flow_results.pop("m.login.sso")
465-
# we should have a set of IdPs
448+
flows = {flow["type"]: flow for flow in channel.json_body["flows"]}
466449
self.assertCountEqual(
467-
sso_flow["org.matrix.msc2858.identity_providers"],
450+
flows["m.login.sso"]["identity_providers"],
468451
[
469452
{"id": "cas", "name": "CAS"},
470453
{"id": "saml", "name": "SAML"},
@@ -473,19 +456,10 @@ def test_get_msc2858_login_flows(self):
473456
],
474457
)
475458

476-
# the rest of the flows are simple
477-
expected_flows = [
478-
{"type": "m.login.cas"},
479-
{"type": "m.login.token"},
480-
{"type": "m.login.password"},
481-
] + ADDITIONAL_LOGIN_FLOWS
482-
483-
self.assertCountEqual(flow_results.values(), expected_flows)
484-
485459
def test_multi_sso_redirect(self):
486460
"""/login/sso/redirect should redirect to an identity picker"""
487461
# first hit the redirect url, which should redirect to our idp picker
488-
channel = self._make_sso_redirect_request(False, None)
462+
channel = self._make_sso_redirect_request(None)
489463
self.assertEqual(channel.code, 302, channel.result)
490464
uri = channel.headers.getRawHeaders("Location")[0]
491465

@@ -637,51 +611,26 @@ def test_multi_sso_redirect_to_unknown(self):
637611

638612
def test_client_idp_redirect_to_unknown(self):
639613
"""If the client tries to pick an unknown IdP, return a 404"""
640-
channel = self._make_sso_redirect_request(False, "xxx")
614+
channel = self._make_sso_redirect_request("xxx")
641615
self.assertEqual(channel.code, 404, channel.result)
642616
self.assertEqual(channel.json_body["errcode"], "M_NOT_FOUND")
643617

644618
def test_client_idp_redirect_to_oidc(self):
645619
"""If the client pick a known IdP, redirect to it"""
646-
channel = self._make_sso_redirect_request(False, "oidc")
647-
self.assertEqual(channel.code, 302, channel.result)
648-
oidc_uri = channel.headers.getRawHeaders("Location")[0]
649-
oidc_uri_path, oidc_uri_query = oidc_uri.split("?", 1)
650-
651-
# it should redirect us to the auth page of the OIDC server
652-
self.assertEqual(oidc_uri_path, TEST_OIDC_AUTH_ENDPOINT)
653-
654-
@override_config({"experimental_features": {"msc2858_enabled": True}})
655-
def test_client_msc2858_redirect_to_oidc(self):
656-
"""Test the unstable API"""
657-
channel = self._make_sso_redirect_request(True, "oidc")
620+
channel = self._make_sso_redirect_request("oidc")
658621
self.assertEqual(channel.code, 302, channel.result)
659622
oidc_uri = channel.headers.getRawHeaders("Location")[0]
660623
oidc_uri_path, oidc_uri_query = oidc_uri.split("?", 1)
661624

662625
# it should redirect us to the auth page of the OIDC server
663626
self.assertEqual(oidc_uri_path, TEST_OIDC_AUTH_ENDPOINT)
664627

665-
def test_client_idp_redirect_msc2858_disabled(self):
666-
"""If the client tries to use the MSC2858 endpoint but MSC2858 is disabled, return a 400"""
667-
channel = self._make_sso_redirect_request(True, "oidc")
668-
self.assertEqual(channel.code, 400, channel.result)
669-
self.assertEqual(channel.json_body["errcode"], "M_UNRECOGNIZED")
670-
671-
def _make_sso_redirect_request(
672-
self, unstable_endpoint: bool = False, idp_prov: Optional[str] = None
673-
):
628+
def _make_sso_redirect_request(self, idp_prov: Optional[str] = None):
674629
"""Send a request to /_matrix/client/r0/login/sso/redirect
675630
676-
... or the unstable equivalent
677-
678631
... possibly specifying an IDP provider
679632
"""
680-
endpoint = (
681-
"/_matrix/client/unstable/org.matrix.msc2858/login/sso/redirect"
682-
if unstable_endpoint
683-
else "/_matrix/client/r0/login/sso/redirect"
684-
)
633+
endpoint = "/_matrix/client/r0/login/sso/redirect"
685634
if idp_prov is not None:
686635
endpoint += "/" + idp_prov
687636
endpoint += "?redirectUrl=" + urllib.parse.quote_plus(TEST_CLIENT_REDIRECT_URL)

0 commit comments

Comments
 (0)