phpbb_login: Make the table prefix configurable.
[matthijs/projects/wipi.git] / conf / auth / phpbb_login.py
1 # -*- coding: iso-8859-1 -*-
2 """
3     MoinMoin - auth plugin doing a check against MySQL db
4
5     @copyright: 2008 Matthijs Kooijman
6     @license: GNU GPL, see COPYING for details.
7 """
8
9 import MySQLdb
10 import md5
11 from MoinMoin import user
12 from MoinMoin.auth import BaseAuth, ContinueLogin
13 from MoinMoin import log
14 logging = log.getLogger(__name__)
15
16 class phpbb_login(BaseAuth):
17     logout_possible = True
18     login_inputs    = ['username', 'password']
19     
20     def __init__(self, name='phpbb', dbhost=None, dbuser=None, dbpass=None, dbname=None, dbport=None, phpbb_prefix='', hint=None):
21         """
22             Authenticate using credentials from a phpbb database
23
24             The name parameter should be unique among all authentication methods.
25
26             The hint parameter is a snippet of HTML that is displayed below the login form.
27         """
28         self.dbhost  = dbhost
29         self.dbuser  = dbuser
30         self.dbpass  = dbpass
31         self.dbname  = dbname
32         self.dbport  = dbport
33         self.phpbb_prefix = phpbb_prefix
34         self.name    = name
35         self.hint    = hint
36     
37     def check_login(self, request, username, password):
38         """ Checks the given username password combination. Returns the
39         corresponding emailaddress, or False if authentication failed.
40         """
41         conn = self.connect(request)
42
43         if not conn:
44             return False
45
46         # Get some data. Note that we interpolate the prefix ourselves, since
47         # letting the mysql library do it only works with values (it adds ''
48         # automatically). Note also that this allows possible SQL injection
49         # through the phpbb_prefix variable, but that should be a trusted
50         # value anyway.
51         cursor = conn.cursor ()
52         cursor.execute ("SELECT user_password,user_email FROM `%susers` WHERE username=%%s" % self.phpbb_prefix, username)
53
54         # No data? No login.
55         if (cursor.rowcount == 0):
56             conn.close()
57             return False
58        
59         # Check password
60         row = cursor.fetchone()
61         conn.close()
62
63         if (md5.new(password).hexdigest() == row[0]):
64             return row[1]
65         else:
66             return False
67
68     def connect(self, request):
69         # This code was shamelessly stolen from
70         # django.db.backends.mysql.base.cursor
71         kwargs = {
72             'charset': 'utf8',
73             'use_unicode': False,
74         }
75         if self.dbuser:
76             kwargs['user'] = self.dbuser
77         if self.dbname:
78             kwargs['db'] = self.dbname
79         if self.dbpass:
80             kwargs['passwd'] = self.dbpass
81         if self.dbhost.startswith('/'):
82             kwargs['unix_socket'] = self.dbhost
83         elif self.dbhost:
84             kwargs['host'] = self.dbhost
85         if self.dbport:
86             kwargs['port'] = int(self.dbport)
87
88         # End stolen code
89
90         try:
91             conn = MySQLdb.connect (**kwargs)
92         except:
93             import sys
94             import traceback
95             info = sys.exc_info()
96             logging.error("phpbb_login: authentication failed due to exception connecting to DB, traceback follows...")
97             logging.error(''.join(traceback.format_exception(*info)))
98             return False
99
100         return conn
101
102     def login(self, request, user_obj, **kw):
103         try:
104             username = kw.get('username')
105             password = kw.get('password')
106
107             logging.debug("phpbb_login: Trying to log in, username=%r " % (username))
108            
109             # simply continue if something else already logged in
110             # successfully
111             if user_obj and user_obj.valid:
112                 return ContinueLogin(user_obj)
113
114             # Deny empty username or passwords
115             if not username or not password:
116                 return ContinueLogin(user_obj)
117
118             email = self.check_login(request, username, password)
119             
120             # Login incorrect
121             if (not email):
122                 logging.debug("phpbb_login: authentication failed for %s" % (username))
123                 return ContinueLogin(user_obj)
124
125             logging.debug("phpbb_login: authenticated %s (email %s)" % (username, email))
126
127             u = user.User(request, auth_username=username, auth_method=self.name, auth_attribs=('name', 'password', 'email'))
128             u.email = email
129             #u.remember_me = 0 # 0 enforces cookie_lifetime config param
130             u.create_or_update(True)
131
132             return ContinueLogin(u)
133         except:
134             import sys
135             import traceback
136             info = sys.exc_info()
137             logging.error("phpbb_login: authentication failed due to unexpected exception, traceback follows...")
138             logging.error(''.join(traceback.format_exception(*info)))
139             return ContinueLogin(user_obj)
140
141     def login_hint(self, request):
142         """ Return a snippet of HTML that is displayed with the login form. """
143         return self.hint
144
145 # vim: set sw=4 expandtab sts=4:vim