diff options
author | Magnus Hagander | 2012-08-17 13:51:35 +0000 |
---|---|---|
committer | Magnus Hagander | 2012-08-17 13:51:35 +0000 |
commit | 8f078f66c916943f94b508cc313f887ef9afbeeb (patch) | |
tree | 0923a1635321160a278ed290040788eb64455177 | |
parent | 040b27476030a7aa651c6f9ee1eb8ea8c7db22e8 (diff) |
Integrate with community login
-rw-r--r-- | pgmailmgr/auth.py | 128 | ||||
-rw-r--r-- | pgmailmgr/mailmgr/templates/home.html | 6 | ||||
-rw-r--r-- | pgmailmgr/urls.py | 5 |
3 files changed, 139 insertions, 0 deletions
diff --git a/pgmailmgr/auth.py b/pgmailmgr/auth.py new file mode 100644 index 0000000..c3118d5 --- /dev/null +++ b/pgmailmgr/auth.py @@ -0,0 +1,128 @@ +# +# Django module to support postgresql.org community authentication 2.0 +# +# The main location for this module is the pgweb git repository hosted +# on git.postgresql.org - look there for updates. +# +# To integrate with django, you need the following: +# * Make sure the view "login" from this module is used for login +# * Map an url somwehere (typicall /auth_receive/) to the auth_receive +# view. +# * In settings.py, set AUTHENTICATION_BACKENDS to point to the class +# AuthBackend in this module. +# * (And of course, register for a crypto key with the main authentication +# provider website) +# * If the application uses the django admin interface, the login screen +# has to be replaced with something similar to login.html in this +# directory (adjust urls, and name it admin/login.html in any template +# directory that's processed before the default django.contrib.admin) +# + +from django.http import HttpResponseRedirect +from django.contrib.auth.models import User +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth import login as django_login +from django.contrib.auth import logout as django_logout +from django.conf import settings + +import base64 +import urlparse +from urllib import quote_plus +from Crypto.Cipher import AES +import time + +class AuthBackend(ModelBackend): + # We declare a fake backend that always fails direct authentication - + # since we should never be using direct authentication in the first place! + def authenticate(self, username=None, password=None): + raise Exception("Direct authentication not supported") + + +#### +# Two regular django views to interact with the login system +#### + +# Handle login requests by sending them off to the main site +def login(request): + if request.GET.has_key('next'): + return HttpResponseRedirect("%s?su=%s" % ( + settings.PGAUTH_REDIRECT, + quote_plus(request.GET['next']), + )) + else: + return HttpResponseRedirect(settings.PGAUTH_REDIRECT) + +# Handle logout requests by logging out of this site and then +# redirecting to log out from the main site as well. +def logout(request): + if request.user.is_authenticated(): + django_logout(request) + return HttpResponseRedirect("%slogout/" % settings.PGAUTH_REDIRECT) + +# Receive an authentication response from the main website and try +# to log the user in. +def auth_receive(request): + if request.GET.has_key('s') and request.GET['s'] == "logout": + # This was a logout request + return HttpResponseRedirect('/') + + if not request.GET.has_key('i'): + raise Exception("Missing IV") + if not request.GET.has_key('d'): + raise Exception("Missing data!") + + # Set up an AES object and decrypt the data we received + decryptor = AES.new(base64.b64decode(settings.PGAUTH_KEY), + AES.MODE_CBC, + base64.b64decode(str(request.GET['i']), "-_")) + s = decryptor.decrypt(base64.b64decode(str(request.GET['d']), "-_")).rstrip(' ') + + # Now un-urlencode it + try: + data = urlparse.parse_qs(s, strict_parsing=True) + except ValueError, e: + raise Exception("Invalid encrypted data received.") + + # Check the timestamp in the authentication + if (int(data['t'][0]) < time.time() - 10): + raise Exception("Authentication token too old.") + + # Update the user record (if any) + try: + user = User.objects.get(username=data['u'][0]) + # User found, let's see if any important fields have changed + changed = False + if user.first_name != data['f'][0]: + user.first_name = data['f'][0] + changed = True + if user.last_name != data['l'][0]: + user.last_name = data['l'][0] + changed = True + if user.email != data['e'][0]: + user.email = data['e'][0] + changed= True + if changed: + user.save() + except User.DoesNotExist, e: + # User not found, create it! + user = User(username=data['u'][0], + first_name=data['f'][0], + last_name=data['l'][0], + email=data['e'][0], + password='setbypluginnotasha1', + ) + user.save() + + # Ok, we have a proper user record. Now tell django that + # we're authenticated so it persists it in the session. Before + # we do that, we have to annotate it with the backend information. + user.backend = "%s.%s" % (AuthBackend.__module__, AuthBackend.__name__) + django_login(request, user) + + # Finally, redirect the user + if data.has_key('su'): + return HttpResponseRedirect(data['su'][0]) + # No redirect specified, see if we have it in our settings + if hasattr(settings, 'PGAUTH_REDIRECT_SUCCESS'): + return HttpResponseRedirect(settings.PGAUTH_REDIRECT_SUCCESS) + raise Exception("Authentication successful, but don't know where to redirect!") diff --git a/pgmailmgr/mailmgr/templates/home.html b/pgmailmgr/mailmgr/templates/home.html index 514edd8..492b91d 100644 --- a/pgmailmgr/mailmgr/templates/home.html +++ b/pgmailmgr/mailmgr/templates/home.html @@ -47,5 +47,11 @@ </table> <a href="/https/git.postgresql.org/forwarder/add/">Add</a> new. +<br/> +<br/> +<a href="/https/git.postgresql.org/accounts/logout/">Log out</a><br/> +{% if user.is_superuser %} +<a href="/https/git.postgresql.org/admin/">View admin</a><br/> +{%endif%} </body> </html> diff --git a/pgmailmgr/urls.py b/pgmailmgr/urls.py index d4c3d29..bde17a8 100644 --- a/pgmailmgr/urls.py +++ b/pgmailmgr/urls.py @@ -9,6 +9,11 @@ urlpatterns = patterns('', url(r'^user/(\d+|add)/$', 'pgmailmgr.mailmgr.views.userform'), url(r'^forwarder/(\d+|add)/$', 'pgmailmgr.mailmgr.views.forwarderform'), + # Auth + url('^auth_receive/$', 'pgmailmgr.auth.auth_receive'), + url('^accounts/logout/$', 'pgmailmgr.auth.logout'), + url('^accounts/login/$', 'pgmailmgr.auth.login'), + # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)), ) |