Merge lp:~statik/ubuntu/lucid/python-django-openid-auth/new-upstream-version into lp:ubuntu/lucid/python-django-openid-auth
- Lucid (10.04)
- new-upstream-version
- Merge into lucid
Proposed by
Elliot Murphy
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~statik/ubuntu/lucid/python-django-openid-auth/new-upstream-version |
Merge into: | lp:ubuntu/lucid/python-django-openid-auth |
Diff against target: |
1101 lines (+528/-69) 26 files modified
PKG-INFO (+6/-3) README.txt (+42/-8) debian/changelog (+10/-0) debian/compat (+1/-1) debian/control (+4/-7) debian/pycompat (+0/-1) debian/rules (+2/-3) debian/source/format (+1/-0) django_openid_auth/__init__.py (+1/-0) django_openid_auth/admin.py (+24/-0) django_openid_auth/auth.py (+9/-0) django_openid_auth/forms.py (+36/-0) django_openid_auth/management/__init__.py (+27/-0) django_openid_auth/management/commands/__init__.py (+27/-0) django_openid_auth/management/commands/openid_cleanup.py (+28/-0) django_openid_auth/store.py (+16/-7) django_openid_auth/templates/openid/login.html (+4/-2) django_openid_auth/tests/__init__.py (+28/-0) django_openid_auth/tests/test_store.py (+46/-3) django_openid_auth/tests/test_views.py (+143/-25) django_openid_auth/tests/urls.py (+29/-1) django_openid_auth/urls.py (+3/-3) django_openid_auth/views.py (+30/-1) example_consumer/settings.py (+4/-1) example_consumer/urls.py (+1/-1) setup.py (+6/-2) |
To merge this branch: | bzr merge lp:~statik/ubuntu/lucid/python-django-openid-auth/new-upstream-version |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+18671@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Elliot Murphy (statik) wrote : | # |
Revision history for this message
Elliot Murphy (statik) wrote : | # |
Daniel, I added you as a reviewer only because I know you were anxious to get this new version.
- 4. By Elliot Murphy
-
Drop Provides:
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' | |||
2 | --- PKG-INFO 2009-04-08 15:07:49 +0000 | |||
3 | +++ PKG-INFO 2010-02-05 06:33:16 +0000 | |||
4 | @@ -1,12 +1,12 @@ | |||
6 | 1 | Metadata-Version: 1.0 | 1 | Metadata-Version: 1.1 |
7 | 2 | Name: django-openid-auth | 2 | Name: django-openid-auth |
9 | 3 | Version: 0.1 | 3 | Version: 0.2 |
10 | 4 | Summary: OpenID integration for django.contrib.auth | 4 | Summary: OpenID integration for django.contrib.auth |
11 | 5 | Home-page: https://launchpad.net/django-openid-auth | 5 | Home-page: https://launchpad.net/django-openid-auth |
12 | 6 | Author: Canonical Ltd | 6 | Author: Canonical Ltd |
13 | 7 | Author-email: UNKNOWN | 7 | Author-email: UNKNOWN |
14 | 8 | License: BSD | 8 | License: BSD |
16 | 9 | Download-URL: https://launchpad.net/django-openid-auth/+download | 9 | Download-URL: http://launchpad.net/django-openid-auth/trunk/0.2/+download/django-openid-auth-0.2.tar.gz |
17 | 10 | Description: A library that can be used to add OpenID support to Django applications. | 10 | Description: A library that can be used to add OpenID support to Django applications. |
18 | 11 | The library integrates with Django's built in authentication system, so | 11 | The library integrates with Django's built in authentication system, so |
19 | 12 | most applications require minimal changes to support OpenID llogin. The | 12 | most applications require minimal changes to support OpenID llogin. The |
20 | @@ -26,3 +26,6 @@ | |||
21 | 26 | Classifier: Operating System :: OS Independent | 26 | Classifier: Operating System :: OS Independent |
22 | 27 | Classifier: Programming Language :: Python | 27 | Classifier: Programming Language :: Python |
23 | 28 | Classifier: Topic :: Software Development :: Libraries :: Python Modules | 28 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
24 | 29 | Requires: django (>=1.0) | ||
25 | 30 | Requires: openid (>=2.2.0) | ||
26 | 31 | Provides: django_openid_auth | ||
27 | 29 | 32 | ||
28 | === modified file 'README.txt' | |||
29 | --- README.txt 2009-04-08 15:07:49 +0000 | |||
30 | +++ README.txt 2010-02-05 06:33:16 +0000 | |||
31 | @@ -8,7 +8,14 @@ | |||
32 | 8 | 8 | ||
33 | 9 | == Basic Installation == | 9 | == Basic Installation == |
34 | 10 | 10 | ||
36 | 11 | 1. Add 'django_auth_openid' to INSTALLED_APPS for your application. | 11 | 1. Install the Jan Rain Python OpenID library. It can be found at: |
37 | 12 | |||
38 | 13 | http://openidenabled.com/python-openid/ | ||
39 | 14 | |||
40 | 15 | It can also be found in most Linux distributions packaged as | ||
41 | 16 | "python-openid". You will need version 2.2.0 or later. | ||
42 | 17 | |||
43 | 18 | 2. Add 'django_openid_auth' to INSTALLED_APPS for your application. | ||
44 | 12 | At a minimum, you'll need the following in there: | 19 | At a minimum, you'll need the following in there: |
45 | 13 | 20 | ||
46 | 14 | INSTALLED_APPS = ( | 21 | INSTALLED_APPS = ( |
47 | @@ -18,7 +25,7 @@ | |||
48 | 18 | 'django_openid_auth', | 25 | 'django_openid_auth', |
49 | 19 | ) | 26 | ) |
50 | 20 | 27 | ||
52 | 21 | 2. Add 'django_auth_openid.auth.OpenIDBackend' to | 28 | 3. Add 'django_auth_openid.auth.OpenIDBackend' to |
53 | 22 | AUTHENTICATION_BACKENDS. This should be in addition to the | 29 | AUTHENTICATION_BACKENDS. This should be in addition to the |
54 | 23 | default ModelBackend: | 30 | default ModelBackend: |
55 | 24 | 31 | ||
56 | @@ -27,17 +34,17 @@ | |||
57 | 27 | 'django.contrib.auth.backends.ModelBackend', | 34 | 'django.contrib.auth.backends.ModelBackend', |
58 | 28 | ) | 35 | ) |
59 | 29 | 36 | ||
61 | 30 | 3. To create users automatically when a new OpenID is used, add the | 37 | 4. To create users automatically when a new OpenID is used, add the |
62 | 31 | following to the settings: | 38 | following to the settings: |
63 | 32 | 39 | ||
64 | 33 | OPENID_CREATE_USERS = True | 40 | OPENID_CREATE_USERS = True |
65 | 34 | 41 | ||
67 | 35 | 4. To have user details updated from OpenID Simple Registration data | 42 | 5. To have user details updated from OpenID Simple Registration data |
68 | 36 | each time they log in, add the following: | 43 | each time they log in, add the following: |
69 | 37 | 44 | ||
70 | 38 | OPENID_UPDATE_DETAILS_FROM_SREG = True | 45 | OPENID_UPDATE_DETAILS_FROM_SREG = True |
71 | 39 | 46 | ||
73 | 40 | 5. Hook up the login URLs to your application's urlconf with | 47 | 6. Hook up the login URLs to your application's urlconf with |
74 | 41 | something like: | 48 | something like: |
75 | 42 | 49 | ||
76 | 43 | urlpatterns = patterns('', | 50 | urlpatterns = patterns('', |
77 | @@ -46,16 +53,16 @@ | |||
78 | 46 | ... | 53 | ... |
79 | 47 | ) | 54 | ) |
80 | 48 | 55 | ||
82 | 49 | 6. Configure the LOGIN_URL and LOGIN_REDIRECT_URL appropriately for | 56 | 7. Configure the LOGIN_URL and LOGIN_REDIRECT_URL appropriately for |
83 | 50 | your site: | 57 | your site: |
84 | 51 | 58 | ||
86 | 52 | LOGIN_URL = '/openid/login' | 59 | LOGIN_URL = '/openid/login/' |
87 | 53 | LOGIN_REDIRECT_URL = '/' | 60 | LOGIN_REDIRECT_URL = '/' |
88 | 54 | 61 | ||
89 | 55 | This will allow pages that use the standard @login_required | 62 | This will allow pages that use the standard @login_required |
90 | 56 | decorator to use the OpenID login page. | 63 | decorator to use the OpenID login page. |
91 | 57 | 64 | ||
93 | 58 | 7. Rerun "python manage.py syncdb" to add the UserOpenID table to | 65 | 8. Rerun "python manage.py syncdb" to add the UserOpenID table to |
94 | 59 | your database. | 66 | your database. |
95 | 60 | 67 | ||
96 | 61 | 68 | ||
97 | @@ -90,3 +97,30 @@ | |||
98 | 90 | 97 | ||
99 | 91 | When a user logs in, they will be added or removed from the relevant | 98 | When a user logs in, they will be added or removed from the relevant |
100 | 92 | teams listed in the mapping. | 99 | teams listed in the mapping. |
101 | 100 | |||
102 | 101 | If you have already django-groups and want to map these groups automatically, you can use the OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO variable in your settings.py file. | ||
103 | 102 | |||
104 | 103 | OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO = True | ||
105 | 104 | |||
106 | 105 | If you use OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO, the variable OPENID_LAUNCHPAD_TEAMS_MAPPING will be ignored. | ||
107 | 106 | If you want to exclude some groups from the auto mapping, use OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST. This variable has only an effect if OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO is True. | ||
108 | 107 | |||
109 | 108 | OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST = ['django-group1', 'django-group2'] | ||
110 | 109 | |||
111 | 110 | == External redirect domains == | ||
112 | 111 | |||
113 | 112 | By default, redirecting back to an external URL after auth is forbidden. To permit redirection to external URLs on a separate domain, define ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS in your settings.py file as a list of permitted domains: | ||
114 | 113 | |||
115 | 114 | ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = ['example.com', 'example.org'] | ||
116 | 115 | |||
117 | 116 | and redirects to external URLs on those domains will additionally be permitted. | ||
118 | 117 | |||
119 | 118 | == Use as /admin (django.admin.contrib) login == | ||
120 | 119 | |||
121 | 120 | If you require openid authentication into the admin application, add the following setting: | ||
122 | 121 | |||
123 | 122 | OPENID_USE_AS_ADMIN_LOGIN = True | ||
124 | 123 | |||
125 | 124 | It is worth noting that a user needs to be be marked as a "staff user" to be able to access the admin interface. A new openid user will not normally be a "staff user". | ||
126 | 125 | The easiest way to resolve this is to use traditional authentication (OPENID_USE_AS_ADMIN_LOGIN = False) to sign in as your first user with a password and authorise your | ||
127 | 126 | openid user to be staff. | ||
128 | 93 | 127 | ||
129 | === modified file 'debian/changelog' | |||
130 | --- debian/changelog 2009-04-08 15:07:49 +0000 | |||
131 | +++ debian/changelog 2010-02-05 06:33:16 +0000 | |||
132 | @@ -1,3 +1,13 @@ | |||
133 | 1 | python-django-openid-auth (0.2-0ubuntu1) lucid; urgency=low | ||
134 | 2 | |||
135 | 3 | * New upstream release. (LP: #517400) | ||
136 | 4 | * Switch to dpkg-source 3.0 (quilt) format | ||
137 | 5 | * Switch to dh 7 from CDBS | ||
138 | 6 | * Switch from pycentral to pysupport | ||
139 | 7 | * Bump standards version to 3.8.3 | ||
140 | 8 | |||
141 | 9 | -- Elliot Murphy <elliot@ubuntu.com> Fri, 05 Feb 2010 00:01:53 -0500 | ||
142 | 10 | |||
143 | 1 | python-django-openid-auth (0.1-0ubuntu1) karmic; urgency=low | 11 | python-django-openid-auth (0.1-0ubuntu1) karmic; urgency=low |
144 | 2 | 12 | ||
145 | 3 | * Initial release. (LP: #359304) | 13 | * Initial release. (LP: #359304) |
146 | 4 | 14 | ||
147 | === modified file 'debian/compat' | |||
148 | --- debian/compat 2009-04-08 15:07:49 +0000 | |||
149 | +++ debian/compat 2010-02-05 06:33:16 +0000 | |||
150 | @@ -1,1 +1,1 @@ | |||
152 | 1 | 6 | 1 | 7 |
153 | 2 | 2 | ||
154 | === modified file 'debian/control' | |||
155 | --- debian/control 2009-04-08 15:07:49 +0000 | |||
156 | +++ debian/control 2010-02-05 06:33:16 +0000 | |||
157 | @@ -1,26 +1,23 @@ | |||
158 | 1 | Source: python-django-openid-auth | 1 | Source: python-django-openid-auth |
159 | 2 | Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com> | 2 | Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com> |
161 | 3 | XSBC-Original-Maintainer: Elliot Murphy <elliot@canonical.com> | 3 | XSBC-Original-Maintainer: Elliot Murphy <elliot@ubuntu.com> |
162 | 4 | Section: python | 4 | Section: python |
163 | 5 | Priority: optional | 5 | Priority: optional |
165 | 6 | Standards-Version: 3.8.0 | 6 | Standards-Version: 3.8.3 |
166 | 7 | Build-Depends-Indep: | 7 | Build-Depends-Indep: |
168 | 8 | python-central (>= 0.6.7) | 8 | python-support (>= 0.6.4) |
169 | 9 | Build-Depends: | 9 | Build-Depends: |
172 | 10 | cdbs (>= 0.4.51), | 10 | debhelper (>= 7.0.50), |
171 | 11 | debhelper (>= 6.0.4), | ||
173 | 12 | python (>= 2.5) | 11 | python (>= 2.5) |
174 | 13 | XS-Python-Version: all | 12 | XS-Python-Version: all |
175 | 14 | Homepage: https://launchpad.net/django-openid-auth | 13 | Homepage: https://launchpad.net/django-openid-auth |
176 | 15 | 14 | ||
177 | 16 | Package: python-django-openid-auth | 15 | Package: python-django-openid-auth |
178 | 17 | Architecture: all | 16 | Architecture: all |
179 | 18 | XB-Python-Version: ${python:Versions} | ||
180 | 19 | Depends: ${python:Depends}, | 17 | Depends: ${python:Depends}, |
181 | 20 | ${misc:Depends}, | 18 | ${misc:Depends}, |
182 | 21 | python-openid, | 19 | python-openid, |
183 | 22 | python-django | 20 | python-django |
184 | 23 | Provides: ${python:Provides} | ||
185 | 24 | Description: OpenID integration for django.contrib.auth | 21 | Description: OpenID integration for django.contrib.auth |
186 | 25 | A library that can be used to add OpenID support to Django applications. | 22 | A library that can be used to add OpenID support to Django applications. |
187 | 26 | The library integrates with Django's builtin authentication system, so | 23 | The library integrates with Django's builtin authentication system, so |
188 | 27 | 24 | ||
189 | === removed file 'debian/pycompat' | |||
190 | --- debian/pycompat 2009-04-08 15:07:49 +0000 | |||
191 | +++ debian/pycompat 1970-01-01 00:00:00 +0000 | |||
192 | @@ -1,1 +0,0 @@ | |||
193 | 1 | 2 | ||
194 | 2 | 0 | ||
195 | === modified file 'debian/rules' | |||
196 | --- debian/rules 2009-04-08 15:07:49 +0000 | |||
197 | +++ debian/rules 2010-02-05 06:33:16 +0000 | |||
198 | @@ -1,5 +1,4 @@ | |||
199 | 1 | #!/usr/bin/make -f | 1 | #!/usr/bin/make -f |
200 | 2 | 2 | ||
204 | 3 | include /usr/share/cdbs/1/rules/debhelper.mk | 3 | %: |
205 | 4 | DEB_PYTHON_SYSTEM = pycentral | 4 | dh --buildsystem=python_distutils $@ |
203 | 5 | include /usr/share/cdbs/1/class/python-distutils.mk | ||
206 | 6 | 5 | ||
207 | === added directory 'debian/source' | |||
208 | === added file 'debian/source/format' | |||
209 | --- debian/source/format 1970-01-01 00:00:00 +0000 | |||
210 | +++ debian/source/format 2010-02-05 06:33:16 +0000 | |||
211 | @@ -0,0 +1,1 @@ | |||
212 | 1 | 3.0 (quilt) | ||
213 | 0 | 2 | ||
214 | === modified file 'django_openid_auth/__init__.py' | |||
215 | --- django_openid_auth/__init__.py 2009-04-08 15:07:49 +0000 | |||
216 | +++ django_openid_auth/__init__.py 2010-02-05 06:33:16 +0000 | |||
217 | @@ -26,3 +26,4 @@ | |||
218 | 26 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | 26 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
219 | 27 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 27 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
220 | 28 | # POSSIBILITY OF SUCH DAMAGE. | 28 | # POSSIBILITY OF SUCH DAMAGE. |
221 | 29 | |||
222 | 29 | 30 | ||
223 | === modified file 'django_openid_auth/admin.py' | |||
224 | --- django_openid_auth/admin.py 2009-04-08 15:07:49 +0000 | |||
225 | +++ django_openid_auth/admin.py 2010-02-05 06:33:16 +0000 | |||
226 | @@ -1,6 +1,7 @@ | |||
227 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | 1 | # django-openid-auth - OpenID integration for django.contrib.auth |
228 | 2 | # | 2 | # |
229 | 3 | # Copyright (C) 2008-2009 Canonical Ltd. | 3 | # Copyright (C) 2008-2009 Canonical Ltd. |
230 | 4 | # Copyright (C) 2010 Dave Walker | ||
231 | 4 | # | 5 | # |
232 | 5 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
233 | 6 | # modification, are permitted provided that the following conditions | 7 | # modification, are permitted provided that the following conditions |
234 | @@ -26,6 +27,7 @@ | |||
235 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 27 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
236 | 27 | # POSSIBILITY OF SUCH DAMAGE. | 28 | # POSSIBILITY OF SUCH DAMAGE. |
237 | 28 | 29 | ||
238 | 30 | from django.conf import settings | ||
239 | 29 | from django.contrib import admin | 31 | from django.contrib import admin |
240 | 30 | from django_openid_auth.models import Nonce, Association, UserOpenID | 32 | from django_openid_auth.models import Nonce, Association, UserOpenID |
241 | 31 | from django_openid_auth.store import DjangoOpenIDStore | 33 | from django_openid_auth.store import DjangoOpenIDStore |
242 | @@ -64,3 +66,25 @@ | |||
243 | 64 | search_fields = ('claimed_id',) | 66 | search_fields = ('claimed_id',) |
244 | 65 | 67 | ||
245 | 66 | admin.site.register(UserOpenID, UserOpenIDAdmin) | 68 | admin.site.register(UserOpenID, UserOpenIDAdmin) |
246 | 69 | |||
247 | 70 | |||
248 | 71 | # Support for allowing openid authentication for /admin (django.contrib.admin) | ||
249 | 72 | if getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False): | ||
250 | 73 | from django.http import HttpResponseRedirect | ||
251 | 74 | from django_openid_auth import views | ||
252 | 75 | |||
253 | 76 | def _openid_login(self, request, error_message='', extra_context=None): | ||
254 | 77 | if request.user.is_authenticated(): | ||
255 | 78 | if not request.user.is_staff: | ||
256 | 79 | return views.render_failure( | ||
257 | 80 | request, "User %s does not have admin access." | ||
258 | 81 | % request.user.username) | ||
259 | 82 | return views.render_failure( | ||
260 | 83 | request, "Unknown Error: %s" % error_message) | ||
261 | 84 | else: | ||
262 | 85 | # Redirect to openid login path, | ||
263 | 86 | return HttpResponseRedirect( | ||
264 | 87 | settings.LOGIN_URL + "?next=" + request.get_full_path()) | ||
265 | 88 | |||
266 | 89 | # Overide the standard admin login form. | ||
267 | 90 | admin.sites.AdminSite.display_login_form = _openid_login | ||
268 | 67 | 91 | ||
269 | === modified file 'django_openid_auth/auth.py' | |||
270 | --- django_openid_auth/auth.py 2009-04-08 15:07:49 +0000 | |||
271 | +++ django_openid_auth/auth.py 2010-02-05 06:33:16 +0000 | |||
272 | @@ -158,7 +158,16 @@ | |||
273 | 158 | user.save() | 158 | user.save() |
274 | 159 | 159 | ||
275 | 160 | def update_groups_from_teams(self, user, teams_response): | 160 | def update_groups_from_teams(self, user, teams_response): |
276 | 161 | teams_mapping_auto = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False) | ||
277 | 162 | teams_mapping_auto_blacklist = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', []) | ||
278 | 161 | teams_mapping = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) | 163 | teams_mapping = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) |
279 | 164 | if teams_mapping_auto: | ||
280 | 165 | #ignore teams_mapping. use all django-groups | ||
281 | 166 | teams_mapping = dict() | ||
282 | 167 | all_groups = Group.objects.exclude(name__in=teams_mapping_auto_blacklist) | ||
283 | 168 | for group in all_groups: | ||
284 | 169 | teams_mapping[group.name] = group.name | ||
285 | 170 | |||
286 | 162 | if len(teams_mapping) == 0: | 171 | if len(teams_mapping) == 0: |
287 | 163 | return | 172 | return |
288 | 164 | 173 | ||
289 | 165 | 174 | ||
290 | === modified file 'django_openid_auth/forms.py' | |||
291 | --- django_openid_auth/forms.py 2009-04-08 15:07:49 +0000 | |||
292 | +++ django_openid_auth/forms.py 2010-02-05 06:33:16 +0000 | |||
293 | @@ -28,12 +28,48 @@ | |||
294 | 28 | # POSSIBILITY OF SUCH DAMAGE. | 28 | # POSSIBILITY OF SUCH DAMAGE. |
295 | 29 | 29 | ||
296 | 30 | from django import forms | 30 | from django import forms |
297 | 31 | from django.contrib.auth.admin import UserAdmin | ||
298 | 32 | from django.contrib.auth.forms import UserChangeForm | ||
299 | 33 | from django.contrib.auth.models import Group | ||
300 | 31 | from django.utils.translation import ugettext as _ | 34 | from django.utils.translation import ugettext as _ |
301 | 32 | from django.conf import settings | 35 | from django.conf import settings |
302 | 33 | 36 | ||
303 | 34 | from openid.yadis import xri | 37 | from openid.yadis import xri |
304 | 35 | 38 | ||
305 | 36 | 39 | ||
306 | 40 | def teams_new_unicode(self): | ||
307 | 41 | """ | ||
308 | 42 | Replacement for Group.__unicode__() | ||
309 | 43 | Calls original method to chain results | ||
310 | 44 | """ | ||
311 | 45 | name = self.unicode_before_teams() | ||
312 | 46 | teams_mapping = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) | ||
313 | 47 | group_teams = [t for t in teams_mapping if teams_mapping[t] == self.name] | ||
314 | 48 | if len(group_teams) > 0: | ||
315 | 49 | return "%s -> %s" % (name, ", ".join(group_teams)) | ||
316 | 50 | else: | ||
317 | 51 | return name | ||
318 | 52 | Group.unicode_before_teams = Group.__unicode__ | ||
319 | 53 | Group.__unicode__ = teams_new_unicode | ||
320 | 54 | |||
321 | 55 | |||
322 | 56 | class UserChangeFormWithTeamRestriction(UserChangeForm): | ||
323 | 57 | """ | ||
324 | 58 | Extends UserChangeForm to add teams awareness to the user admin form | ||
325 | 59 | """ | ||
326 | 60 | def clean_groups(self): | ||
327 | 61 | data = self.cleaned_data['groups'] | ||
328 | 62 | teams_mapping = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) | ||
329 | 63 | known_teams = teams_mapping.values() | ||
330 | 64 | user_groups = self.instance.groups.all() | ||
331 | 65 | for group in data: | ||
332 | 66 | if group.name in known_teams and group not in user_groups: | ||
333 | 67 | raise forms.ValidationError("""The group %s is mapped to an | ||
334 | 68 | external team. You cannot assign it manually.""" % group.name) | ||
335 | 69 | return data | ||
336 | 70 | UserAdmin.form = UserChangeFormWithTeamRestriction | ||
337 | 71 | |||
338 | 72 | |||
339 | 37 | class OpenIDLoginForm(forms.Form): | 73 | class OpenIDLoginForm(forms.Form): |
340 | 38 | openid_identifier = forms.CharField( | 74 | openid_identifier = forms.CharField( |
341 | 39 | max_length=255, | 75 | max_length=255, |
342 | 40 | 76 | ||
343 | === modified file 'django_openid_auth/management/__init__.py' | |||
344 | --- django_openid_auth/management/__init__.py 2009-04-08 15:07:49 +0000 | |||
345 | +++ django_openid_auth/management/__init__.py 2010-02-05 06:33:16 +0000 | |||
346 | @@ -0,0 +1,27 @@ | |||
347 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
348 | 2 | # | ||
349 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
350 | 4 | # | ||
351 | 5 | # Redistribution and use in source and binary forms, with or without | ||
352 | 6 | # modification, are permitted provided that the following conditions | ||
353 | 7 | # are met: | ||
354 | 8 | # | ||
355 | 9 | # * Redistributions of source code must retain the above copyright | ||
356 | 10 | # notice, this list of conditions and the following disclaimer. | ||
357 | 11 | # | ||
358 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
359 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
360 | 14 | # documentation and/or other materials provided with the distribution. | ||
361 | 15 | # | ||
362 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
363 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
364 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
365 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
366 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
367 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
368 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
369 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
370 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
371 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
372 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
373 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
374 | 0 | 28 | ||
375 | === modified file 'django_openid_auth/management/commands/__init__.py' | |||
376 | --- django_openid_auth/management/commands/__init__.py 2009-04-08 15:07:49 +0000 | |||
377 | +++ django_openid_auth/management/commands/__init__.py 2010-02-05 06:33:16 +0000 | |||
378 | @@ -0,0 +1,27 @@ | |||
379 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
380 | 2 | # | ||
381 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
382 | 4 | # | ||
383 | 5 | # Redistribution and use in source and binary forms, with or without | ||
384 | 6 | # modification, are permitted provided that the following conditions | ||
385 | 7 | # are met: | ||
386 | 8 | # | ||
387 | 9 | # * Redistributions of source code must retain the above copyright | ||
388 | 10 | # notice, this list of conditions and the following disclaimer. | ||
389 | 11 | # | ||
390 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
391 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
392 | 14 | # documentation and/or other materials provided with the distribution. | ||
393 | 15 | # | ||
394 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
395 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
396 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
397 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
398 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
399 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
400 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
401 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
402 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
403 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
404 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
405 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
406 | 0 | 28 | ||
407 | === modified file 'django_openid_auth/management/commands/openid_cleanup.py' | |||
408 | --- django_openid_auth/management/commands/openid_cleanup.py 2009-04-08 15:07:49 +0000 | |||
409 | +++ django_openid_auth/management/commands/openid_cleanup.py 2010-02-05 06:33:16 +0000 | |||
410 | @@ -1,3 +1,31 @@ | |||
411 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
412 | 2 | # | ||
413 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
414 | 4 | # | ||
415 | 5 | # Redistribution and use in source and binary forms, with or without | ||
416 | 6 | # modification, are permitted provided that the following conditions | ||
417 | 7 | # are met: | ||
418 | 8 | # | ||
419 | 9 | # * Redistributions of source code must retain the above copyright | ||
420 | 10 | # notice, this list of conditions and the following disclaimer. | ||
421 | 11 | # | ||
422 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
423 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
424 | 14 | # documentation and/or other materials provided with the distribution. | ||
425 | 15 | # | ||
426 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
427 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
428 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
429 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
430 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
431 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
432 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
433 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
434 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
435 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
436 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
437 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
438 | 28 | |||
439 | 1 | from django.core.management.base import NoArgsCommand | 29 | from django.core.management.base import NoArgsCommand |
440 | 2 | 30 | ||
441 | 3 | from django_openid_auth.store import DjangoOpenIDStore | 31 | from django_openid_auth.store import DjangoOpenIDStore |
442 | 4 | 32 | ||
443 | === modified file 'django_openid_auth/store.py' | |||
444 | --- django_openid_auth/store.py 2009-04-08 15:07:49 +0000 | |||
445 | +++ django_openid_auth/store.py 2010-02-05 06:33:16 +0000 | |||
446 | @@ -42,13 +42,22 @@ | |||
447 | 42 | self.max_nonce_age = 6 * 60 * 60 # Six hours | 42 | self.max_nonce_age = 6 * 60 * 60 # Six hours |
448 | 43 | 43 | ||
449 | 44 | def storeAssociation(self, server_url, association): | 44 | def storeAssociation(self, server_url, association): |
457 | 45 | assoc = Association( | 45 | try: |
458 | 46 | server_url=server_url, | 46 | assoc = Association.objects.get( |
459 | 47 | handle=association.handle, | 47 | server_url=server_url, handle=association.handle) |
460 | 48 | secret=base64.encodestring(association.secret), | 48 | except Association.DoesNotExist: |
461 | 49 | issued=association.issued, | 49 | assoc = Association( |
462 | 50 | lifetime=association.lifetime, | 50 | server_url=server_url, |
463 | 51 | assoc_type=association.assoc_type) | 51 | handle=association.handle, |
464 | 52 | secret=base64.encodestring(association.secret), | ||
465 | 53 | issued=association.issued, | ||
466 | 54 | lifetime=association.lifetime, | ||
467 | 55 | assoc_type=association.assoc_type) | ||
468 | 56 | else: | ||
469 | 57 | assoc.secret = base64.encodestring(association.secret) | ||
470 | 58 | assoc.issued = association.issued | ||
471 | 59 | assoc.lifetime = association.lifetime | ||
472 | 60 | assoc.assoc_type = association.assoc_type | ||
473 | 52 | assoc.save() | 61 | assoc.save() |
474 | 53 | 62 | ||
475 | 54 | def getAssociation(self, server_url, handle=None): | 63 | def getAssociation(self, server_url, handle=None): |
476 | 55 | 64 | ||
477 | === modified file 'django_openid_auth/templates/openid/login.html' | |||
478 | --- django_openid_auth/templates/openid/login.html 2009-04-08 15:07:49 +0000 | |||
479 | +++ django_openid_auth/templates/openid/login.html 2010-02-05 06:33:16 +0000 | |||
480 | @@ -28,8 +28,10 @@ | |||
481 | 28 | <form name="fopenid" action="{{ action }}" method="post"> | 28 | <form name="fopenid" action="{{ action }}" method="post"> |
482 | 29 | <fieldset> | 29 | <fieldset> |
483 | 30 | <legend>{% trans "Sign In Using Your OpenID" %}</legend> | 30 | <legend>{% trans "Sign In Using Your OpenID" %}</legend> |
486 | 31 | <div class="form-row"><label for="id_openid_identifier">{% | 31 | <div class="form-row"> |
487 | 32 | trans "OpenID:" %}</label><br />{{ form.openid_identifier }}</div> | 32 | <label for="id_openid_identifier">{% trans "OpenID:" %}</label><br /> |
488 | 33 | {{ form.openid_identifier }} | ||
489 | 34 | </div> | ||
490 | 33 | <div class="submit-row "><input name="bsignin" type="submit" value="{% trans "Sign in" %}"></div> | 35 | <div class="submit-row "><input name="bsignin" type="submit" value="{% trans "Sign in" %}"></div> |
491 | 34 | 36 | ||
492 | 35 | {% if next %} | 37 | {% if next %} |
493 | 36 | 38 | ||
494 | === modified file 'django_openid_auth/tests/__init__.py' | |||
495 | --- django_openid_auth/tests/__init__.py 2009-04-08 15:07:49 +0000 | |||
496 | +++ django_openid_auth/tests/__init__.py 2010-02-05 06:33:16 +0000 | |||
497 | @@ -1,3 +1,31 @@ | |||
498 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
499 | 2 | # | ||
500 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
501 | 4 | # | ||
502 | 5 | # Redistribution and use in source and binary forms, with or without | ||
503 | 6 | # modification, are permitted provided that the following conditions | ||
504 | 7 | # are met: | ||
505 | 8 | # | ||
506 | 9 | # * Redistributions of source code must retain the above copyright | ||
507 | 10 | # notice, this list of conditions and the following disclaimer. | ||
508 | 11 | # | ||
509 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
510 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
511 | 14 | # documentation and/or other materials provided with the distribution. | ||
512 | 15 | # | ||
513 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
514 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
515 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
516 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
517 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
518 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
519 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
520 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
521 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
522 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
523 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
524 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
525 | 28 | |||
526 | 1 | import unittest | 29 | import unittest |
527 | 2 | 30 | ||
528 | 3 | 31 | ||
529 | 4 | 32 | ||
530 | === modified file 'django_openid_auth/tests/test_store.py' | |||
531 | --- django_openid_auth/tests/test_store.py 2009-04-08 15:07:49 +0000 | |||
532 | +++ django_openid_auth/tests/test_store.py 2010-02-05 06:33:16 +0000 | |||
533 | @@ -1,3 +1,31 @@ | |||
534 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
535 | 2 | # | ||
536 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
537 | 4 | # | ||
538 | 5 | # Redistribution and use in source and binary forms, with or without | ||
539 | 6 | # modification, are permitted provided that the following conditions | ||
540 | 7 | # are met: | ||
541 | 8 | # | ||
542 | 9 | # * Redistributions of source code must retain the above copyright | ||
543 | 10 | # notice, this list of conditions and the following disclaimer. | ||
544 | 11 | # | ||
545 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
546 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
547 | 14 | # documentation and/or other materials provided with the distribution. | ||
548 | 15 | # | ||
549 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
550 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
551 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
552 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
553 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
554 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
555 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
556 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
557 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
558 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
559 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
560 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
561 | 28 | |||
562 | 1 | import time | 29 | import time |
563 | 2 | import unittest | 30 | import unittest |
564 | 3 | 31 | ||
565 | @@ -28,6 +56,20 @@ | |||
566 | 28 | self.assertEquals(dbassoc.lifetime, 600) | 56 | self.assertEquals(dbassoc.lifetime, 600) |
567 | 29 | self.assertEquals(dbassoc.assoc_type, 'HMAC-SHA1') | 57 | self.assertEquals(dbassoc.assoc_type, 'HMAC-SHA1') |
568 | 30 | 58 | ||
569 | 59 | def test_storeAssociation_update_existing(self): | ||
570 | 60 | assoc = OIDAssociation('handle', 'secret', 42, 600, 'HMAC-SHA1') | ||
571 | 61 | self.store.storeAssociation('server-url', assoc) | ||
572 | 62 | |||
573 | 63 | # Now update the association with new information. | ||
574 | 64 | assoc = OIDAssociation('handle', 'secret2', 420, 900, 'HMAC-SHA256') | ||
575 | 65 | self.store.storeAssociation('server-url', assoc) | ||
576 | 66 | dbassoc = Association.objects.get( | ||
577 | 67 | server_url='server-url', handle='handle') | ||
578 | 68 | self.assertEqual(dbassoc.secret, 'secret2'.encode('base-64')) | ||
579 | 69 | self.assertEqual(dbassoc.issued, 420) | ||
580 | 70 | self.assertEqual(dbassoc.lifetime, 900) | ||
581 | 71 | self.assertEqual(dbassoc.assoc_type, 'HMAC-SHA256') | ||
582 | 72 | |||
583 | 31 | def test_getAssociation(self): | 73 | def test_getAssociation(self): |
584 | 32 | timestamp = int(time.time()) | 74 | timestamp = int(time.time()) |
585 | 33 | self.store.storeAssociation( | 75 | self.store.storeAssociation( |
586 | @@ -76,9 +118,6 @@ | |||
587 | 76 | self.assertEquals(assoc.issued, timestamp + 1) | 118 | self.assertEquals(assoc.issued, timestamp + 1) |
588 | 77 | 119 | ||
589 | 78 | def test_removeAssociation(self): | 120 | def test_removeAssociation(self): |
590 | 79 | self.assertEquals( | ||
591 | 80 | self.store.removeAssociation('server-url', 'unknown'), False) | ||
592 | 81 | |||
593 | 82 | timestamp = int(time.time()) | 121 | timestamp = int(time.time()) |
594 | 83 | self.store.storeAssociation( | 122 | self.store.storeAssociation( |
595 | 84 | 'server-url', OIDAssociation('handle', 'secret', timestamp, 600, | 123 | 'server-url', OIDAssociation('handle', 'secret', timestamp, 600, |
596 | @@ -88,6 +127,10 @@ | |||
597 | 88 | self.assertEquals( | 127 | self.assertEquals( |
598 | 89 | self.store.getAssociation('server-url', 'handle'), None) | 128 | self.store.getAssociation('server-url', 'handle'), None) |
599 | 90 | 129 | ||
600 | 130 | def test_removeAssociation_unknown(self): | ||
601 | 131 | self.assertEquals( | ||
602 | 132 | self.store.removeAssociation('server-url', 'unknown'), False) | ||
603 | 133 | |||
604 | 91 | def test_useNonce(self): | 134 | def test_useNonce(self): |
605 | 92 | timestamp = time.time() | 135 | timestamp = time.time() |
606 | 93 | # The nonce can only be used once. | 136 | # The nonce can only be used once. |
607 | 94 | 137 | ||
608 | === modified file 'django_openid_auth/tests/test_views.py' | |||
609 | --- django_openid_auth/tests/test_views.py 2009-04-08 15:07:49 +0000 | |||
610 | +++ django_openid_auth/tests/test_views.py 2010-02-05 06:33:16 +0000 | |||
611 | @@ -1,3 +1,31 @@ | |||
612 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
613 | 2 | # | ||
614 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
615 | 4 | # | ||
616 | 5 | # Redistribution and use in source and binary forms, with or without | ||
617 | 6 | # modification, are permitted provided that the following conditions | ||
618 | 7 | # are met: | ||
619 | 8 | # | ||
620 | 9 | # * Redistributions of source code must retain the above copyright | ||
621 | 10 | # notice, this list of conditions and the following disclaimer. | ||
622 | 11 | # | ||
623 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
624 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
625 | 14 | # documentation and/or other materials provided with the distribution. | ||
626 | 15 | # | ||
627 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
628 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
629 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
630 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
631 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
632 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
633 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
634 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
635 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
636 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
637 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
638 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
639 | 28 | |||
640 | 1 | import cgi | 29 | import cgi |
641 | 2 | import re | 30 | import re |
642 | 3 | import time | 31 | import time |
643 | @@ -15,6 +43,7 @@ | |||
644 | 15 | 43 | ||
645 | 16 | from django_openid_auth import teams | 44 | from django_openid_auth import teams |
646 | 17 | from django_openid_auth.models import UserOpenID | 45 | from django_openid_auth.models import UserOpenID |
647 | 46 | from django_openid_auth.views import sanitise_redirect_url | ||
648 | 18 | 47 | ||
649 | 19 | 48 | ||
650 | 20 | ET = importElementTree() | 49 | ET = importElementTree() |
651 | @@ -97,21 +126,26 @@ | |||
652 | 97 | self.provider = StubOpenIDProvider('http://example.com/') | 126 | self.provider = StubOpenIDProvider('http://example.com/') |
653 | 98 | setDefaultFetcher(self.provider, wrap_exceptions=False) | 127 | setDefaultFetcher(self.provider, wrap_exceptions=False) |
654 | 99 | 128 | ||
655 | 129 | self.old_login_redirect_url = getattr(settings, 'LOGIN_REDIRECT_URL', '/accounts/profile/') | ||
656 | 100 | self.old_create_users = getattr(settings, 'OPENID_CREATE_USERS', False) | 130 | self.old_create_users = getattr(settings, 'OPENID_CREATE_USERS', False) |
657 | 101 | self.old_update_details = getattr(settings, 'OPENID_UPDATE_DETAILS_FROM_SREG', False) | 131 | self.old_update_details = getattr(settings, 'OPENID_UPDATE_DETAILS_FROM_SREG', False) |
658 | 102 | self.old_sso_server_url = getattr(settings, 'OPENID_SSO_SERVER_URL') | 132 | self.old_sso_server_url = getattr(settings, 'OPENID_SSO_SERVER_URL') |
659 | 103 | self.old_teams_map = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) | 133 | self.old_teams_map = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) |
660 | 134 | self.old_use_as_admin_login = getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False) | ||
661 | 104 | 135 | ||
662 | 105 | settings.OPENID_CREATE_USERS = False | 136 | settings.OPENID_CREATE_USERS = False |
663 | 106 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = False | 137 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = False |
664 | 107 | settings.OPENID_SSO_SERVER_URL = None | 138 | settings.OPENID_SSO_SERVER_URL = None |
665 | 108 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {} | 139 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {} |
666 | 140 | settings.OPENID_USE_AS_ADMIN_LOGIN = False | ||
667 | 109 | 141 | ||
668 | 110 | def tearDown(self): | 142 | def tearDown(self): |
669 | 143 | settings.LOGIN_REDIRECT_URL = self.old_login_redirect_url | ||
670 | 111 | settings.OPENID_CREATE_USERS = self.old_create_users | 144 | settings.OPENID_CREATE_USERS = self.old_create_users |
671 | 112 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = self.old_update_details | 145 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = self.old_update_details |
672 | 113 | settings.OPENID_SSO_SERVER_URL = self.old_sso_server_url | 146 | settings.OPENID_SSO_SERVER_URL = self.old_sso_server_url |
673 | 114 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = self.old_teams_map | 147 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = self.old_teams_map |
674 | 148 | settings.OPENID_USE_AS_ADMIN_LOGIN = self.old_use_as_admin_login | ||
675 | 115 | 149 | ||
676 | 116 | setDefaultFetcher(None) | 150 | setDefaultFetcher(None) |
677 | 117 | super(RelyingPartyTests, self).tearDown() | 151 | super(RelyingPartyTests, self).tearDown() |
678 | @@ -122,8 +156,8 @@ | |||
679 | 122 | self.assertEquals(webresponse.code, 302) | 156 | self.assertEquals(webresponse.code, 302) |
680 | 123 | redirect_to = webresponse.headers['location'] | 157 | redirect_to = webresponse.headers['location'] |
681 | 124 | self.assertTrue(redirect_to.startswith( | 158 | self.assertTrue(redirect_to.startswith( |
684 | 125 | 'http://testserver/openid/complete')) | 159 | 'http://testserver/openid/complete/')) |
685 | 126 | return self.client.get('/openid/complete', | 160 | return self.client.get('/openid/complete/', |
686 | 127 | dict(cgi.parse_qsl(redirect_to.split('?', 1)[1]))) | 161 | dict(cgi.parse_qsl(redirect_to.split('?', 1)[1]))) |
687 | 128 | 162 | ||
688 | 129 | def test_login(self): | 163 | def test_login(self): |
689 | @@ -135,29 +169,54 @@ | |||
690 | 135 | useropenid.save() | 169 | useropenid.save() |
691 | 136 | 170 | ||
692 | 137 | # The login form is displayed: | 171 | # The login form is displayed: |
694 | 138 | response = self.client.get('/openid/login') | 172 | response = self.client.get('/openid/login/') |
695 | 139 | self.assertTemplateUsed(response, 'openid/login.html') | 173 | self.assertTemplateUsed(response, 'openid/login.html') |
696 | 140 | 174 | ||
697 | 141 | # Posting in an identity URL begins the authentication request: | 175 | # Posting in an identity URL begins the authentication request: |
699 | 142 | response = self.client.post('/openid/login', | 176 | response = self.client.post('/openid/login/', |
700 | 143 | {'openid_identifier': 'http://example.com/identity', | 177 | {'openid_identifier': 'http://example.com/identity', |
702 | 144 | 'next': '/getuser'}) | 178 | 'next': '/getuser/'}) |
703 | 145 | self.assertContains(response, 'OpenID transaction in progress') | 179 | self.assertContains(response, 'OpenID transaction in progress') |
704 | 146 | 180 | ||
705 | 147 | openid_request = self.provider.parseFormPost(response.content) | 181 | openid_request = self.provider.parseFormPost(response.content) |
706 | 148 | self.assertEquals(openid_request.mode, 'checkid_setup') | 182 | self.assertEquals(openid_request.mode, 'checkid_setup') |
707 | 149 | self.assertTrue(openid_request.return_to.startswith( | 183 | self.assertTrue(openid_request.return_to.startswith( |
709 | 150 | 'http://testserver/openid/complete')) | 184 | 'http://testserver/openid/complete/')) |
710 | 151 | 185 | ||
711 | 152 | # Complete the request. The user is redirected to the next URL. | 186 | # Complete the request. The user is redirected to the next URL. |
712 | 153 | openid_response = openid_request.answer(True) | 187 | openid_response = openid_request.answer(True) |
713 | 154 | response = self.complete(openid_response) | 188 | response = self.complete(openid_response) |
715 | 155 | self.assertRedirects(response, 'http://testserver/getuser') | 189 | self.assertRedirects(response, 'http://testserver/getuser/') |
716 | 156 | 190 | ||
717 | 157 | # And they are now logged in: | 191 | # And they are now logged in: |
719 | 158 | response = self.client.get('/getuser') | 192 | response = self.client.get('/getuser/') |
720 | 159 | self.assertEquals(response.content, 'someuser') | 193 | self.assertEquals(response.content, 'someuser') |
721 | 160 | 194 | ||
722 | 195 | def test_login_no_next(self): | ||
723 | 196 | """Logins with no next parameter redirect to LOGIN_REDIRECT_URL.""" | ||
724 | 197 | user = User.objects.create_user('someuser', 'someone@example.com') | ||
725 | 198 | useropenid = UserOpenID( | ||
726 | 199 | user=user, | ||
727 | 200 | claimed_id='http://example.com/identity', | ||
728 | 201 | display_id='http://example.com/identity') | ||
729 | 202 | useropenid.save() | ||
730 | 203 | |||
731 | 204 | settings.LOGIN_REDIRECT_URL = '/getuser/' | ||
732 | 205 | response = self.client.post('/openid/login/', | ||
733 | 206 | {'openid_identifier': 'http://example.com/identity'}) | ||
734 | 207 | self.assertContains(response, 'OpenID transaction in progress') | ||
735 | 208 | |||
736 | 209 | openid_request = self.provider.parseFormPost(response.content) | ||
737 | 210 | self.assertEquals(openid_request.mode, 'checkid_setup') | ||
738 | 211 | self.assertTrue(openid_request.return_to.startswith( | ||
739 | 212 | 'http://testserver/openid/complete/')) | ||
740 | 213 | |||
741 | 214 | # Complete the request. The user is redirected to the next URL. | ||
742 | 215 | openid_response = openid_request.answer(True) | ||
743 | 216 | response = self.complete(openid_response) | ||
744 | 217 | self.assertRedirects( | ||
745 | 218 | response, 'http://testserver' + settings.LOGIN_REDIRECT_URL) | ||
746 | 219 | |||
747 | 161 | def test_login_sso(self): | 220 | def test_login_sso(self): |
748 | 162 | settings.OPENID_SSO_SERVER_URL = 'http://example.com/identity' | 221 | settings.OPENID_SSO_SERVER_URL = 'http://example.com/identity' |
749 | 163 | user = User.objects.create_user('someuser', 'someone@example.com') | 222 | user = User.objects.create_user('someuser', 'someone@example.com') |
750 | @@ -169,22 +228,22 @@ | |||
751 | 169 | 228 | ||
752 | 170 | # Requesting the login form immediately begins an | 229 | # Requesting the login form immediately begins an |
753 | 171 | # authentication request. | 230 | # authentication request. |
755 | 172 | response = self.client.get('/openid/login', {'next': '/getuser'}) | 231 | response = self.client.get('/openid/login/', {'next': '/getuser/'}) |
756 | 173 | self.assertEquals(response.status_code, 200) | 232 | self.assertEquals(response.status_code, 200) |
757 | 174 | self.assertContains(response, 'OpenID transaction in progress') | 233 | self.assertContains(response, 'OpenID transaction in progress') |
758 | 175 | 234 | ||
759 | 176 | openid_request = self.provider.parseFormPost(response.content) | 235 | openid_request = self.provider.parseFormPost(response.content) |
760 | 177 | self.assertEquals(openid_request.mode, 'checkid_setup') | 236 | self.assertEquals(openid_request.mode, 'checkid_setup') |
761 | 178 | self.assertTrue(openid_request.return_to.startswith( | 237 | self.assertTrue(openid_request.return_to.startswith( |
763 | 179 | 'http://testserver/openid/complete')) | 238 | 'http://testserver/openid/complete/')) |
764 | 180 | 239 | ||
765 | 181 | # Complete the request. The user is redirected to the next URL. | 240 | # Complete the request. The user is redirected to the next URL. |
766 | 182 | openid_response = openid_request.answer(True) | 241 | openid_response = openid_request.answer(True) |
767 | 183 | response = self.complete(openid_response) | 242 | response = self.complete(openid_response) |
769 | 184 | self.assertRedirects(response, 'http://testserver/getuser') | 243 | self.assertRedirects(response, 'http://testserver/getuser/') |
770 | 185 | 244 | ||
771 | 186 | # And they are now logged in: | 245 | # And they are now logged in: |
773 | 187 | response = self.client.get('/getuser') | 246 | response = self.client.get('/getuser/') |
774 | 188 | self.assertEquals(response.content, 'someuser') | 247 | self.assertEquals(response.content, 'someuser') |
775 | 189 | 248 | ||
776 | 190 | def test_login_create_users(self): | 249 | def test_login_create_users(self): |
777 | @@ -193,9 +252,9 @@ | |||
778 | 193 | User.objects.create_user('someuser', 'someone@example.com') | 252 | User.objects.create_user('someuser', 'someone@example.com') |
779 | 194 | 253 | ||
780 | 195 | # Posting in an identity URL begins the authentication request: | 254 | # Posting in an identity URL begins the authentication request: |
782 | 196 | response = self.client.post('/openid/login', | 255 | response = self.client.post('/openid/login/', |
783 | 197 | {'openid_identifier': 'http://example.com/identity', | 256 | {'openid_identifier': 'http://example.com/identity', |
785 | 198 | 'next': '/getuser'}) | 257 | 'next': '/getuser/'}) |
786 | 199 | self.assertContains(response, 'OpenID transaction in progress') | 258 | self.assertContains(response, 'OpenID transaction in progress') |
787 | 200 | 259 | ||
788 | 201 | # Complete the request, passing back some simple registration | 260 | # Complete the request, passing back some simple registration |
789 | @@ -208,11 +267,11 @@ | |||
790 | 208 | 'email': 'foo@example.com'}) | 267 | 'email': 'foo@example.com'}) |
791 | 209 | openid_response.addExtension(sreg_response) | 268 | openid_response.addExtension(sreg_response) |
792 | 210 | response = self.complete(openid_response) | 269 | response = self.complete(openid_response) |
794 | 211 | self.assertRedirects(response, 'http://testserver/getuser') | 270 | self.assertRedirects(response, 'http://testserver/getuser/') |
795 | 212 | 271 | ||
796 | 213 | # And they are now logged in as a new user (they haven't taken | 272 | # And they are now logged in as a new user (they haven't taken |
797 | 214 | # over the existing "someuser" user). | 273 | # over the existing "someuser" user). |
799 | 215 | response = self.client.get('/getuser') | 274 | response = self.client.get('/getuser/') |
800 | 216 | self.assertEquals(response.content, 'someuser2') | 275 | self.assertEquals(response.content, 'someuser2') |
801 | 217 | 276 | ||
802 | 218 | # Check the details of the new user. | 277 | # Check the details of the new user. |
803 | @@ -231,9 +290,9 @@ | |||
804 | 231 | useropenid.save() | 290 | useropenid.save() |
805 | 232 | 291 | ||
806 | 233 | # Posting in an identity URL begins the authentication request: | 292 | # Posting in an identity URL begins the authentication request: |
808 | 234 | response = self.client.post('/openid/login', | 293 | response = self.client.post('/openid/login/', |
809 | 235 | {'openid_identifier': 'http://example.com/identity', | 294 | {'openid_identifier': 'http://example.com/identity', |
811 | 236 | 'next': '/getuser'}) | 295 | 'next': '/getuser/'}) |
812 | 237 | self.assertContains(response, 'OpenID transaction in progress') | 296 | self.assertContains(response, 'OpenID transaction in progress') |
813 | 238 | 297 | ||
814 | 239 | # Complete the request, passing back some simple registration | 298 | # Complete the request, passing back some simple registration |
815 | @@ -246,11 +305,11 @@ | |||
816 | 246 | 'email': 'foo@example.com'}) | 305 | 'email': 'foo@example.com'}) |
817 | 247 | openid_response.addExtension(sreg_response) | 306 | openid_response.addExtension(sreg_response) |
818 | 248 | response = self.complete(openid_response) | 307 | response = self.complete(openid_response) |
820 | 249 | self.assertRedirects(response, 'http://testserver/getuser') | 308 | self.assertRedirects(response, 'http://testserver/getuser/') |
821 | 250 | 309 | ||
822 | 251 | # And they are now logged in as testuser (the passed in | 310 | # And they are now logged in as testuser (the passed in |
823 | 252 | # nickname has not caused the username to change). | 311 | # nickname has not caused the username to change). |
825 | 253 | response = self.client.get('/getuser') | 312 | response = self.client.get('/getuser/') |
826 | 254 | self.assertEquals(response.content, 'testuser') | 313 | self.assertEquals(response.content, 'testuser') |
827 | 255 | 314 | ||
828 | 256 | # The user's full name and email have been updated. | 315 | # The user's full name and email have been updated. |
829 | @@ -276,9 +335,9 @@ | |||
830 | 276 | useropenid.save() | 335 | useropenid.save() |
831 | 277 | 336 | ||
832 | 278 | # Posting in an identity URL begins the authentication request: | 337 | # Posting in an identity URL begins the authentication request: |
834 | 279 | response = self.client.post('/openid/login', | 338 | response = self.client.post('/openid/login/', |
835 | 280 | {'openid_identifier': 'http://example.com/identity', | 339 | {'openid_identifier': 'http://example.com/identity', |
837 | 281 | 'next': '/getuser'}) | 340 | 'next': '/getuser/'}) |
838 | 282 | self.assertContains(response, 'OpenID transaction in progress') | 341 | self.assertContains(response, 'OpenID transaction in progress') |
839 | 283 | 342 | ||
840 | 284 | # Complete the request | 343 | # Complete the request |
841 | @@ -289,10 +348,10 @@ | |||
842 | 289 | teams_request, 'teamname,some-other-team') | 348 | teams_request, 'teamname,some-other-team') |
843 | 290 | openid_response.addExtension(teams_response) | 349 | openid_response.addExtension(teams_response) |
844 | 291 | response = self.complete(openid_response) | 350 | response = self.complete(openid_response) |
846 | 292 | self.assertRedirects(response, 'http://testserver/getuser') | 351 | self.assertRedirects(response, 'http://testserver/getuser/') |
847 | 293 | 352 | ||
848 | 294 | # And they are now logged in as testuser | 353 | # And they are now logged in as testuser |
850 | 295 | response = self.client.get('/getuser') | 354 | response = self.client.get('/getuser/') |
851 | 296 | self.assertEquals(response.content, 'testuser') | 355 | self.assertEquals(response.content, 'testuser') |
852 | 297 | 356 | ||
853 | 298 | # The user's groups have been updated. | 357 | # The user's groups have been updated. |
854 | @@ -300,6 +359,65 @@ | |||
855 | 300 | self.assertTrue(group in user.groups.all()) | 359 | self.assertTrue(group in user.groups.all()) |
856 | 301 | self.assertTrue(ogroup not in user.groups.all()) | 360 | self.assertTrue(ogroup not in user.groups.all()) |
857 | 302 | 361 | ||
859 | 303 | 362 | def test_login_teams_automapping(self): | |
860 | 363 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {'teamname': 'groupname', | ||
861 | 364 | 'otherteam': 'othergroup'} | ||
862 | 365 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO = True | ||
863 | 366 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST = ['django-group1', 'django-group2'] | ||
864 | 367 | user = User.objects.create_user('testuser', 'someone@example.com') | ||
865 | 368 | group1 = Group(name='django-group1') | ||
866 | 369 | group1.save() | ||
867 | 370 | group2 = Group(name='django-group2') | ||
868 | 371 | group2.save() | ||
869 | 372 | group3 = Group(name='django-group3') | ||
870 | 373 | group3.save() | ||
871 | 374 | user.save() | ||
872 | 375 | useropenid = UserOpenID( | ||
873 | 376 | user=user, | ||
874 | 377 | claimed_id='http://example.com/identity', | ||
875 | 378 | display_id='http://example.com/identity') | ||
876 | 379 | useropenid.save() | ||
877 | 380 | |||
878 | 381 | # Posting in an identity URL begins the authentication request: | ||
879 | 382 | response = self.client.post('/openid/login/', | ||
880 | 383 | {'openid_identifier': 'http://example.com/identity', | ||
881 | 384 | 'next': '/getuser/'}) | ||
882 | 385 | self.assertContains(response, 'OpenID transaction in progress') | ||
883 | 386 | |||
884 | 387 | # Complete the request | ||
885 | 388 | openid_request = self.provider.parseFormPost(response.content) | ||
886 | 389 | openid_response = openid_request.answer(True) | ||
887 | 390 | teams_request = teams.TeamsRequest.fromOpenIDRequest(openid_request) | ||
888 | 391 | |||
889 | 392 | self.assertEqual(group1 in user.groups.all(), False) | ||
890 | 393 | self.assertEqual(group2 in user.groups.all(), False) | ||
891 | 394 | self.assertTrue(group3 not in user.groups.all()) | ||
892 | 395 | |||
893 | 396 | class HelperFunctionsTest(TestCase): | ||
894 | 397 | def test_sanitise_redirect_url(self): | ||
895 | 398 | settings.ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [ | ||
896 | 399 | "example.com", "example.org"] | ||
897 | 400 | # list of URLs and whether they should be passed or not | ||
898 | 401 | urls = [ | ||
899 | 402 | ("http://example.com", True), | ||
900 | 403 | ("http://example.org/", True), | ||
901 | 404 | ("http://example.org/foo/bar", True), | ||
902 | 405 | ("http://example.org/foo/bar?baz=quux", True), | ||
903 | 406 | ("http://example.org:9999/foo/bar?baz=quux", True), | ||
904 | 407 | ("http://www.example.org/", False), | ||
905 | 408 | ("http://example.net/foo/bar?baz=quux", False), | ||
906 | 409 | ("/somewhere/local", True), | ||
907 | 410 | ("/somewhere/local?url=http://fail.com/bar", True), | ||
908 | 411 | # An empty path, as seen when no "next" parameter is passed. | ||
909 | 412 | ("", False), | ||
910 | 413 | ("/path with spaces", False), | ||
911 | 414 | ] | ||
912 | 415 | for url, returns_self in urls: | ||
913 | 416 | sanitised = sanitise_redirect_url(url) | ||
914 | 417 | if returns_self: | ||
915 | 418 | self.assertEqual(url, sanitised) | ||
916 | 419 | else: | ||
917 | 420 | self.assertEqual(settings.LOGIN_REDIRECT_URL, sanitised) | ||
918 | 421 | |||
919 | 304 | def suite(): | 422 | def suite(): |
920 | 305 | return unittest.TestLoader().loadTestsFromName(__name__) | 423 | return unittest.TestLoader().loadTestsFromName(__name__) |
921 | 306 | 424 | ||
922 | === modified file 'django_openid_auth/tests/urls.py' | |||
923 | --- django_openid_auth/tests/urls.py 2009-04-08 15:07:49 +0000 | |||
924 | +++ django_openid_auth/tests/urls.py 2010-02-05 06:33:16 +0000 | |||
925 | @@ -1,3 +1,31 @@ | |||
926 | 1 | # django-openid-auth - OpenID integration for django.contrib.auth | ||
927 | 2 | # | ||
928 | 3 | # Copyright (C) 2009 Canonical Ltd. | ||
929 | 4 | # | ||
930 | 5 | # Redistribution and use in source and binary forms, with or without | ||
931 | 6 | # modification, are permitted provided that the following conditions | ||
932 | 7 | # are met: | ||
933 | 8 | # | ||
934 | 9 | # * Redistributions of source code must retain the above copyright | ||
935 | 10 | # notice, this list of conditions and the following disclaimer. | ||
936 | 11 | # | ||
937 | 12 | # * Redistributions in binary form must reproduce the above copyright | ||
938 | 13 | # notice, this list of conditions and the following disclaimer in the | ||
939 | 14 | # documentation and/or other materials provided with the distribution. | ||
940 | 15 | # | ||
941 | 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
942 | 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
943 | 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
944 | 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
945 | 20 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
946 | 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
947 | 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
948 | 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
949 | 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
950 | 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
951 | 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
952 | 27 | # POSSIBILITY OF SUCH DAMAGE. | ||
953 | 28 | |||
954 | 1 | from django.http import HttpResponse | 29 | from django.http import HttpResponse |
955 | 2 | from django.conf.urls.defaults import * | 30 | from django.conf.urls.defaults import * |
956 | 3 | 31 | ||
957 | @@ -6,6 +34,6 @@ | |||
958 | 6 | return HttpResponse(request.user.username) | 34 | return HttpResponse(request.user.username) |
959 | 7 | 35 | ||
960 | 8 | urlpatterns = patterns('', | 36 | urlpatterns = patterns('', |
962 | 9 | (r'^getuser', get_user), | 37 | (r'^getuser/$', get_user), |
963 | 10 | (r'^openid/', include('django_openid_auth.urls')), | 38 | (r'^openid/', include('django_openid_auth.urls')), |
964 | 11 | ) | 39 | ) |
965 | 12 | 40 | ||
966 | === modified file 'django_openid_auth/urls.py' | |||
967 | --- django_openid_auth/urls.py 2009-04-08 15:07:49 +0000 | |||
968 | +++ django_openid_auth/urls.py 2010-02-05 06:33:16 +0000 | |||
969 | @@ -30,7 +30,7 @@ | |||
970 | 30 | from django.conf.urls.defaults import * | 30 | from django.conf.urls.defaults import * |
971 | 31 | 31 | ||
972 | 32 | urlpatterns = patterns('django_openid_auth.views', | 32 | urlpatterns = patterns('django_openid_auth.views', |
976 | 33 | (r'^login$', 'login_begin'), | 33 | (r'^login/$', 'login_begin'), |
977 | 34 | (r'^complete$', 'login_complete'), | 34 | (r'^complete/$', 'login_complete'), |
978 | 35 | url(r'^logo$', 'logo', name='openid-logo'), | 35 | url(r'^logo.gif$', 'logo', name='openid-logo'), |
979 | 36 | ) | 36 | ) |
980 | 37 | 37 | ||
981 | === modified file 'django_openid_auth/views.py' | |||
982 | --- django_openid_auth/views.py 2009-04-08 15:07:49 +0000 | |||
983 | +++ django_openid_auth/views.py 2010-02-05 06:33:16 +0000 | |||
984 | @@ -29,10 +29,12 @@ | |||
985 | 29 | 29 | ||
986 | 30 | import re | 30 | import re |
987 | 31 | import urllib | 31 | import urllib |
988 | 32 | from urlparse import urlsplit | ||
989 | 32 | 33 | ||
990 | 33 | from django.conf import settings | 34 | from django.conf import settings |
991 | 34 | from django.contrib.auth import ( | 35 | from django.contrib.auth import ( |
992 | 35 | REDIRECT_FIELD_NAME, authenticate, login as auth_login) | 36 | REDIRECT_FIELD_NAME, authenticate, login as auth_login) |
993 | 37 | from django.contrib.auth.models import Group | ||
994 | 36 | from django.core.urlresolvers import reverse | 38 | from django.core.urlresolvers import reverse |
995 | 37 | from django.http import HttpResponse, HttpResponseRedirect | 39 | from django.http import HttpResponse, HttpResponseRedirect |
996 | 38 | from django.shortcuts import render_to_response | 40 | from django.shortcuts import render_to_response |
997 | @@ -62,8 +64,26 @@ | |||
998 | 62 | def sanitise_redirect_url(redirect_to): | 64 | def sanitise_redirect_url(redirect_to): |
999 | 63 | """Sanitise the redirection URL.""" | 65 | """Sanitise the redirection URL.""" |
1000 | 64 | # Light security check -- make sure redirect_to isn't garbage. | 66 | # Light security check -- make sure redirect_to isn't garbage. |
1002 | 65 | if not redirect_to or '//' in redirect_to or ' ' in redirect_to: | 67 | is_valid = True |
1003 | 68 | if not redirect_to or ' ' in redirect_to: | ||
1004 | 69 | is_valid = False | ||
1005 | 70 | elif '//' in redirect_to: | ||
1006 | 71 | # Allow the redirect URL to be external if it's a permitted domain | ||
1007 | 72 | allowed_domains = getattr(settings, | ||
1008 | 73 | "ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS", []) | ||
1009 | 74 | s, netloc, p, q, f = urlsplit(redirect_to) | ||
1010 | 75 | # allow it if netloc is blank or if the domain is allowed | ||
1011 | 76 | if netloc: | ||
1012 | 77 | # a domain was specified. Is it an allowed domain? | ||
1013 | 78 | if netloc.find(":") != -1: | ||
1014 | 79 | netloc, _ = netloc.split(":", 1) | ||
1015 | 80 | if netloc not in allowed_domains: | ||
1016 | 81 | is_valid = False | ||
1017 | 82 | |||
1018 | 83 | # If the return_to URL is not valid, use the default. | ||
1019 | 84 | if not is_valid: | ||
1020 | 66 | redirect_to = settings.LOGIN_REDIRECT_URL | 85 | redirect_to = settings.LOGIN_REDIRECT_URL |
1021 | 86 | |||
1022 | 67 | return redirect_to | 87 | return redirect_to |
1023 | 68 | 88 | ||
1024 | 69 | 89 | ||
1025 | @@ -148,7 +168,16 @@ | |||
1026 | 148 | sreg.SRegRequest(optional=['email', 'fullname', 'nickname'])) | 168 | sreg.SRegRequest(optional=['email', 'fullname', 'nickname'])) |
1027 | 149 | 169 | ||
1028 | 150 | # Request team info | 170 | # Request team info |
1029 | 171 | teams_mapping_auto = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False) | ||
1030 | 172 | teams_mapping_auto_blacklist = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', []) | ||
1031 | 151 | launchpad_teams = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) | 173 | launchpad_teams = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) |
1032 | 174 | if teams_mapping_auto: | ||
1033 | 175 | #ignore launchpad teams. use all django-groups | ||
1034 | 176 | launchpad_teams = dict() | ||
1035 | 177 | all_groups = Group.objects.exclude(name__in=teams_mapping_auto_blacklist) | ||
1036 | 178 | for group in all_groups: | ||
1037 | 179 | launchpad_teams[group.name] = group.name | ||
1038 | 180 | |||
1039 | 152 | if launchpad_teams: | 181 | if launchpad_teams: |
1040 | 153 | openid_request.addExtension(teams.TeamsRequest(launchpad_teams.keys())) | 182 | openid_request.addExtension(teams.TeamsRequest(launchpad_teams.keys())) |
1041 | 154 | 183 | ||
1042 | 155 | 184 | ||
1043 | === modified file 'example_consumer/settings.py' | |||
1044 | --- example_consumer/settings.py 2009-04-08 15:07:49 +0000 | |||
1045 | +++ example_consumer/settings.py 2010-02-05 06:33:16 +0000 | |||
1046 | @@ -125,5 +125,8 @@ | |||
1047 | 125 | OPENID_SSO_SERVER_URL = 'https://login.launchpad.net/' | 125 | OPENID_SSO_SERVER_URL = 'https://login.launchpad.net/' |
1048 | 126 | 126 | ||
1049 | 127 | # Tell django.contrib.auth to use the OpenID signin URLs. | 127 | # Tell django.contrib.auth to use the OpenID signin URLs. |
1051 | 128 | LOGIN_URL = '/openid/login' | 128 | LOGIN_URL = '/openid/login/' |
1052 | 129 | LOGIN_REDIRECT_URL = '/' | 129 | LOGIN_REDIRECT_URL = '/' |
1053 | 130 | |||
1054 | 131 | # Should django_auth_openid be used to sign into the admin interface? | ||
1055 | 132 | OPENID_USE_AS_ADMIN_LOGIN = False | ||
1056 | 130 | 133 | ||
1057 | === modified file 'example_consumer/urls.py' | |||
1058 | --- example_consumer/urls.py 2009-04-08 15:07:49 +0000 | |||
1059 | +++ example_consumer/urls.py 2010-02-05 06:33:16 +0000 | |||
1060 | @@ -38,7 +38,7 @@ | |||
1061 | 38 | urlpatterns = patterns('', | 38 | urlpatterns = patterns('', |
1062 | 39 | (r'^$', views.index), | 39 | (r'^$', views.index), |
1063 | 40 | (r'^openid/', include('django_openid_auth.urls')), | 40 | (r'^openid/', include('django_openid_auth.urls')), |
1065 | 41 | (r'^logout$', 'django.contrib.auth.views.logout'), | 41 | (r'^logout/$', 'django.contrib.auth.views.logout'), |
1066 | 42 | (r'^private/$', views.require_authentication), | 42 | (r'^private/$', views.require_authentication), |
1067 | 43 | 43 | ||
1068 | 44 | (r'^admin/(.*)', admin.site.root), | 44 | (r'^admin/(.*)', admin.site.root), |
1069 | 45 | 45 | ||
1070 | === modified file 'setup.py' | |||
1071 | --- setup.py 2009-04-08 15:07:49 +0000 | |||
1072 | +++ setup.py 2010-02-05 06:33:16 +0000 | |||
1073 | @@ -43,17 +43,19 @@ | |||
1074 | 43 | 43 | ||
1075 | 44 | 44 | ||
1076 | 45 | description, long_description = __doc__.split('\n\n', 1) | 45 | description, long_description = __doc__.split('\n\n', 1) |
1077 | 46 | VERSION = '0.2' | ||
1078 | 46 | 47 | ||
1079 | 47 | setup( | 48 | setup( |
1080 | 48 | name='django-openid-auth', | 49 | name='django-openid-auth', |
1082 | 49 | version='0.1', | 50 | version=VERSION, |
1083 | 50 | author='Canonical Ltd', | 51 | author='Canonical Ltd', |
1084 | 51 | description=description, | 52 | description=description, |
1085 | 52 | long_description=long_description, | 53 | long_description=long_description, |
1086 | 53 | license='BSD', | 54 | license='BSD', |
1087 | 54 | platforms=['any'], | 55 | platforms=['any'], |
1088 | 55 | url='https://launchpad.net/django-openid-auth', | 56 | url='https://launchpad.net/django-openid-auth', |
1090 | 56 | download_url='https://launchpad.net/django-openid-auth/+download', | 57 | download_url=('http://launchpad.net/django-openid-auth/trunk/%s/+download' |
1091 | 58 | '/django-openid-auth-%s.tar.gz' % (VERSION, VERSION)), | ||
1092 | 57 | classifiers=[ | 59 | classifiers=[ |
1093 | 58 | 'Development Status :: 4 - Beta', | 60 | 'Development Status :: 4 - Beta', |
1094 | 59 | 'Environment :: Web Environment', | 61 | 'Environment :: Web Environment', |
1095 | @@ -73,4 +75,6 @@ | |||
1096 | 73 | package_data={ | 75 | package_data={ |
1097 | 74 | 'django_openid_auth': ['templates/openid/*.html'], | 76 | 'django_openid_auth': ['templates/openid/*.html'], |
1098 | 75 | }, | 77 | }, |
1099 | 78 | provides=['django_openid_auth'], | ||
1100 | 79 | requires=['django (>=1.0)', 'openid (>=2.2.0)'], | ||
1101 | 76 | ) | 80 | ) |
updating to the new upstream release, converting from CDBS to dh7, switching from python-central to python-support, converting to sourcepackage 3.0 (quilt).
Builds and installs ok, confirmed that the upgrade from 0.1 to 0.2 doesn't seem to leave any python-central garbage behind.