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

Commit 2c2e649

Browse files
Move and refactor LoginRestServlet helper methods (#8182)
This is split out from #7438, which had gotten rather large. `LoginRestServlet` has a couple helper methods, `login_submission_legacy_convert` and `login_id_thirdparty_from_phone`. They're primarily used for converting legacy user login submissions to "identifier" dicts ([see spec](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-login)). Identifying information such as usernames or 3PID information used to be top-level in the login body. They're now supposed to be put inside an [identifier](https://matrix.org/docs/spec/client_server/r0.6.1#identifier-types) parameter instead. #7438's purpose is to allow using the new identifier parameter during User-Interactive Authentication, which is currently handled in AuthHandler. That's why I've moved these helper methods there. I also moved the refactoring of these method from #7438 as they're relevant.
1 parent e00816a commit 2c2e649

File tree

3 files changed

+94
-55
lines changed

3 files changed

+94
-55
lines changed

changelog.d/8182.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Refactor some of `LoginRestServlet`'s helper methods, and move them to `AuthHandler` for easier reuse.

synapse/handlers/auth.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,101 @@
4242
from synapse.logging.context import defer_to_thread
4343
from synapse.metrics.background_process_metrics import run_as_background_process
4444
from synapse.module_api import ModuleApi
45-
from synapse.types import Requester, UserID
45+
from synapse.types import JsonDict, Requester, UserID
4646
from synapse.util import stringutils as stringutils
47+
from synapse.util.msisdn import phone_number_to_msisdn
4748
from synapse.util.threepids import canonicalise_email
4849

4950
from ._base import BaseHandler
5051

5152
logger = logging.getLogger(__name__)
5253

5354

55+
def convert_client_dict_legacy_fields_to_identifier(
56+
submission: JsonDict,
57+
) -> Dict[str, str]:
58+
"""
59+
Convert a legacy-formatted login submission to an identifier dict.
60+
61+
Legacy login submissions (used in both login and user-interactive authentication)
62+
provide user-identifying information at the top-level instead.
63+
64+
These are now deprecated and replaced with identifiers:
65+
https://matrix.org/docs/spec/client_server/r0.6.1#identifier-types
66+
67+
Args:
68+
submission: The client dict to convert
69+
70+
Returns:
71+
The matching identifier dict
72+
73+
Raises:
74+
SynapseError: If the format of the client dict is invalid
75+
"""
76+
identifier = submission.get("identifier", {})
77+
78+
# Generate an m.id.user identifier if "user" parameter is present
79+
user = submission.get("user")
80+
if user:
81+
identifier = {"type": "m.id.user", "user": user}
82+
83+
# Generate an m.id.thirdparty identifier if "medium" and "address" parameters are present
84+
medium = submission.get("medium")
85+
address = submission.get("address")
86+
if medium and address:
87+
identifier = {
88+
"type": "m.id.thirdparty",
89+
"medium": medium,
90+
"address": address,
91+
}
92+
93+
# We've converted valid, legacy login submissions to an identifier. If the
94+
# submission still doesn't have an identifier, it's invalid
95+
if not identifier:
96+
raise SynapseError(400, "Invalid login submission", Codes.INVALID_PARAM)
97+
98+
# Ensure the identifier has a type
99+
if "type" not in identifier:
100+
raise SynapseError(
101+
400, "'identifier' dict has no key 'type'", errcode=Codes.MISSING_PARAM,
102+
)
103+
104+
return identifier
105+
106+
107+
def login_id_phone_to_thirdparty(identifier: JsonDict) -> Dict[str, str]:
108+
"""
109+
Convert a phone login identifier type to a generic threepid identifier.
110+
111+
Args:
112+
identifier: Login identifier dict of type 'm.id.phone'
113+
114+
Returns:
115+
An equivalent m.id.thirdparty identifier dict
116+
"""
117+
if "country" not in identifier or (
118+
# The specification requires a "phone" field, while Synapse used to require a "number"
119+
# field. Accept both for backwards compatibility.
120+
"phone" not in identifier
121+
and "number" not in identifier
122+
):
123+
raise SynapseError(
124+
400, "Invalid phone-type identifier", errcode=Codes.INVALID_PARAM
125+
)
126+
127+
# Accept both "phone" and "number" as valid keys in m.id.phone
128+
phone_number = identifier.get("phone", identifier["number"])
129+
130+
# Convert user-provided phone number to a consistent representation
131+
msisdn = phone_number_to_msisdn(identifier["country"], phone_number)
132+
133+
return {
134+
"type": "m.id.thirdparty",
135+
"medium": "msisdn",
136+
"address": msisdn,
137+
}
138+
139+
54140
class AuthHandler(BaseHandler):
55141
SESSION_EXPIRE_MS = 48 * 60 * 60 * 1000
56142

synapse/rest/client/v1/login.py

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919
from synapse.api.errors import Codes, LoginError, SynapseError
2020
from synapse.api.ratelimiting import Ratelimiter
21+
from synapse.handlers.auth import (
22+
convert_client_dict_legacy_fields_to_identifier,
23+
login_id_phone_to_thirdparty,
24+
)
2125
from synapse.http.server import finish_request
2226
from synapse.http.servlet import (
2327
RestServlet,
@@ -28,56 +32,11 @@
2832
from synapse.rest.client.v2_alpha._base import client_patterns
2933
from synapse.rest.well_known import WellKnownBuilder
3034
from synapse.types import JsonDict, UserID
31-
from synapse.util.msisdn import phone_number_to_msisdn
3235
from synapse.util.threepids import canonicalise_email
3336

3437
logger = logging.getLogger(__name__)
3538

3639

37-
def login_submission_legacy_convert(submission):
38-
"""
39-
If the input login submission is an old style object
40-
(ie. with top-level user / medium / address) convert it
41-
to a typed object.
42-
"""
43-
if "user" in submission:
44-
submission["identifier"] = {"type": "m.id.user", "user": submission["user"]}
45-
del submission["user"]
46-
47-
if "medium" in submission and "address" in submission:
48-
submission["identifier"] = {
49-
"type": "m.id.thirdparty",
50-
"medium": submission["medium"],
51-
"address": submission["address"],
52-
}
53-
del submission["medium"]
54-
del submission["address"]
55-
56-
57-
def login_id_thirdparty_from_phone(identifier):
58-
"""
59-
Convert a phone login identifier type to a generic threepid identifier
60-
Args:
61-
identifier(dict): Login identifier dict of type 'm.id.phone'
62-
63-
Returns: Login identifier dict of type 'm.id.threepid'
64-
"""
65-
if "country" not in identifier or (
66-
# The specification requires a "phone" field, while Synapse used to require a "number"
67-
# field. Accept both for backwards compatibility.
68-
"phone" not in identifier
69-
and "number" not in identifier
70-
):
71-
raise SynapseError(400, "Invalid phone-type identifier")
72-
73-
# Accept both "phone" and "number" as valid keys in m.id.phone
74-
phone_number = identifier.get("phone", identifier["number"])
75-
76-
msisdn = phone_number_to_msisdn(identifier["country"], phone_number)
77-
78-
return {"type": "m.id.thirdparty", "medium": "msisdn", "address": msisdn}
79-
80-
8140
class LoginRestServlet(RestServlet):
8241
PATTERNS = client_patterns("/login$", v1=True)
8342
CAS_TYPE = "m.login.cas"
@@ -194,18 +153,11 @@ async def _do_other_login(self, login_submission: JsonDict) -> Dict[str, str]:
194153
login_submission.get("address"),
195154
login_submission.get("user"),
196155
)
197-
login_submission_legacy_convert(login_submission)
198-
199-
if "identifier" not in login_submission:
200-
raise SynapseError(400, "Missing param: identifier")
201-
202-
identifier = login_submission["identifier"]
203-
if "type" not in identifier:
204-
raise SynapseError(400, "Login identifier has no type")
156+
identifier = convert_client_dict_legacy_fields_to_identifier(login_submission)
205157

206158
# convert phone type identifiers to generic threepids
207159
if identifier["type"] == "m.id.phone":
208-
identifier = login_id_thirdparty_from_phone(identifier)
160+
identifier = login_id_phone_to_thirdparty(identifier)
209161

210162
# convert threepid identifiers to user IDs
211163
if identifier["type"] == "m.id.thirdparty":

0 commit comments

Comments
 (0)