Edgewall Software

Ticket #2456: user.2.py

File user.2.py, 8.6 kB (added by wkornewald, 19 months ago)

now with User object, still completely untested

Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright 2006 Waldemar Kornewald, wkornewald@haiku-os.org
4# All rights reserved.
5#
6# This software is licensed as described in the file COPYING, which
7# you should have received as part of this distribution. The terms
8# are also available at http://trac.edgewall.org/wiki/TracLicense.
9#
10# This software consists of voluntary contributions made by many
11# individuals. For the exact contribution history, see the revision
12# history and logs, available at http://trac.edgewall.org/log/.
13#
14# Author: Waldemar Kornewald, wkornewald@haiku-os.org
15
16from trac.core import *
17from trac.config import *
18
19
20class IUserStore(Interface):
21    """
22    Extension point interface for backends that store known users.
23    """
24
25    def supports_user_operation(self, operation):
26        """
27        Returns whether the operation (a method name) is supported.
28
29        @return supported
30        """
31        return hasattr(self, operation)
32
33    def create_user(self, username, password):
34        """
35        Creates a new user with the given username and password.
36
37        @return success
38        """
39
40    def get_usernames(self):
41        """
42        Generator that yields an ordered list of known usernames.
43
44        @return username
45        """
46
47    def check_password(self, username, password):
48        """
49        Checks if the password is correct for the given user.
50        """
51
52    def change_password(self, username, password):
53        """
54        Changes a user's password.
55
56        @return success
57        """
58
59    def delete_user(self, username):
60        """
61        Deletes a user.
62
63        @return success
64            Returns False if the user didn't exist.
65        """
66
67
68class IUserAttributeProvider(Interface):
69    """
70    Extension point interface for backends that store user attributes.
71    """
72
73    def supports_attribute_operation(self, operation):
74        """
75        Returns whether the operation (a method name) is supported.
76
77        @return supported
78        """
79        return hasattr(self, operation)
80
81    def get_user_attribute(self, username, attribute):
82        """
83        Returns a user attribute.
84
85        If the attribute is not set it returs an empty string.
86        If the attribute is not supported None is returned.
87        """
88
89    def set_user_attribute(self, username, attribute, value):
90        """
91        Sets a user attribute.
92
93        @return success
94            Returns False if setting the attribute is not supported.
95        """
96
97    def delete_all_user_attributes(self, username):
98        """
99        Deletes all of the given user's attributes.
100
101        @return success
102        """
103
104
105class UserManager(Component):
106    """
107    Component responsible for managing users and user attributes.
108    """
109
110    store = ExtensionOption('users',
111        'store', IUserStore, 'SessionUserStore',
112        doc="""The user store that should be used for authentication
113            (''since 0.11'').""")
114    attribute_providers = OrderedExtensionsOption('users',
115        'attribute_providers', IUserAttributeProvider,
116        doc="""Ordered list of user attribute providers (''since 0.11'').""")
117
118    # public API
119
120    def supports_operation(self, operation):
121        if self.store.supports_user_operation(operation):
122            return True
123        for provider in self.attribute_providers:
124            if self.provider.supports_attribute_operation(operation):
125                return True
126        return False
127
128    # IUserStore methods
129
130    def create_user(self, username, password):
131        if not self.store.supports_user_operation('create_user'):
132            return False
133        return self.store.create_user(username, password)
134
135    def get_user(self, username):
136        """
137        Returns a User object for the username.
138
139        @return User object or None if the user doesn't exist
140        """
141        if username in self.get_usernames():
142            return User(username, self.store, self.attribute_providers)
143        return None
144
145    def get_usernames(self):
146        if not self.store.supports_user_operation('get_usernames'):
147            return []
148        return self.store.get_usernames()
149
150
151
152class User(object):
153    """
154    Object representing a user.
155    """
156
157    def __init__(self, username, store, attribute_providers):
158        self._username = username
159        self.store = store
160        self.attribute_providers = attribute_providers
161
162    # public API
163
164    @property
165    def username():
166        return self._username
167
168    # IUserStore methods
169
170    def check_password(self, password):
171        if not self.store.supports_user_operation('check_password'):
172            return False
173        return self.store.check_password(self.username, password)
174
175    def change_password(self, password):
176        if not self.store.supports_user_operation('change_password'):
177            return False
178        return self.store.change_password(self.username, password)
179
180    def delete(self):
181        if not self.store.supports_user_operation('delete_user') or \
182                not self.delete_all_attributes(self.username):
183            return False
184        return self.store.delete_user(self.username)
185
186    # IUserAttributeProvider methods
187
188    def __getattr__(self, attribute):
189        for provider in self.attribute_providers:
190            if not provider.supports_attribute_operation('get_user_attribute'):
191                continue
192            value = provider.get_user_attribute(self.username, attribute)
193            if value is not None:
194                return value
195        return None
196
197    def __setattr__(self, attribute, value):
198        for provider in self.attribute_providers:
199            if not provider.supports_attribute_operation('set_user_attribute'):
200                continue
201            result = provider.set_user_attribute(self.username, attribute,
202                                                 value)
203            if result:
204                return True
205        return False
206
207    def delete_all_attributes(self):
208        for provider in self.attribute_providers:
209            if not provider.supports_attribute_operation('delete_all_user_attributes'):
210                continue
211            result = provider.delete_all_user_attributes(username)
212            if result:
213                return True
214        return False
215
216
217class SessionUserStore(Component):
218    """
219    Component for managing authenticated users stored in sessions.
220    """
221
222    implements(IUserStore)
223
224    def get_usernames(self):
225        db = self.env.get_db_cnx()
226        cursor = db.cursor()
227        cursor.execute("SELECT sid FROM session "
228                       "WHERE authenticated=1 "
229                       "ORDER BY sid")
230        for row in cursor:
231            yield row[0]
232
233
234class SessionUserAttributeProvider(Component):
235    """
236    Component for providing user attributes via Trac sessions.
237    """
238
239    implements(IUserAttributeProvider)
240
241    def get_user_attribute(self, username, attribute):
242        db = self.env.get_db_cnx()
243        cursor = db.cursor()
244        cursor.execute("SELECT value FROM session_attribute "
245                       "WHERE sid=%s AND name=%s AND authenticated=1",
246                       (username, attribute))
247        row = cursor.fetchone()
248        if row:
249            return row[0]
250
251        # if the attribute isn't set we return empty string to indicate
252        # that the attribute is supported, but empty
253        return ''
254
255    def set_user_attribute(self, username, attribute, value):
256        db = self.env.get_db_cnx()
257        cursor = db.cursor()
258
259        # check if attribute exists
260        cursor.execute("SELECT value FROM session_attribute "
261                       "WHERE sid=%s AND name=%s AND authenticated=1",
262                       (username, attribute))
263        if cursor.fetchone():
264            # update the attribute
265            cursor.execute("UPDATE session_attribute SET value=%s "
266                           "WHERE sid=%s AND name=%s AND authenticated=1",
267                           (username, attribute, value))
268        else:
269            # create new attribute
270            cursor.execute("INSERT INTO session_attribute "
271                           "(sid,authenticated,name,value) "
272                           "VALUES(%s,1,%s,%s)",
273                           (username, attribute, value))
274        db.commit()
275        return True
276
277    def delete_all_user_attributes(self, username):
278        db = self.env.get_db_cnx()
279        cursor = db.cursor()
280        cursor.execute("DELETE FROM session_attribute WHERE sid=%s",
281                      (username,))
282        db.commit()
283        return True