summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Hagander2012-08-17 13:51:35 +0000
committerMagnus Hagander2012-08-17 13:51:35 +0000
commit8f078f66c916943f94b508cc313f887ef9afbeeb (patch)
tree0923a1635321160a278ed290040788eb64455177
parent040b27476030a7aa651c6f9ee1eb8ea8c7db22e8 (diff)
Integrate with community login
-rw-r--r--pgmailmgr/auth.py128
-rw-r--r--pgmailmgr/mailmgr/templates/home.html6
-rw-r--r--pgmailmgr/urls.py5
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)),
)