Merge lp:~statik/ubuntu/lucid/python-django-openid-auth/new-upstream-version into lp:ubuntu/lucid/python-django-openid-auth

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
Reviewer Review Type Date Requested Status
Daniel Holbach Approve
Ubuntu branches Pending
Review via email: mp+18671@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Elliot Murphy (statik) wrote :

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.

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:

Revision history for this message
Daniel Holbach (dholbach) wrote :

Great work!

review: Approve

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

Subscribers

People subscribed via source and target branches

to all changes: