|
1 try: |
|
2 set |
|
3 except NameError: |
|
4 from sets import Set as set # Python 2.3 fallback |
|
5 |
|
6 from django.db import connection |
|
7 from django.contrib.auth.models import User |
|
8 |
|
9 |
|
10 class ModelBackend(object): |
|
11 """ |
|
12 Authenticates against django.contrib.auth.models.User. |
|
13 """ |
|
14 # TODO: Model, login attribute name and password attribute name should be |
|
15 # configurable. |
|
16 def authenticate(self, username=None, password=None): |
|
17 try: |
|
18 user = User.objects.get(username=username) |
|
19 if user.check_password(password): |
|
20 return user |
|
21 except User.DoesNotExist: |
|
22 return None |
|
23 |
|
24 def get_group_permissions(self, user_obj): |
|
25 """ |
|
26 Returns a set of permission strings that this user has through his/her |
|
27 groups. |
|
28 """ |
|
29 if not hasattr(user_obj, '_group_perm_cache'): |
|
30 cursor = connection.cursor() |
|
31 # The SQL below works out to the following, after DB quoting: |
|
32 # cursor.execute(""" |
|
33 # SELECT ct."app_label", p."codename" |
|
34 # FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct |
|
35 # WHERE p."id" = gp."permission_id" |
|
36 # AND gp."group_id" = ug."group_id" |
|
37 # AND ct."id" = p."content_type_id" |
|
38 # AND ug."user_id" = %s, [self.id]) |
|
39 qn = connection.ops.quote_name |
|
40 sql = """ |
|
41 SELECT ct.%s, p.%s |
|
42 FROM %s p, %s gp, %s ug, %s ct |
|
43 WHERE p.%s = gp.%s |
|
44 AND gp.%s = ug.%s |
|
45 AND ct.%s = p.%s |
|
46 AND ug.%s = %%s""" % ( |
|
47 qn('app_label'), qn('codename'), |
|
48 qn('auth_permission'), qn('auth_group_permissions'), |
|
49 qn('auth_user_groups'), qn('django_content_type'), |
|
50 qn('id'), qn('permission_id'), |
|
51 qn('group_id'), qn('group_id'), |
|
52 qn('id'), qn('content_type_id'), |
|
53 qn('user_id'),) |
|
54 cursor.execute(sql, [user_obj.id]) |
|
55 user_obj._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()]) |
|
56 return user_obj._group_perm_cache |
|
57 |
|
58 def get_all_permissions(self, user_obj): |
|
59 if not hasattr(user_obj, '_perm_cache'): |
|
60 user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()]) |
|
61 user_obj._perm_cache.update(self.get_group_permissions(user_obj)) |
|
62 return user_obj._perm_cache |
|
63 |
|
64 def has_perm(self, user_obj, perm): |
|
65 return perm in self.get_all_permissions(user_obj) |
|
66 |
|
67 def has_module_perms(self, user_obj, app_label): |
|
68 """ |
|
69 Returns True if user_obj has any permissions in the given app_label. |
|
70 """ |
|
71 for perm in self.get_all_permissions(user_obj): |
|
72 if perm[:perm.index('.')] == app_label: |
|
73 return True |
|
74 return False |
|
75 |
|
76 def get_user(self, user_id): |
|
77 try: |
|
78 return User.objects.get(pk=user_id) |
|
79 except User.DoesNotExist: |
|
80 return None |
|
81 |
|
82 |
|
83 class RemoteUserBackend(ModelBackend): |
|
84 """ |
|
85 This backend is to be used in conjunction with the ``RemoteUserMiddleware`` |
|
86 found in the middleware module of this package, and is used when the server |
|
87 is handling authentication outside of Django. |
|
88 |
|
89 By default, the ``authenticate`` method creates ``User`` objects for |
|
90 usernames that don't already exist in the database. Subclasses can disable |
|
91 this behavior by setting the ``create_unknown_user`` attribute to |
|
92 ``False``. |
|
93 """ |
|
94 |
|
95 # Create a User object if not already in the database? |
|
96 create_unknown_user = True |
|
97 |
|
98 def authenticate(self, remote_user): |
|
99 """ |
|
100 The username passed as ``remote_user`` is considered trusted. This |
|
101 method simply returns the ``User`` object with the given username, |
|
102 creating a new ``User`` object if ``create_unknown_user`` is ``True``. |
|
103 |
|
104 Returns None if ``create_unknown_user`` is ``False`` and a ``User`` |
|
105 object with the given username is not found in the database. |
|
106 """ |
|
107 if not remote_user: |
|
108 return |
|
109 user = None |
|
110 username = self.clean_username(remote_user) |
|
111 |
|
112 # Note that this could be accomplished in one try-except clause, but |
|
113 # instead we use get_or_create when creating unknown users since it has |
|
114 # built-in safeguards for multiple threads. |
|
115 if self.create_unknown_user: |
|
116 user, created = User.objects.get_or_create(username=username) |
|
117 if created: |
|
118 user = self.configure_user(user) |
|
119 else: |
|
120 try: |
|
121 user = User.objects.get(username=username) |
|
122 except User.DoesNotExist: |
|
123 pass |
|
124 return user |
|
125 |
|
126 def clean_username(self, username): |
|
127 """ |
|
128 Performs any cleaning on the "username" prior to using it to get or |
|
129 create the user object. Returns the cleaned username. |
|
130 |
|
131 By default, returns the username unchanged. |
|
132 """ |
|
133 return username |
|
134 |
|
135 def configure_user(self, user): |
|
136 """ |
|
137 Configures a user after creation and returns the updated user. |
|
138 |
|
139 By default, returns the user unmodified. |
|
140 """ |
|
141 return user |