[PATCH] Make it possible to configure Patchwork to delegate user authentication to an OpenID provider.

Guilherme Salgado guilherme.salgado at linaro.org
Fri Feb 18 06:53:17 EST 2011


The default still is to authenticate against the local user database

Also, instead using RegistrationForm's profile_callback to register
UserProfiles we now use a signal handler for post_save on User, so that
a UserProfile is always created, regardless of how the new User is created.

Signed-off-by: Guilherme Salgado <guilherme.salgado at linaro.org>
---

I think this would be a nice addition and the change itself is not very
intrusive.

There's just one gotcha which I haven't dealt with yet. The 'register' link
is still shown at the top right when the user is not logged in, but it doesn't
make sense when using OpenID. Maybe one alternative would be to have just the
'login' link there and provide a link to /accounts/register from
/accounts/login?

 apps/patchwork/context_processors.py |    6 +++---
 apps/patchwork/forms.py              |    8 +++++---
 apps/patchwork/models.py             |   11 +++++++++--
 apps/patchwork/tests/utils.py        |    4 ----
 apps/patchwork/utils.py              |    5 -----
 apps/settings.py                     |   16 +++++++++++++++-
 apps/urls.py                         |    5 ++---
 docs/INSTALL                         |   15 +++++++++++++++
 templates/base.html                  |    2 +-
 9 files changed, 50 insertions(+), 22 deletions(-)

diff --git a/apps/patchwork/context_processors.py b/apps/patchwork/context_processors.py
index f4ab5a9..b458eef 100644
--- a/apps/patchwork/context_processors.py
+++ b/apps/patchwork/context_processors.py
@@ -17,9 +17,9 @@
 # along with Patchwork; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
+from django.conf import settings
 
 from patchwork.models import Bundle
-from patchwork.utils import order_map, get_order
 
 def bundle(request):
     user = request.user
@@ -28,5 +28,5 @@ def bundle(request):
     return {'bundles': Bundle.objects.filter(owner = user)}
 
 
-def patchlists(request):
-
+def login_url(request):
+    return dict(login_url=settings.LOGIN_URL)
diff --git a/apps/patchwork/forms.py b/apps/patchwork/forms.py
index 1c5aeef..72c2c42 100644
--- a/apps/patchwork/forms.py
+++ b/apps/patchwork/forms.py
@@ -45,9 +45,11 @@ class RegistrationForm(RegistrationFormUniqueEmail):
         user.last_name = self.cleaned_data.get('last_name', '')
         user.save()
 
-	# saving the userprofile causes the firstname/lastname to propagate
-	# to the person objects.
-	user.get_profile().save()
+        # XXX: I think the code below is no longer needed as the signal
+        # handler responsible for creating the UserProfile already saves it.
+        # saving the userprofile causes the firstname/lastname to propagate
+        # to the person objects.
+        user.get_profile().save()
 
         return user
 
diff --git a/apps/patchwork/models.py b/apps/patchwork/models.py
index 6842622..3ee007f 100644
--- a/apps/patchwork/models.py
+++ b/apps/patchwork/models.py
@@ -18,6 +18,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from django.db import models
+from django.db.models.signals import post_save
 from django.contrib.auth.models import User
 from django.core.urlresolvers import reverse
 from django.contrib.sites.models import Site
@@ -126,8 +127,8 @@ class UserProfile(models.Model):
             person.save()
         else:
             for person in people:
-                 person.link_to_user(self.user)
-                 person.save()
+                person.link_to_user(self.user)
+                person.save()
 
     def __str__(self):
         return self.name()
@@ -400,3 +401,9 @@ class UserPersonConfirmation(models.Model):
         super(UserPersonConfirmation, self).save()
 
 
+def register_userprofile(sender, **kwargs):
+    if kwargs['created']:
+        UserProfile(user=kwargs['instance']).save()
+
+
+post_save.connect(register_userprofile, User)
diff --git a/apps/patchwork/tests/utils.py b/apps/patchwork/tests/utils.py
index a85e168..819e5b9 100644
--- a/apps/patchwork/tests/utils.py
+++ b/apps/patchwork/tests/utils.py
@@ -59,10 +59,6 @@ def create_user():
 
     user = User.objects.create_user(userid, email, userid)
     user.save()
-
-    profile = UserProfile(user = user)
-    profile.save()
-
     return user
 
 def create_maintainer(project):
