From a84594800b20abaabd3499ccf5dc91ae2e2aa0d3 Mon Sep 17 00:00:00 2001 From: mohammad taleb Date: Wed, 7 Dec 2011 19:35:17 -0500 Subject: [PATCH 1/3] Add multiple domain --- googleappsauth/backends.py | 27 ++++- googleappsauth/middleware.py | 3 + .../templates/googleappsauth/domains.html | 84 +++++++------- googleappsauth/views.py | 109 ++++++++++-------- 4 files changed, 130 insertions(+), 93 deletions(-) diff --git a/googleappsauth/backends.py b/googleappsauth/backends.py index f4f86b6..3445e63 100644 --- a/googleappsauth/backends.py +++ b/googleappsauth/backends.py @@ -11,7 +11,7 @@ from django.conf import settings from django.contrib.admin.models import LogEntry, ADDITION from django.contrib.auth.backends import ModelBackend -from django.contrib.auth.models import User, SiteProfileNotAvailable +from django.contrib.auth.models import User, Group, SiteProfileNotAvailable from django.contrib.contenttypes.models import ContentType from django.db import models import re @@ -19,11 +19,12 @@ class GoogleAuthBackend(ModelBackend): def authenticate(self, identifier=None, attributes=None): - # da wir von Google keinen Benutzernamen bekommen versuchen wir zuerst, - # den ersten Teil der Emailadresse zu nehmen. Wenn wir keine Email haben - # dann bleibt nur der OpenID-Identifier als Benutzername + # Because we get a user name of Google we first try + # To accept the first part of the email address. If we do not have email + # Then only remains of the OpenID identifier as the username email = attributes.get('email', '') - username = attributes.get('email', identifier).split('@')[0].replace('.', '') + username = email + users = User.objects.filter(username=username) if len(users) > 1: raise RuntimeError("duplicate user %s" % email) @@ -37,6 +38,7 @@ def authenticate(self, identifier=None, attributes=None): LogEntry.objects.log_action(1, ContentType.objects.get_for_model(User).id, user.id, unicode(User), ADDITION, "durch googleauth automatisch erzeugt") + else: user = users[0] # jetzt aktualisieren wir die Attribute des Benutzers mit den neuesten @@ -63,6 +65,21 @@ def authenticate(self, identifier=None, attributes=None): # das war's, Benutzer zurueckliefern, damit ist Login geglueckt return user + def set_group(self, username): + domain = email.split('@')[1] + + try: + group = Group.object.get(name = domain) + except DoesNotExist: + group = Group(name = domain) + group.save() + + users = User.objects.filter(username=username) + users.groups.add(group) + + + + def get_user(self, user_id): try: return User.objects.get(pk=user_id) diff --git a/googleappsauth/middleware.py b/googleappsauth/middleware.py index bb2e720..9d17751 100644 --- a/googleappsauth/middleware.py +++ b/googleappsauth/middleware.py @@ -54,6 +54,9 @@ def process_request(self, request): if request.user.is_authenticated(): return + print "path:: %s" % path + print "in0:: %s?%s" % (path, request.META.get('QUERY_STRING', '')) + # nein, wir haben noch keinen User. Also den Login ueber # Google Apps OpenID/OAuth starten und Parameter in Session speichern return googleappsauth.views.login(request, diff --git a/googleappsauth/templates/googleappsauth/domains.html b/googleappsauth/templates/googleappsauth/domains.html index 801c1ef..ebc4446 100644 --- a/googleappsauth/templates/googleappsauth/domains.html +++ b/googleappsauth/templates/googleappsauth/domains.html @@ -1,45 +1,45 @@ - - Bitte Google-Login-Domain auswaehlen! - - - - -
-

Bitte wählen Sie die Domain aus,
über die Sie sich einloggen möchten:

-
- -
- -
-
- + + Bitte Google-Login-Domain auswaehlen! + + + + +
+

Please select the domain,
which you want to log in:

