]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/blob - wradmin/lib/mediawiki.py
Create a readme file.
[philipp/winterrodeln/wradmin.git] / wradmin / lib / mediawiki.py
1 #!/usr/bin/python3.4
2 # $Id$
3 """MediaWiki communication functions"""
4 import datetime
5 import re
6
7 from authkit.users import UsersReadOnly, md5, AuthKitError
8 import formencode, formencode.national
9
10 import logging
11 log = logging.getLogger(__name__)
12
13 import wradmin.model as model
14
15
16 # User management
17 # ---------------
18
19 class MediaWikiUsers(UsersReadOnly):
20     def __init__(self, data=None, encrypt=None):
21         UsersReadOnly.__init__(self, data, encrypt)
22
23         # Initialize class fields
24         self.usernames = []
25         self.passwords = {}
26         self.roles = {}
27         self.groups = {}
28         self.user_ids = {} # MediaWiki user_id field of the database
29         self.real_names = {} # Real names of the users
30         self.emails = {} # E-Mail addresses of the users
31         
32         # Query database
33         con = model.meta.engine.connect()
34         sql = "SELECT user_id, user_name, user_real_name, user_password, user_email FROM user, user_groups WHERE ug_user=user_id AND ug_group='beauftragte'"
35         result = con.execute(sql)
36         for row in result:
37             user_id, username, real_name, password, email = row
38             username = username.lower()
39             role = []
40             group = None
41             
42             self.usernames.append(username)
43             self.passwords[username] = password
44             self.roles[username] = role
45             self.groups[username] = group
46             self.user_ids[username] = user_id
47             self.real_names[username] = real_name
48             self.emails[username] = email
49         con.close()
50         log.info("%d users loaded from the MediaWiki database" % len(self.usernames))
51     
52     @staticmethod
53     def password_is_correct(password_plain, password_db):
54         """Returns true if a plain text password corresponds to the hash of the password as stored in the MediaWiki db.
55
56         :param password_plain: plain text password, e.g. 'abc'
57         :param password_db: complete password line as stored in the database, e.g. ':pbkdf2:sha256:10000:128:EXgVGhc2mAs710feKvkiaw==:J5fYth9pg/R2d0F8bSsYfTR8SBpTBNIcdv/DgJ0tOPC1rtajl2Dr0RLqOozLb8O0XpDhtv4a3JJd/M0b58WebfNWAcdJBJI9nNeC0EYYD7OCYZGVAaRhiYtK4m53KZBBL6x/k2j4RjHPT1NmgV8Fr1DPqBNOlOHxUIh5z5oslM4='
58         """
59         if not password_db.startswith(':'):
60             raise AuthKitError("Password entry in the database does have an unexpected format (does not start with ':').")
61         pwd_parts = password_db[1:].split(':')
62         pwd_type = pwd_parts[0]
63         if pwd_type == 'B':
64             # legacy
65             # example: password_db == ':B:d25b2886:41e46c952790b1b442aac4f24f7ea7a8'
66             # pwd_parts == ['B', 'd25b2886', '41e46c952790b1b442aac4f24f7ea7a8']
67             if len(pwd_parts) != 3:
68                 raise AuthKitError("Password entry in the database does have an unexpected format (too few ':').")
69             salt, pwd_md5 = tuple(pwd_parts[1:3]) # salt = 'd25b2886'; pwd_md5 = '41e46c952790b1b442aac4f24f7ea7a8'
70             # log.info("user: '%s'; md5 of salt+' '+entered_pwd: '%s'; md5-part of DB-pwd: %s" % (username, md5(salt + '-' + md5(password)), pwd_md5))
71             return md5(salt + '-' + md5(password_plain)) == pwd_md5
72         elif pwd_type == 'pbkdf2':
73             if len(pwd_parts) != 6:
74                 raise AuthKitError("Password entry in the database does have an unexpected format (too few ':').")
75             _, algorithm, rounds, num_bit, salt, pwd_hash = pwd_parts
76             from base64 import b64decode, b64encode
77             from hashlib import pbkdf2_hmac
78             salt = b64decode(salt)
79             hash = pbkdf2_hmac(algorithm, password_plain, salt, int(rounds), int(num_bit))
80             hash = b64encode(hash)
81             return hash == pwd_hash
82
83
84     def user_has_password(self, username, password):
85         """
86         Passwords are case sensitive.
87         Returns ``True`` if the user has the password specified, ``False`` otherwise.
88         Raises an exception if the user doesn't exist.
89
90         See http://www.winterrodeln.org/trac/wiki/MediaWikiAuthorization
91         """
92         password_db = self.user_password(username)
93         return self.password_is_correct(password, password_db)