]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/commitdiff
Added support of MediaWiki 1.27 pbkdf2 hashes.
authorphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Thu, 20 Oct 2016 20:22:20 +0000 (20:22 +0000)
committerphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Thu, 20 Oct 2016 20:22:20 +0000 (20:22 +0000)
git-svn-id: http://www.winterrodeln.org/svn/wradmin/trunk@2504 7aebc617-e5e2-0310-91dc-80fb5f6d2477

wradmin/lib/mediawiki.py
wradmin/tests/test_lib.py

index 5a31cf0898e44712d78250ad2f62f5d85184dff4..8f7cbf4b3c70978dfc0742deae0c5b1dc12bf09c 100644 (file)
@@ -51,21 +51,45 @@ class MediaWikiUsers(UsersReadOnly):
         con.close()
         log.info("%d users loaded from the MediaWiki database" % len(self.usernames))
     
-    
+    @staticmethod
+    def password_is_correct(password_plain, password_db):
+        """Returns true if a plain text password corresponds to the hash of the password as stored in the MediaWiki db.
+
+        :param password_plain: plain text password, e.g. 'abc'
+        :param password_db: complete password line as stored in the database, e.g. ':pbkdf2:sha256:10000:128:EXgVGhc2mAs710feKvkiaw==:J5fYth9pg/R2d0F8bSsYfTR8SBpTBNIcdv/DgJ0tOPC1rtajl2Dr0RLqOozLb8O0XpDhtv4a3JJd/M0b58WebfNWAcdJBJI9nNeC0EYYD7OCYZGVAaRhiYtK4m53KZBBL6x/k2j4RjHPT1NmgV8Fr1DPqBNOlOHxUIh5z5oslM4='
+        """
+        if not password_db.startswith(':'):
+            raise AuthKitError("Password entry in the database does have an unexpected format (does not start with ':').")
+        pwd_parts = password_db[1:].split(':')
+        pwd_type = pwd_parts[0]
+        if pwd_type == 'B':
+            # legacy
+            # example: password_db == ':B:d25b2886:41e46c952790b1b442aac4f24f7ea7a8'
+            # pwd_parts == ['B', 'd25b2886', '41e46c952790b1b442aac4f24f7ea7a8']
+            if len(pwd_parts) != 3:
+                raise AuthKitError("Password entry in the database does have an unexpected format (too few ':').")
+            salt, pwd_md5 = tuple(pwd_parts[1:3]) # salt = 'd25b2886'; pwd_md5 = '41e46c952790b1b442aac4f24f7ea7a8'
+            # log.info("user: '%s'; md5 of salt+' '+entered_pwd: '%s'; md5-part of DB-pwd: %s" % (username, md5(salt + '-' + md5(password)), pwd_md5))
+            return md5(salt + '-' + md5(password_plain)) == pwd_md5
+        elif pwd_type == 'pbkdf2':
+            if len(pwd_parts) != 6:
+                raise AuthKitError("Password entry in the database does have an unexpected format (too few ':').")
+            _, algorithm, rounds, num_bit, salt, pwd_hash = pwd_parts
+            from base64 import b64decode, b64encode
+            from hashlib import pbkdf2_hmac
+            salt = b64decode(salt)
+            hash = pbkdf2_hmac(algorithm, password_plain, salt, int(rounds), int(num_bit))
+            hash = b64encode(hash)
+            return hash == pwd_hash
+
+
     def user_has_password(self, username, password):
         """
         Passwords are case sensitive.
-        Returns ``True`` if the user has the password specified, ``False`` otherwise. 
+        Returns ``True`` if the user has the password specified, ``False`` otherwise.
         Raises an exception if the user doesn't exist.
-        
+
         See http://www.winterrodeln.org/trac/wiki/MediaWikiAuthorization
         """
-        pwd = self.user_password(username)
-        # Example: pwd = ':B:d25b2886:41e46c952790b1b442aac4f24f7ea7a8'
-        pwd_parts = pwd.split(':') # password_parts = ['', 'B', 'd25b2886', '41e46c952790b1b442aac4f24f7ea7a8']
-        if len(pwd_parts) == 4 and pwd_parts[1] == 'B':
-            salt, pwd_md5 = tuple(pwd_parts[2:4]) # salt = 'd25b2886'; pwd_md5 = '41e46c952790b1b442aac4f24f7ea7a8'
-        else:
-            raise AuthKitError("Password in the MediaWiki database format has an unexpected format ('%s' instead of e.g. ':B:d25b2886:41e46c952790b1b442aac4f24f7ea7a8')" % pwd)
-        # log.info("user: '%s'; md5 of salt+' '+entered_pwd: '%s'; md5-part of DB-pwd: %s" % (username, md5(salt + '-' + md5(password)), pwd_md5))
-        return md5(salt + '-' + md5(password)) == pwd_md5
+        password_db = self.user_password(username)
+        return self.password_is_correct(password, password_db)
index 347c1e4359dd488867eb4a7e9cbae8106c267f4d..196a04a5282da9144a05a5432c6caf9ac00ecf6f 100644 (file)
@@ -1,12 +1,25 @@
-#!/usr/bin/python2.6
+#!/usr/bin/python2.7
 # -*- coding: iso-8859-15 -*-
 # $Id$
+import unittest
 import wradmin.lib
 import wradmin.lib.mediawiki
 import wradmin.model
 
 
+class TestMediaWikiUsers(unittest.TestCase):
 
-def _test_mediawiki_users():
-    users = wradmin.lib.mediawiki.MediaWikiUsers(True)
-    assert len(users.usernames) >= 1 # We have at least one user
+    @unittest.skip
+    def test_mediawiki_users(self):
+        users = wradmin.lib.mediawiki.MediaWikiUsers(True)
+        assert len(users.usernames) >= 1 # We have at least one user
+
+    def test_mediawiki_users_has_password_is_correct_b(self):
+        password_db = ':B:d25b2886:41e46c952790b1b442aac4f24f7ea7a8'  # 'abc'
+        self.assertTrue(wradmin.lib.mediawiki.MediaWikiUsers.password_is_correct('abc', password_db))
+        self.assertFalse(wradmin.lib.mediawiki.MediaWikiUsers.password_is_correct('abcd', password_db))
+
+    def test_mediawiki_users_has_password_is_correct_pbkdf2(self):
+        password_db = ':pbkdf2:sha256:10000:128:EXgVGhc2mAs710feKvkiaw==:J5fYth9pg/R2d0F8bSsYfTR8SBpTBNIcdv/DgJ0tOPC1rtajl2Dr0RLqOozLb8O0XpDhtv4a3JJd/M0b58WebfNWAcdJBJI9nNeC0EYYD7OCYZGVAaRhiYtK4m53KZBBL6x/k2j4RjHPT1NmgV8Fr1DPqBNOlOHxUIh5z5oslM4='  # 'abc'
+        self.assertTrue(wradmin.lib.mediawiki.MediaWikiUsers.password_is_correct('abc', password_db))
+        self.assertFalse(wradmin.lib.mediawiki.MediaWikiUsers.password_is_correct('abcd', password_db))