+
+ +
+ +
+
+ diff --git a/googleappsauth/views.py b/googleappsauth/views.py index ceb5327..a4a3c82 100644 --- a/googleappsauth/views.py +++ b/googleappsauth/views.py @@ -17,7 +17,6 @@ import django.contrib.auth as djauth import googleappsauth.openid - _google_apps_domain = getattr(settings, 'GOOGLE_APPS_DOMAIN', None) _google_openid_endpoint = getattr(settings, 'GOOGLE_OPENID_ENDPOINT', None) _google_openid_realm = getattr(settings, 'GOOGLE_OPENID_REALM', None) @@ -27,56 +26,55 @@ _login_url = getattr(settings, 'LOGIN_URL', None) - def login(request, redirect_field_name=REDIRECT_FIELD_NAME, redirect_url=None): - # wenn wir ueber einen Post-Request in die Method gekommen sind gehen - # wir davon aus, das der Benutzer vorher eine Domain fuer den Login - # ausgewaehlt hat. Ansonsten ist's ein Fehler. + login_domain = None + # If we go over a post-request came in the Method + # We assume that the user previously for domain login + # Has selected. Otherwise, s is a mistake. if request.method == 'POST': - callback_url = request.session['callback_url'] login_domain = request.POST.get('domain') if not login_domain: raise Http404('invalid or missing login domain!') - # ansonsten ist das ein Login-Versuch, also bestimmen wir zuerst, wohin - # nach erfolgtem Login in die App umgeleitet werden soll + # Otherwise it's a login attempt, so we first determine where + # After a successful login will be redirected to the app + # If we have more than one configured Apps domain and yet + # Was chosen not out of the log-domain POST request then + # We now show first a selection box for the + # Desired login to domain. + else: - login_domain = None - if not redirect_url: - redirect_url = request.REQUEST.get(redirect_field_name) - if not redirect_url: - redirect_url = getattr(settings, 'LOGIN_REDIRECT_URL', '/') - request.session['redirect_url'] = redirect_url - - # jetzt bauen wir uns die URL fuer den Callback zusammen, unter - # dem wir von Google aufgerufen werden moechten nach dem Login - callback_url = request.build_absolute_uri(reverse(callback)) - request.session['callback_url'] = callback_url - - # wenn wir mehr als eine Apps-Domain konfiguriert haben und noch - # keine Login-Domain aus dem POST-Request ausgewaehlt wurde dann - # dann zeigen wir jetzt zuerst noch eine Auswahlbox fuer die - # gewuenschte Login-Domain an. - if not login_domain: if type(_google_apps_domain) == types.ListType: return render_to_response('googleappsauth/domains.html', - { 'login_url': _login_url, 'domains': _google_apps_domain }) + { 'login_url': request.get_full_path(), 'domains': _google_apps_domain}) else: login_domain = _google_apps_domain - # jetzt haben wir ganz sicher eine Domain, ueber die wir uns einloggen - # sollen. Um die Kompatibilitaet mit alten Versionen (in denen der Settings- - # Parameter 'GOOGLE_OPENID_ENDPOINT' bereits die vollstaendige Endpoint-URL - # inkl. Login-Domain enthalten hat) nicht zu brechen fangen wir hier moegliche - # Typfehler (eben wenn der Parameter kein passendes '%s' enthaelt) ab. + if not redirect_url: + redirect_url = request.REQUEST.get(redirect_field_name) + if not redirect_url: + redirect_url = getattr(settings, 'LOGIN_REDIRECT_URL', '/') + + request.session['redirect_url'] = redirect_url + + # Now we build us the URL for the callback together, under + # We want to be called from Google after login + callback_url = request.build_absolute_uri(reverse(callback)) + request.session['callback_url'] = callback_url + + # Now we have certainly a domain over which we logTo + #. To provide compatibility with older versions (where the Settings + # Parameters 'GOOGLE_OPENID_ENDPOINT' already full endpoint URL + # Include has domain including login) does not break, we catch are possible + # Type of error (if the parameter is not precisely matching '% s' contains) from. openid_endpoint = _google_openid_endpoint try: openid_endpoint = openid_endpoint % login_domain except TypeError: pass - # und schliesslich konstruieren wir darauf die Google-OpenID- - # Endpoint-URL, auf die wir dann den Benutzer umleiten + # And finally we build out the Google OpenID + # Endpoint URL to which we then redirect the user url = googleappsauth.openid.build_login_url( openid_endpoint, _google_openid_realm, callback_url, _oauth_consumer_key, _google_api_scope) @@ -84,34 +82,42 @@ def login(request, redirect_field_name=REDIRECT_FIELD_NAME, redirect_url=None): def callback(request): - # haben wir einen erfolgreichen Login? Wenn nicht gehen wir - # sofort zurueck, ohne einen Benutzer einzuloggen + # We have a successful login? If we do not go + # Back immediately, without a user login + print 'in callback' callback_url = request.session.get('callback_url', '/') identifier = googleappsauth.openid.parse_login_response(request, callback_url) if not identifier: # TODO: was ist hier los? return HttpResponseRedirect('/') - # jetzt holen wir uns die restlichen Daten aus dem Login + # Now we get the remaining data from the login attributes = { 'email': googleappsauth.openid.get_email(request), 'language': googleappsauth.openid.get_language(request), 'firstname': googleappsauth.openid.get_firstname(request), 'lastname': googleappsauth.openid.get_lastname(request)} - - # wenn wir ein OAuth request token bekommen haben machen wir - # daraus jetzt noch flott ein access token + + + # If we do get an OAuth request token we + # Now it still afloat an access token request_token = googleappsauth.openid.get_oauth_request_token(request) #if request_token: # attributes['access_token'] = None # raise Exception('access token handling not yet implemented!') - # Usernames are based on E-Mail Addresses which are unique. - username = attributes.get('email', identifier).split('@')[0].replace('.', '') + # Finally, we report the user and its attributes on + # Of Django auth system, then back to the actual app + redirect_url = request.session['redirect_url'] - # schliesslich melden wir den Benutzer mit seinen Attributen am - # Auth-System von Django an, dann zurueck zur eigentlichen App - user = djauth.authenticate(identifier=username, attributes=attributes) + domain = _is_valid_domain(googleappsauth.openid.get_email(request)) + if domain: + request.session['loged_in_domain'] = domain + else: + _clear_session_data() + return HttpResponseRedirect(redirect_url) + + user = djauth.authenticate(attributes=attributes) if not user: # For some reason I do not fully understand we get back a "None"" coasionalty - retry. user = djauth.authenticate(identifier=username, attributes=attributes) @@ -119,11 +125,22 @@ def callback(request): # die Authentifizierung ist gescheitert raise RuntimeError("Authentifizierungsproblem: %s|%s|%s" % (username, identifier, attributes)) djauth.login(request, user) - redirect_url = request.session['redirect_url'] + # del request.session['redirect_url'] return HttpResponseRedirect(redirect_url) - def logout(request): djauth.logout(request) return HttpResponseRedirect('https://www.google.com/a/%s/Logout' % _google_apps_domain) + +def _clear_session_data(): + del request.session['redirect_url'] + del request.session['callback_url'] + del request.session['redirect_url'] + +def _is_valid_domain(email): + domain = email.split("@")[1] + if domain in _google_apps_domain: + return domain + else: + return False \ No newline at end of file From 1722878be2928597ebbeaece357ccf38c3e952ee Mon Sep 17 00:00:00 2001 From: mohammad taleb Date: Thu, 8 Dec 2011 18:03:33 -0500 Subject: [PATCH 2/3] Update documentation --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 03cc4aa..7407b32 100644 --- a/README.rst +++ b/README.rst @@ -18,6 +18,7 @@ To use googleappsauth, configuration in `settings.py` should look like this:: GOOGLE_APPS_CONSUMER_SECRET = '*sekret*' # domain where your application is running GOOGLE_OPENID_REALM = 'http://*.hudora.biz/' + GOOGLE_OPENID_ENDPOINT = 'https://www.google.com/accounts/o8/ud' If you want to choose from a list of Google apps domains on a login-by-login basis you can configure an array of apps domains:: From 65ef4fff3f0c08e764245aa22407645d5076b12c Mon Sep 17 00:00:00 2001 From: mohammad taleb Date: Thu, 15 Dec 2011 16:00:46 -0500 Subject: [PATCH 3/3] Add login time out --- googleappsauth/middleware.py | 17 +++++-- .../templates/googleappsauth/login_error.html | 19 ++++++++ googleappsauth/views.py | 46 ++++++++++--------- 3 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 googleappsauth/templates/googleappsauth/login_error.html diff --git a/googleappsauth/middleware.py b/googleappsauth/middleware.py index 9d17751..1113025 100644 --- a/googleappsauth/middleware.py +++ b/googleappsauth/middleware.py @@ -6,6 +6,7 @@ Created by Axel Schlüter on 2009-12 Copyright (c) 2009, 2010 HUDORA GmbH. All rights reserved. """ +from datetime import datetime, timedelta from django.conf import settings from django.contrib.auth.models import User, SiteProfileNotAvailable @@ -52,11 +53,21 @@ def process_request(self, request): # ok, die Seite muss auth'd werden. Haben wir vielleicht # schon einen geauth'd User in der aktuellen Session? if request.user.is_authenticated(): + try: + print timedelta( 0, settings.AUTO_LOGOUT_DELAY * 60, 0) + print datetime.now() - request.session['last_touch'] + if datetime.now() - request.session['last_touch'] > timedelta( 0, settings.AUTO_LOGOUT_DELAY * 60, 0): + print 'Time out!' + djauth.logout(request) + del request.session['last_touch'] + return HttpResponseRedirect(redirect_url) + except KeyError: + pass + + request.session['last_touch'] = datetime.now() + return - print "path:: %s" % path - print "in0:: %s?%s" % (path, request.META.get('QUERY_STRING', '')) - # nein, wir haben noch keinen User. Also den Login ueber # Google Apps OpenID/OAuth starten und Parameter in Session speichern return googleappsauth.views.login(request, diff --git a/googleappsauth/templates/googleappsauth/login_error.html b/googleappsauth/templates/googleappsauth/login_error.html new file mode 100644 index 0000000..5ce4da7 --- /dev/null +++ b/googleappsauth/templates/googleappsauth/login_error.html @@ -0,0 +1,19 @@ + + + + + + + + login-error + + + + +You already loged in as different google app user +
+Please use valid email address! +Google.com + + diff --git a/googleappsauth/views.py b/googleappsauth/views.py index a4a3c82..6349491 100644 --- a/googleappsauth/views.py +++ b/googleappsauth/views.py @@ -24,6 +24,7 @@ _oauth_consumer_secret = getattr(settings, 'GOOGLE_APPS_CONSUMER_SECRET', None) _google_api_scope = getattr(settings, 'GOOGLE_API_SCOPE', None) + _login_url = getattr(settings, 'LOGIN_URL', None) def login(request, redirect_field_name=REDIRECT_FIELD_NAME, redirect_url=None): @@ -84,7 +85,6 @@ def login(request, redirect_field_name=REDIRECT_FIELD_NAME, redirect_url=None): def callback(request): # We have a successful login? If we do not go # Back immediately, without a user login - print 'in callback' callback_url = request.session.get('callback_url', '/') identifier = googleappsauth.openid.parse_login_response(request, callback_url) if not identifier: @@ -111,36 +111,38 @@ def callback(request): redirect_url = request.session['redirect_url'] domain = _is_valid_domain(googleappsauth.openid.get_email(request)) + if domain: - request.session['loged_in_domain'] = domain - else: - _clear_session_data() - return HttpResponseRedirect(redirect_url) - - user = djauth.authenticate(attributes=attributes) - if not user: - # For some reason I do not fully understand we get back a "None"" coasionalty - retry. - user = djauth.authenticate(identifier=username, attributes=attributes) + + user = djauth.authenticate(attributes=attributes) if not user: - # die Authentifizierung ist gescheitert - raise RuntimeError("Authentifizierungsproblem: %s|%s|%s" % (username, identifier, attributes)) - djauth.login(request, user) - - # del request.session['redirect_url'] - return HttpResponseRedirect(redirect_url) + # For some reason I do not fully understand we get back a "None"" coasionalty - retry. + user = djauth.authenticate(identifier=username, attributes=attributes) + if not user: + # die Authentifizierung ist gescheitert + raise RuntimeError("Authentifizierungsproblem: %s|%s|%s" % (username, identifier, attributes)) + + djauth.login(request, user) + request.session.set_expiry(300) + return HttpResponseRedirect(redirect_url) + + else: + return HttpResponseRedirect("/error-googleappsauth") + def logout(request): djauth.logout(request) + del request.session['last_touch'] + del request.session['redirect_url'] return HttpResponseRedirect('https://www.google.com/a/%s/Logout' % _google_apps_domain) -def _clear_session_data(): - del request.session['redirect_url'] - del request.session['callback_url'] - del request.session['redirect_url'] - +def login_error(request): + return render_to_response('googleappsauth/login_error.html') + def _is_valid_domain(email): + print email domain = email.split("@")[1] if domain in _google_apps_domain: - return domain + return True else: return False \ No newline at end of file