-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Allow for identifier
dicts in User Interactive Auth dicts
#7438
Conversation
identifier
dicts in User Interactive Auth dicts
cc02e3c
to
cc2576f
Compare
We then use this in both login and authhandler, the latter being where we process m.login.password User Interactive Authentication responses, which can now include identifiers
020209e
to
699904c
Compare
synapse/handlers/auth.py
Outdated
SynapseError: if the dict contains a "medium" parameter that is anything other than | ||
"email" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment seems wrong? It raises if the format is invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that was a check I added, as that's technically required by the spec for login although it's a bit of a weird requirement if identifier
is allowed to be m.id.phone
.
Will remove the comment though.
synapse/rest/client/v1/login.py
Outdated
) | ||
if medium and address: | ||
self._failed_attempts_ratelimiter.ratelimit( | ||
(medium.lower(), address.lower()), update=False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lower-casing of medium
here seems to be a change in behavior? Or maybe I can't follow the logic...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Yes it is, and apologies for not calling it out during the commit.
This would've allowed someone to bypass the ratelimiter by specifying eMail
or some other combination of capitalisation.
However, now that I'm testing it, this trickery will get caught later on in the flow anyways, and return an immediate 403 before trying anything CPU-heavy like password hashing.
So it's not too sensitive - but I am going to pull it out of here into another PR as I think it's worthwhile, but needs more careful thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please do! 👍
# We mark that we've failed to log in here, as | ||
# `check_password_provider_3pid` might have returned `None` due | ||
# to an incorrect password, rather than the account not | ||
# existing. | ||
# | ||
# If it returned None but the 3PID was bound then we won't hit | ||
# this code path, which is fine as then the per-user ratelimit | ||
# will kick in below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment seems more helpful than the new version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I think things have slightly changed now though (which may or may not be an issue as well).
> # If it returned None but the 3PID was bound then we won't hit
> # this code path,
This is no longer true. If None
is returned by username_from_identifier
and a medium
and address
was used, then we will check the ratelimiter. This sounds sensible, but it is a change from before, where it seems like the code would rate limit on the User ID instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm...I think I was thinking the part about the incorrect password vs. the account not existing seems useful to keep (if that's still true).
synapse/rest/client/v1/login.py
Outdated
result = await self._complete_login( | ||
canonical_user_id, login_submission, callback_3pid | ||
) | ||
return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code path seems to now go through an additional self.auth_handler.validate_login
, I don't know if that's OK or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha, yes good spot.
I believe this originally did not as we have already validated the password via the password auth provider, so there's no need to validate_login
at that point (which will itself ask password auth providers with a user_id/password combo).
Considering this would change Synapse's behaviour related to third-party code we should probably try to get the behaviour to match.
if identifier["user"].startswith("@"): | ||
qualified_user_id = identifier["user"] | ||
else: | ||
qualified_user_id = UserID(identifier["user"], self.hs.hostname).to_string() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic seems to have disappeared.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It moved to AuthHandler.validate_login
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, actually this was always in validate_login
, I think? So this was just duplicated?
class DummyPasswordChecker(UserInteractiveAuthChecker): | ||
def check_auth(self, authdict, clientip): | ||
return succeed(authdict["identifier"]["user"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just not used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was used by 1807115#diff-5fc780094ae3ec668024efd505af6a3dL170
This checker was a patch to allow for identifiers being passed to AuthHandler.check_auth
, but this PR removes the need for it as it providers that functionality.
# https://github.com/matrix-org/synapse/issues/5665 | ||
# "identifier": {"type": "m.id.user", "user": user_id}, | ||
"user": user_id, | ||
"identifier": {"type": "m.id.user", "user": user_id}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We likely still want a test for the legacy login type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, so the login
unittest function still uses the old method:
Lines 512 to 518 in c2e1a21
def login(self, username, password, device_id=None): | |
""" | |
Log in a user, and get an access token. Requires the Login API be | |
registered. | |
""" | |
body = {"type": "m.login.password", "user": username, "password": password} |
But it may be a better idea to update this to the new format and just have a specific test for the old behaviour?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look crazy, but it does modify a lot of code.
I do wonder if the conversion of the legacy login to identifier dicts should be done at the REST layer and the handlers become a bit purer. I don't know how many callers there are though (and this isn't a requirement, just a thought).
Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com>
I've noticed that the User ID ratelimiter now ratelimits on |
c868274
to
af21fbb
Compare
…r_param_ui_auth * 'develop' of github.com:matrix-org/synapse: (369 commits) Add functions to `MultiWriterIdGen` used by events stream (#8164) Do not allow send_nonmember_event to be called with shadow-banned users. (#8158) Changelog fixes 1.19.1rc1 Make StreamIdGen `get_next` and `get_next_mult` async (#8161) Wording fixes to 'name' user admin api filter (#8163) Fix missing double-backtick in RST document Search in columns 'name' and 'displayname' in the admin users endpoint (#7377) Add type hints for state. (#8140) Stop shadow-banned users from sending non-member events. (#8142) Allow capping a room's retention policy (#8104) Add healthcheck for default localhost 8008 port on /health endpoint. (#8147) Fix flaky shadow-ban tests. (#8152) Fix join ratelimiter breaking profile updates and idempotency (#8153) Do not apply ratelimiting on joins to appservices (#8139) Don't fail /submit_token requests on incorrect session ID if request_token_inhibit_3pid_errors is turned on (#7991) Do not apply ratelimiting on joins to appservices (#8139) Micro-optimisations to get_auth_chain_ids (#8132) Allow denying or shadow banning registrations via the spam checker (#8034) Stop shadow-banned users from sending invites. (#8095) ...
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.
Closing this for now as the code is just bitrotting. Though I do plan to break this up further and apply it against |
A stab at fixing #5665
Allows
identifier
dicts to be used in UIA flows and relaxes the requirement of auser
parameter, which has since been deprecated. Relevant spec: https://matrix.org/docs/spec/client_server/r0.6.1#identifier-typesWarning: This deals with UIA and login and may break both - careful review required.
Requires: #7687
Should be reviewable commit-by-commit.
Note: This PR reworks the end of
_check_auth_dict
, which was essentially the place wherem.login.password
UI Auth steps were handled. In a future PR, it may be cleaner to move that code into an instance ofUserInteractiveAuthChecker
in synapse/handlers/ui_auth/checkers.py.