Skip to content

Commit

Permalink
Use custom stage UIA error for MAS cross-signing reset (#17509)
Browse files Browse the repository at this point in the history
Rather than 501 M_UNRECOGNISED

Client side implementation at
matrix-org/matrix-react-sdk#12892
  • Loading branch information
t3chguy authored Aug 30, 2024
1 parent cdd5979 commit 02ebcf7
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 18 deletions.
1 change: 1 addition & 0 deletions changelog.d/17509.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve cross-signing upload when using [MSC3861](https://github.com/matrix-org/matrix-spec-proposals/pull/3861) to use a custom UIA flow stage, with web fallback support.
13 changes: 12 additions & 1 deletion synapse/rest/client/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from synapse.api.constants import LoginType
from synapse.api.errors import LoginError, SynapseError
from synapse.api.urls import CLIENT_API_PREFIX
from synapse.http.server import HttpServer, respond_with_html
from synapse.http.server import HttpServer, respond_with_html, respond_with_redirect
from synapse.http.servlet import RestServlet, parse_string
from synapse.http.site import SynapseRequest

Expand Down Expand Up @@ -66,6 +66,17 @@ async def on_GET(self, request: SynapseRequest, stagetype: str) -> None:
if not session:
raise SynapseError(400, "No session supplied")

if (
self.hs.config.experimental.msc3861.enabled
and stagetype == "org.matrix.cross_signing_reset"
):
config = self.hs.config.experimental.msc3861
if config.account_management_url is not None:
url = f"{config.account_management_url}?action=org.matrix.cross_signing_reset"
else:
url = config.issuer
respond_with_redirect(request, str.encode(url))

if stagetype == LoginType.RECAPTCHA:
html = self.recaptcha_template.render(
session=session,
Expand Down
30 changes: 23 additions & 7 deletions synapse/rest/client/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
import logging
import re
from collections import Counter
from http import HTTPStatus
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple

from synapse.api.errors import Codes, InvalidAPICallError, SynapseError
from synapse.api.errors import (
InteractiveAuthIncompleteError,
InvalidAPICallError,
SynapseError,
)
from synapse.http.server import HttpServer
from synapse.http.servlet import (
RestServlet,
Expand Down Expand Up @@ -409,11 +412,24 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
else:
url = config.issuer

raise SynapseError(
HTTPStatus.NOT_IMPLEMENTED,
"To reset your end-to-end encryption cross-signing identity, "
f"you first need to approve it at {url} and then try again.",
Codes.UNRECOGNIZED,
# We use a dummy session ID as this isn't really a UIA flow, but we
# reuse the same API shape for better client compatibility.
raise InteractiveAuthIncompleteError(
"dummy",
{
"session": "dummy",
"flows": [
{"stages": ["org.matrix.cross_signing_reset"]},
],
"params": {
"org.matrix.cross_signing_reset": {
"url": url,
},
},
"msg": "To reset your end-to-end encryption cross-signing "
f"identity, you first need to approve it at {url} and "
"then try again.",
},
)
else:
# Without MSC3861, we require UIA.
Expand Down
2 changes: 1 addition & 1 deletion tests/handlers/test_oauth_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ def test_cross_signing(self) -> None:
access_token="mockAccessToken",
)

self.assertEqual(channel.code, HTTPStatus.NOT_IMPLEMENTED, channel.json_body)
self.assertEqual(channel.code, HTTPStatus.UNAUTHORIZED, channel.json_body)

def expect_unauthorized(
self, method: str, path: str, content: Union[bytes, str, JsonDict] = ""
Expand Down
12 changes: 3 additions & 9 deletions tests/rest/client/test_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,7 @@ async def mocked_get_user_by_access_token(
"master_key": master_key2,
},
)
self.assertEqual(
channel.code, HTTPStatus.NOT_IMPLEMENTED, channel.json_body
)
self.assertEqual(channel.code, HTTPStatus.UNAUTHORIZED, channel.json_body)

# Pretend that MAS did UIA and allowed us to replace the master key.
channel = self.make_request(
Expand Down Expand Up @@ -349,9 +347,7 @@ async def mocked_get_user_by_access_token(
"master_key": master_key3,
},
)
self.assertEqual(
channel.code, HTTPStatus.NOT_IMPLEMENTED, channel.json_body
)
self.assertEqual(channel.code, HTTPStatus.UNAUTHORIZED, channel.json_body)

# Pretend that MAS did UIA and allowed us to replace the master key.
channel = self.make_request(
Expand All @@ -376,6 +372,4 @@ async def mocked_get_user_by_access_token(
"master_key": master_key3,
},
)
self.assertEqual(
channel.code, HTTPStatus.NOT_IMPLEMENTED, channel.json_body
)
self.assertEqual(channel.code, HTTPStatus.UNAUTHORIZED, channel.json_body)

0 comments on commit 02ebcf7

Please sign in to comment.