Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fix and Translation #3

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
27 changes: 22 additions & 5 deletions googleappsauth/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@
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


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)
Expand All @@ -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
Expand All @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions googleappsauth/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -52,6 +53,19 @@ 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

# nein, wir haben noch keinen User. Also den Login ueber
Expand Down
84 changes: 42 additions & 42 deletions googleappsauth/templates/googleappsauth/domains.html
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Bitte Google-Login-Domain auswaehlen!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body {
font-family: helvetica, arial, sans-serif;
font-size: 10pt;
}
h1 {
font-size: 12pt;
font-weight: normal;
line-height: 1.5em;
}
div#domains {
width: 300px;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
}
select {
margin-bottom: 15px;
font-size: 10pt;
}
input[type='submit'] {
font-size: 10pt;
}
</style>
</head>
<body>
<div id="domains">
<h1>Bitte w&auml;hlen Sie die Domain aus, <br/> &uuml;ber die Sie sich einloggen m&ouml;chten:</h1>
<form action="{{login_url}}" method="post">
<select name="domain" id="id_domain">
{% for domain in domains %}
<option value="{{domain}}">{{domain}}</option>
{% endfor %}
</select>
<br/>
<input type="submit" value="Login auf dieser Domain durchfuehren"/>
</form>
</div>
</body>
<head>
<title>Bitte Google-Login-Domain auswaehlen!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body {
font-family: helvetica, arial, sans-serif;
font-size: 10pt;
}
h1 {
font-size: 12pt;
font-weight: normal;
line-height: 1.5em;
}
div#domains {
width: 300px;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
}
select {
margin-bottom: 15px;
font-size: 10pt;
}
input[type='submit'] {
font-size: 10pt;
}
</style>
</head>
<body>
<div id="domains">
<h1>Please select the domain, <br/> which you want to log in:</h1>
<form action="{{login_url}}" method="post">
<select name="domain" id="id_domain">
{% for domain in domains %}
<option value="{{domain}}">{{domain}}</option>
{% endfor %}
</select>
<br/>
<input type="submit" value="Login to lead by this domain"/>
</form>
</div>
</body>
</html>
19 changes: 19 additions & 0 deletions googleappsauth/templates/googleappsauth/login_error.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<title>login-error</title>

</head>

<body>
You already loged in as different google app user
<br />
Please use valid email address!
<a href="http://www.google.com">Google.com</a>
</body>
</html>
127 changes: 73 additions & 54 deletions googleappsauth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,113 +17,132 @@
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)
_oauth_consumer_key = getattr(settings, 'GOOGLE_APPS_CONSUMER_KEY', None)
_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)

_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)
return HttpResponseRedirect(url)


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
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('.', '')

# 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)
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)
if not user:
# die Authentifizierung ist gescheitert
raise RuntimeError("Authentifizierungsproblem: %s|%s|%s" % (username, identifier, attributes))
djauth.login(request, user)
# 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']
# del request.session['redirect_url']
return HttpResponseRedirect(redirect_url)

domain = _is_valid_domain(googleappsauth.openid.get_email(request))

if domain:

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)
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 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 True
else:
return False