1 # -*- coding: iso-8859-1 -*-
3 MoinMoin - auth plugin doing a check against MySQL db
5 @copyright: 2008 Matthijs Kooijman
6 @license: GNU GPL, see COPYING for details.
11 from MoinMoin import user
12 from MoinMoin.auth import BaseAuth, ContinueLogin
13 from MoinMoin.datastruct.backends import LazyGroupsBackend, LazyGroup
14 from MoinMoin import log
15 logging = log.getLogger(__name__)
18 class PhpbbGroupsBackend(LazyGroupsBackend):
19 class PhpbbGroup(LazyGroup):
23 def __init__(self, request, auth):
24 super(LazyGroupsBackend, self).__init__(request)
27 self.request = request
30 return self.list_query("SELECT group_name \
32 WHERE group_single_user = 0"
33 % self.auth.phpbb_prefix)
35 def __contains__(self, group_name):
36 return self.single_query("SELECT EXISTS ( \
39 WHERE group_single_user = 0 \
40 AND group_name=%%s)" % self.auth.phpbb_prefix,
43 def __getitem__(self, group_name):
44 return self.PhpbbGroup(self.request, group_name, self)
46 def _iter_group_members(self, group_name):
47 return self.list_query ("SELECT username \
48 FROM `%susers` as u, `%suser_group` as ug, `%sgroups` as g \
49 WHERE u.user_id = ug.user_id AND ug.group_id = g.group_id \
50 AND ug.user_pending = 0 AND g.group_single_user = 0 \
51 AND g.group_name = %%s"
52 % (self.auth.phpbb_prefix, self.auth.phpbb_prefix, self.auth.phpbb_prefix),
55 def _group_has_member(self, group_name, member):
56 return self.single_query ("SELECT EXISTS( \
58 FROM `%susers` as u, `%suser_group` as ug, `%sgroups` as g \
59 WHERE u.user_id = ug.user_id AND ug.group_id = g.group_id \
60 AND ug.user_pending = 0 AND g.group_single_user = 0 \
61 AND g.group_name = %%s AND u.username = %%s)"
62 % (self.auth.phpbb_prefix, self.auth.phpbb_prefix, self.auth.phpbb_prefix),
65 def groups_with_member(self, member):
66 return self.list_query ("SELECT g.group_name \
67 FROM `%susers` as u, `%suser_group` as ug, `%sgroups` as g \
68 WHERE u.user_id = ug.user_id AND ug.group_id = g.group_id \
69 AND ug.user_pending = 0 AND g.group_single_user = 0 \
71 % (self.auth.phpbb_prefix, self.auth.phpbb_prefix, self.auth.phpbb_prefix),
74 def single_query(self, *args):
76 Runs an SQL query, that returns single row with a single column.
77 Returns just that single result.
82 conn = self.auth.connect(self.request)
83 cursor = conn.cursor()
86 return cursor.fetchone()[0]
93 def list_query(self, *args):
95 Runs an SQL query, that returns any number of single-column rows.
96 Returns the results as a list of single values
101 conn = self.auth.connect(self.request)
102 cursor = conn.cursor()
103 cursor.execute(*args)
113 class phpbb_login(BaseAuth):
114 logout_possible = True
115 login_inputs = ['username', 'password']
117 def __init__(self, name='phpbb', dbhost=None, dbuser=None, dbpass=None, dbname=None, dbport=None, phpbb_prefix='', hint=None):
119 Authenticate using credentials from a phpbb database
121 The name parameter should be unique among all authentication methods.
123 The hint parameter is a snippet of HTML that is displayed below the login form.
130 self.phpbb_prefix = phpbb_prefix
134 # Create a "constructor" to create a phpbb_groups instance, while
135 # passing ourselves to it.
136 self.groups_backend = lambda config, request: PhpbbGroupsBackend(request, self)
138 def check_login(self, request, username, password):
139 """ Checks the given username password combination. Returns the
140 corresponding emailaddress, or False if authentication failed.
142 conn = self.connect(request)
147 # Get some data. Note that we interpolate the prefix ourselves, since
148 # letting the mysql library do it only works with values (it adds ''
149 # automatically). Note also that this allows possible SQL injection
150 # through the phpbb_prefix variable, but that should be a trusted
152 cursor = conn.cursor ()
153 cursor.execute ("SELECT user_password,user_email FROM `%susers` WHERE username=%%s" % self.phpbb_prefix, username)
156 if (cursor.rowcount == 0):
161 row = cursor.fetchone()
164 if (md5.new(password).hexdigest() == row[0]):
169 def connect(self, request):
170 # This code was shamelessly stolen from
171 # django.db.backends.mysql.base.cursor
174 'use_unicode': False,
177 kwargs['user'] = self.dbuser
179 kwargs['db'] = self.dbname
181 kwargs['passwd'] = self.dbpass
182 if self.dbhost.startswith('/'):
183 kwargs['unix_socket'] = self.dbhost
185 kwargs['host'] = self.dbhost
187 kwargs['port'] = int(self.dbport)
192 conn = MySQLdb.connect (**kwargs)
196 info = sys.exc_info()
197 logging.error("phpbb_login: authentication failed due to exception connecting to DB, traceback follows...")
198 logging.error(''.join(traceback.format_exception(*info)))
203 def login(self, request, user_obj, **kw):
205 username = kw.get('username')
206 password = kw.get('password')
208 logging.debug("phpbb_login: Trying to log in, username=%r " % (username))
210 # simply continue if something else already logged in
212 if user_obj and user_obj.valid:
213 return ContinueLogin(user_obj)
215 # Deny empty username or passwords
216 if not username or not password:
217 return ContinueLogin(user_obj)
219 email = self.check_login(request, username, password)
223 logging.debug("phpbb_login: authentication failed for %s" % (username))
224 return ContinueLogin(user_obj)
226 logging.debug("phpbb_login: authenticated %s (email %s)" % (username, email))
228 u = user.User(request, auth_username=username, auth_method=self.name, auth_attribs=('name', 'password', 'email'))
230 #u.remember_me = 0 # 0 enforces cookie_lifetime config param
231 u.create_or_update(True)
233 return ContinueLogin(u)
237 info = sys.exc_info()
238 logging.error("phpbb_login: authentication failed due to unexpected exception, traceback follows...")
239 logging.error(''.join(traceback.format_exception(*info)))
240 return ContinueLogin(user_obj)
242 def login_hint(self, request):
243 """ Return a snippet of HTML that is displayed with the login form. """
246 # vim: set sw=4 expandtab sts=4:vim