summary refs log tree commit diff
path: root/synapse/handlers/auth.py
diff options
context:
space:
mode:
authorErik Johnston <erik@matrix.org>2015-08-21 12:51:14 +0100
committerErik Johnston <erik@matrix.org>2015-08-21 12:51:14 +0100
commit5dbd10247055dd6c216503b69902a6e235fcb7e8 (patch)
treef0e05422ef4f880b9b4f4eeece4624feffd3b528 /synapse/handlers/auth.py
parentFix bug where we didn't correctly serialize the redacted_because key over fed... (diff)
parentDoc string (diff)
downloadsynapse-5dbd10247055dd6c216503b69902a6e235fcb7e8.tar.xz
Merge branch 'erikj/user_dedup' into release-v0.10.0
Diffstat (limited to 'synapse/handlers/auth.py')
-rw-r--r--synapse/handlers/auth.py37
1 files changed, 29 insertions, 8 deletions
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py
index ff2c66f442..602c5bcd89 100644
--- a/synapse/handlers/auth.py
+++ b/synapse/handlers/auth.py
@@ -162,7 +162,8 @@ class AuthHandler(BaseHandler):
         if not user_id.startswith('@'):
             user_id = UserID.create(user_id, self.hs.hostname).to_string()
 
-        yield self._check_password(user_id, password)
+        user_id, password_hash = yield self._find_user_id_and_pwd_hash(user_id)
+        self._check_password(user_id, password, password_hash)
         defer.returnValue(user_id)
 
     @defer.inlineCallbacks
@@ -283,23 +284,43 @@ class AuthHandler(BaseHandler):
             StoreError if there was a problem storing the token.
             LoginError if there was an authentication problem.
         """
-        yield self._check_password(user_id, password)
+        user_id, password_hash = yield self._find_user_id_and_pwd_hash(user_id)
+        self._check_password(user_id, password, password_hash)
 
         reg_handler = self.hs.get_handlers().registration_handler
         access_token = reg_handler.generate_token(user_id)
         logger.info("Logging in user %s", user_id)
         yield self.store.add_access_token_to_user(user_id, access_token)
-        defer.returnValue(access_token)
+        defer.returnValue((user_id, access_token))
 
     @defer.inlineCallbacks
-    def _check_password(self, user_id, password):
-        """Checks that user_id has passed password, raises LoginError if not."""
-        user_info = yield self.store.get_user_by_id(user_id=user_id)
-        if not user_info:
+    def _find_user_id_and_pwd_hash(self, user_id):
+        """Checks to see if a user with the given id exists. Will check case
+        insensitively, but will throw if there are multiple inexact matches.
+
+        Returns:
+            tuple: A 2-tuple of `(canonical_user_id, password_hash)`
+        """
+        user_infos = yield self.store.get_users_by_id_case_insensitive(user_id)
+        if not user_infos:
             logger.warn("Attempted to login as %s but they do not exist", user_id)
             raise LoginError(403, "", errcode=Codes.FORBIDDEN)
 
-        stored_hash = user_info["password_hash"]
+        if len(user_infos) > 1:
+            if user_id not in user_infos:
+                logger.warn(
+                    "Attempted to login as %s but it matches more than one user "
+                    "inexactly: %r",
+                    user_id, user_infos.keys()
+                )
+                raise LoginError(403, "", errcode=Codes.FORBIDDEN)
+
+            defer.returnValue((user_id, user_infos[user_id]))
+        else:
+            defer.returnValue(user_infos.popitem())
+
+    def _check_password(self, user_id, password, stored_hash):
+        """Checks that user_id has passed password, raises LoginError if not."""
         if not bcrypt.checkpw(password, stored_hash):
             logger.warn("Failed password login for user %s", user_id)
             raise LoginError(403, "", errcode=Codes.FORBIDDEN)