diff --git a/apps/patchwork/utils.py b/apps/patchwork/utils.py
index fa26aef..ba019e6 100644
--- a/apps/patchwork/utils.py
+++ b/apps/patchwork/utils.py
@@ -200,8 +200,3 @@ def set_patches(user, project, action, data, patches, context):
         context.add_message(str)
 
     return (errors, form)
-
-def userprofile_register_callback(user):
-    profile = UserProfile(user = user)
-    profile.save()
-
diff --git a/apps/settings.py b/apps/settings.py
index 68837b3..32886de 100644
--- a/apps/settings.py
+++ b/apps/settings.py
@@ -69,6 +69,12 @@ ROOT_URLCONF = 'apps.urls'
 
 LOGIN_URL = '/accounts/login'
 LOGIN_REDIRECT_URL = '/user/'
+# If you want to make your Patchwork instance an OpenID relying party, you
+# just need to uncomment the lines below.
+# OPENID_CREATE_USERS = True
+# OPENID_UPDATE_DETAILS_FROM_SREG = True
+# LOGIN_URL = '/openid/login/'
+# OPENID_SSO_SERVER_URL = 'https://login.launchpad.net/'
 
 TEMPLATE_DIRS = (
     # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
@@ -80,7 +86,14 @@ TEMPLATE_CONTEXT_PROCESSORS = (
     "django.core.context_processors.auth",
     "django.core.context_processors.debug",
     "django.core.context_processors.i18n",
-    "django.core.context_processors.media")
+    "django.core.context_processors.media",
+    "patchwork.context_processors.login_url",
+    )
+
+AUTHENTICATION_BACKENDS = (
+    'django_openid_auth.auth.OpenIDBackend',
+    'django.contrib.auth.backends.ModelBackend',
+)
 
 AUTH_PROFILE_MODULE = "patchwork.userprofile"
 
@@ -90,6 +103,7 @@ INSTALLED_APPS = (
     'django.contrib.sessions',
     'django.contrib.sites',
     'django.contrib.admin',
+    'django_openid_auth',
     'patchwork',
     'registration',
 )
diff --git a/apps/urls.py b/apps/urls.py
index 5c4ac57..de0769e 100644
--- a/apps/urls.py
+++ b/apps/urls.py
@@ -23,17 +23,16 @@ from patchwork.admin import admin_site
 
 from registration.views import register
 from patchwork.forms import RegistrationForm
-from patchwork.utils import userprofile_register_callback
 
 urlpatterns = patterns('',
     # Example:
+    (r'^openid/', include('django_openid_auth.urls')),
     (r'^', include('patchwork.urls')),
 
     # override the default registration form
     url(r'^accounts/register/$',
         register,
-        {'form_class': RegistrationForm,
-         'profile_callback': userprofile_register_callback},
+        {'form_class': RegistrationForm},
         name='registration_register'),
 
     (r'^accounts/', include('registration.urls')),
diff --git a/docs/INSTALL b/docs/INSTALL
index 57e8042..aac619f 100644
--- a/docs/INSTALL
+++ b/docs/INSTALL
@@ -92,6 +92,21 @@ in brackets):
          cd ../python
          ln -s ../lib/packages/django-registration/registration ./registration
 
+        Two other libraries we may use, in case you use OpenID for
+        authentication, are django-openid-auth and the Python OpenID library.
+        The former is named python-django-openid-auth in Debian/Ubuntu and the
+        latter python-openid, but if they're not available in your
+        distribution, you can follow the steps below to get them:
+
+         cd lib/packages
+         wget http://launchpad.net/django-openid-auth/trunk/0.3/+download/django-openid-auth-0.3.tar.gz
+         wget --no-check-certificate https://github.com/openid/python-openid/tarball/2.2.5 -O python-openid-2.2.5.tgz
+         tar zxvf django-openid-auth-0.3.tar.gz
+         tar zxvf python-openid-2.2.5.tgz
+         cd ../python
+         ln -s ../packages/django-openid-auth-0.3/django_openid_auth ./django_openid_auth
+         ln -s ../packages/openid-python-openid-b666238/openid ./openid
+
         We also use some Javascript libraries:
 
          cd lib/packages
diff --git a/templates/base.html b/templates/base.html
index ec0204d..365200e 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -28,7 +28,7 @@
      <a href="{% url patchwork.views.user.profile %}">profile</a> ::
      <a href="{% url auth_logout %}">logout</a>
 {% else %}
-     <a href="{% url auth_login %}">login</a>
+     <a href="{{ login_url }}">login</a>
      <br/>
      <a href="{% url registration_register %}">register</a>
      <br/>
-- 
1.7.1



More information about the Patchwork mailing list