Commit 1a9fd76c by Natalia

Fully test suite passing on djangos from 1.4 to 1.8.

parent 6f4e845e
./django MANIFEST
./MANIFEST build
./build dist
./dist db.sqlite3
./sqlite.db .tox
./.tox/
check: check:
PYTHONPATH=$(shell pwd) python example_consumer/manage.py test \ PYTHONPATH=$(shell pwd) python manage.py test --verbosity=2 django_openid_auth
--verbosity=2 django_openid_auth
run-example-consumer: run-example-consumer:
PYTHONPATH=$(shell pwd) python example_consumer/manage.py syncdb PYTHONPATH=$(shell pwd) python manage.py syncdb --migrate
PYTHONPATH=$(shell pwd) python example_consumer/manage.py runserver PYTHONPATH=$(shell pwd) python manage.py runserver
.PHONY: check run-example-consumer .PHONY: check run-example-consumer
...@@ -26,4 +26,3 @@ ...@@ -26,4 +26,3 @@
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
from urllib import urlencode
from urlparse import parse_qsl, urlparse
from django.conf import settings from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django_openid_auth.models import Nonce, Association, UserOpenID from django_openid_auth.models import Nonce, Association, UserOpenID
...@@ -69,22 +72,39 @@ class UserOpenIDAdmin(admin.ModelAdmin): ...@@ -69,22 +72,39 @@ class UserOpenIDAdmin(admin.ModelAdmin):
admin.site.register(UserOpenID, UserOpenIDAdmin) admin.site.register(UserOpenID, UserOpenIDAdmin)
# Support for allowing openid authentication for /admin (django.contrib.admin) # override a single time
if getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False): original_admin_login = None
from django.http import HttpResponseRedirect if original_admin_login is None:
from django_openid_auth import views original_admin_login = admin.sites.AdminSite.login
def _openid_login(self, request, error_message='', extra_context=None):
if request.user.is_authenticated(): from django.http import HttpResponseRedirect
if not request.user.is_staff: from django_openid_auth import views
return views.default_render_failure(
request, "User %s does not have admin access."
% request.user.username) def _openid_login(instance, request, error_message='', extra_context=None):
assert error_message, "Unknown Error: %s" % error_message # Support for allowing openid authentication for /admin
else: # (django.contrib.admin)
# Redirect to openid login path, if not getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False):
return HttpResponseRedirect( return original_admin_login(
settings.LOGIN_URL + "?next=" + request.get_full_path()) instance, request, extra_context=extra_context)
# Overide the standard admin login form. if not request.user.is_authenticated():
admin.sites.AdminSite.login = _openid_login # Redirect to openid login path,
_, _, path, _, query, _ = urlparse(request.get_full_path())
qs = dict(parse_qsl(query))
qs.setdefault('next', path)
return HttpResponseRedirect(
settings.LOGIN_URL + "?" + urlencode(qs))
if not request.user.is_staff:
return views.default_render_failure(
request, "User %s does not have admin/staff access."
% request.user.username)
# No error message was supplied
assert error_message, "Unknown Error: %s" % error_message
# Overide the standard admin login form.
admin.sites.AdminSite.login = _openid_login
...@@ -93,8 +93,9 @@ class OpenIDBackend: ...@@ -93,8 +93,9 @@ class OpenIDBackend:
if getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False): if getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False):
pape_response = pape.Response.fromSuccessResponse(openid_response) pape_response = pape.Response.fromSuccessResponse(openid_response)
if pape_response is None or \ key = pape.AUTH_MULTI_FACTOR_PHYSICAL
pape.AUTH_MULTI_FACTOR_PHYSICAL not in pape_response.auth_policies: if (pape_response is None or
key not in pape_response.auth_policies):
raise MissingPhysicalMultiFactor() raise MissingPhysicalMultiFactor()
teams_response = teams.TeamsResponse.fromSuccessResponse( teams_response = teams.TeamsResponse.fromSuccessResponse(
...@@ -194,12 +195,12 @@ class OpenIDBackend: ...@@ -194,12 +195,12 @@ class OpenIDBackend:
if nickname is None or nickname == '': if nickname is None or nickname == '':
raise MissingUsernameViolation() raise MissingUsernameViolation()
# If we don't have a nickname, and we're not being strict, use a default # If we don't have a nickname, and we're not being strict, use default
nickname = nickname or 'openiduser' nickname = nickname or 'openiduser'
# See if we already have this nickname assigned to a username # See if we already have this nickname assigned to a username
try: try:
user = User.objects.get(username__exact=nickname) User.objects.get(username__exact=nickname)
except User.DoesNotExist: except User.DoesNotExist:
# No conflict, we can use this nickname # No conflict, we can use this nickname
return nickname return nickname
...@@ -231,7 +232,6 @@ class OpenIDBackend: ...@@ -231,7 +232,6 @@ class OpenIDBackend:
# No user associated with this identity_url # No user associated with this identity_url
pass pass
if getattr(settings, 'OPENID_STRICT_USERNAMES', False): if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
if User.objects.filter(username__exact=nickname).count() > 0: if User.objects.filter(username__exact=nickname).count() > 0:
raise DuplicateUsernameViolation( raise DuplicateUsernameViolation(
...@@ -248,7 +248,7 @@ class OpenIDBackend: ...@@ -248,7 +248,7 @@ class OpenIDBackend:
if i > 1: if i > 1:
username += str(i) username += str(i)
try: try:
user = User.objects.get(username__exact=username) User.objects.get(username__exact=username)
except User.DoesNotExist: except User.DoesNotExist:
break break
i += 1 i += 1
...@@ -266,12 +266,12 @@ class OpenIDBackend: ...@@ -266,12 +266,12 @@ class OpenIDBackend:
"An attribute required for logging in was not " "An attribute required for logging in was not "
"returned ({0}).".format(required_attr)) "returned ({0}).".format(required_attr))
nickname = self._get_preferred_username(details['nickname'], nickname = self._get_preferred_username(
details['email']) details['nickname'], details['email'])
email = details['email'] or '' email = details['email'] or ''
username = self._get_available_username(nickname, username = self._get_available_username(
openid_response.identity_url) nickname, openid_response.identity_url)
user = User.objects.create_user(username, email, password=None) user = User.objects.create_user(username, email, password=None)
self.associate_openid(user, openid_response) self.associate_openid(user, openid_response)
...@@ -328,13 +328,16 @@ class OpenIDBackend: ...@@ -328,13 +328,16 @@ class OpenIDBackend:
user.save() user.save()
def get_teams_mapping(self): def get_teams_mapping(self):
teams_mapping_auto = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False) teams_mapping_auto = getattr(
teams_mapping_auto_blacklist = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', []) settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False)
teams_mapping_auto_blacklist = getattr(
settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', [])
teams_mapping = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) teams_mapping = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {})
if teams_mapping_auto: if teams_mapping_auto:
#ignore teams_mapping. use all django-groups # ignore teams_mapping. use all django-groups
teams_mapping = dict() teams_mapping = dict()
all_groups = Group.objects.exclude(name__in=teams_mapping_auto_blacklist) all_groups = Group.objects.exclude(
name__in=teams_mapping_auto_blacklist)
for group in all_groups: for group in all_groups:
teams_mapping[group.name] = group.name teams_mapping[group.name] = group.name
return teams_mapping return teams_mapping
...@@ -344,12 +347,12 @@ class OpenIDBackend: ...@@ -344,12 +347,12 @@ class OpenIDBackend:
if len(teams_mapping) == 0: if len(teams_mapping) == 0:
return return
current_groups = set(user.groups.filter( mapping = [
name__in=teams_mapping.values())) teams_mapping[lp_team] for lp_team in teams_response.is_member
desired_groups = set(Group.objects.filter( if lp_team in teams_mapping]
name__in=[teams_mapping[lp_team] current_groups = set(
for lp_team in teams_response.is_member user.groups.filter(name__in=teams_mapping.values()))
if lp_team in teams_mapping])) desired_groups = set(Group.objects.filter(name__in=mapping))
for group in current_groups - desired_groups: for group in current_groups - desired_groups:
user.groups.remove(group) user.groups.remove(group)
for group in desired_groups - current_groups: for group in desired_groups - current_groups:
......
...@@ -28,20 +28,25 @@ ...@@ -28,20 +28,25 @@
"""Exception classes thrown by OpenID Authentication and Validation.""" """Exception classes thrown by OpenID Authentication and Validation."""
class DjangoOpenIDException(Exception): class DjangoOpenIDException(Exception):
pass pass
class RequiredAttributeNotReturned(DjangoOpenIDException): class RequiredAttributeNotReturned(DjangoOpenIDException):
pass pass
class IdentityAlreadyClaimed(DjangoOpenIDException): class IdentityAlreadyClaimed(DjangoOpenIDException):
def __init__(self, message=None): def __init__(self, message=None):
if message is None: if message is None:
self.message = "Another user already exists for your selected OpenID" self.message = (
"Another user already exists for your selected OpenID")
else: else:
self.message = message self.message = message
class DuplicateUsernameViolation(DjangoOpenIDException): class DuplicateUsernameViolation(DjangoOpenIDException):
def __init__(self, message=None): def __init__(self, message=None):
...@@ -50,6 +55,7 @@ class DuplicateUsernameViolation(DjangoOpenIDException): ...@@ -50,6 +55,7 @@ class DuplicateUsernameViolation(DjangoOpenIDException):
else: else:
self.message = message self.message = message
class MissingUsernameViolation(DjangoOpenIDException): class MissingUsernameViolation(DjangoOpenIDException):
def __init__(self, message=None): def __init__(self, message=None):
...@@ -58,11 +64,12 @@ class MissingUsernameViolation(DjangoOpenIDException): ...@@ -58,11 +64,12 @@ class MissingUsernameViolation(DjangoOpenIDException):
else: else:
self.message = message self.message = message
class MissingPhysicalMultiFactor(DjangoOpenIDException): class MissingPhysicalMultiFactor(DjangoOpenIDException):
def __init__(self, message=None): def __init__(self, message=None):
if message is None: if message is None:
self.message = "Login requires physical multi-factor authentication." self.message = (
"Login requires physical multi-factor authentication.")
else: else:
self.message = message self.message = message
...@@ -49,6 +49,7 @@ def teams_new_unicode(self): ...@@ -49,6 +49,7 @@ def teams_new_unicode(self):
return "%s -> %s" % (name, ", ".join(group_teams)) return "%s -> %s" % (name, ", ".join(group_teams))
else: else:
return name return name
Group.unicode_before_teams = Group.__unicode__ Group.unicode_before_teams = Group.__unicode__
Group.__unicode__ = teams_new_unicode Group.__unicode__ = teams_new_unicode
...@@ -64,9 +65,11 @@ class UserChangeFormWithTeamRestriction(UserChangeForm): ...@@ -64,9 +65,11 @@ class UserChangeFormWithTeamRestriction(UserChangeForm):
user_groups = self.instance.groups.all() user_groups = self.instance.groups.all()
for group in data: for group in data:
if group.name in known_teams and group not in user_groups: if group.name in known_teams and group not in user_groups:
raise forms.ValidationError("""The group %s is mapped to an raise forms.ValidationError(
external team. You cannot assign it manually.""" % group.name) "The group %s is mapped to an external team. "
"You cannot assign it manually." % group.name)
return data return data
UserAdmin.form = UserChangeFormWithTeamRestriction UserAdmin.form = UserChangeFormWithTeamRestriction
...@@ -78,10 +81,7 @@ class OpenIDLoginForm(forms.Form): ...@@ -78,10 +81,7 @@ class OpenIDLoginForm(forms.Form):
def clean_openid_identifier(self): def clean_openid_identifier(self):
if 'openid_identifier' in self.cleaned_data: if 'openid_identifier' in self.cleaned_data:
openid_identifier = self.cleaned_data['openid_identifier'] openid_identifier = self.cleaned_data['openid_identifier']
if xri.identifierScheme(openid_identifier) == 'XRI' and getattr( if (xri.identifierScheme(openid_identifier) == 'XRI' and
settings, 'OPENID_DISALLOW_INAMES', False getattr(settings, 'OPENID_DISALLOW_INAMES', False)):
):
raise forms.ValidationError(_('i-names are not supported')) raise forms.ValidationError(_('i-names are not supported'))
return self.cleaned_data['openid_identifier'] return self.cleaned_data['openid_identifier']
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime from __future__ import unicode_literals
from south.db import db
from south.v2 import SchemaMigration from django.db import models, migrations
from django.db import models from django.conf import settings
class Migration(SchemaMigration): class Migration(migrations.Migration):
def forwards(self, orm): dependencies = [
# Adding model 'Nonce' migrations.swappable_dependency(settings.AUTH_USER_MODEL),
db.create_table(u'django_openid_auth_nonce', ( ]
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('server_url', self.gf('django.db.models.fields.CharField')(max_length=2047)), operations = [
('timestamp', self.gf('django.db.models.fields.IntegerField')()), migrations.CreateModel(
('salt', self.gf('django.db.models.fields.CharField')(max_length=40)), name='Association',
)) fields=[
db.send_create_signal(u'django_openid_auth', ['Nonce']) ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('server_url', models.TextField(max_length=2047)),
# Adding model 'Association' ('handle', models.CharField(max_length=255)),
db.create_table(u'django_openid_auth_association', ( ('secret', models.TextField(max_length=255)),
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('issued', models.IntegerField()),
('server_url', self.gf('django.db.models.fields.TextField')(max_length=2047)), ('lifetime', models.IntegerField()),
('handle', self.gf('django.db.models.fields.CharField')(max_length=255)), ('assoc_type', models.TextField(max_length=64)),
('secret', self.gf('django.db.models.fields.TextField')(max_length=255)), ],
('issued', self.gf('django.db.models.fields.IntegerField')()), options={
('lifetime', self.gf('django.db.models.fields.IntegerField')()), },
('assoc_type', self.gf('django.db.models.fields.TextField')(max_length=64)), bases=(models.Model,),
)) ),
db.send_create_signal(u'django_openid_auth', ['Association']) migrations.CreateModel(
name='Nonce',
# Adding model 'UserOpenID' fields=[
db.create_table(u'django_openid_auth_useropenid', ( ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('server_url', models.CharField(max_length=2047)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), ('timestamp', models.IntegerField()),
('claimed_id', self.gf('django.db.models.fields.TextField')(unique=True, max_length=2047)), ('salt', models.CharField(max_length=40)),
('display_id', self.gf('django.db.models.fields.TextField')(max_length=2047)), ],
)) options={
db.send_create_signal(u'django_openid_auth', ['UserOpenID']) },
bases=(models.Model,),
),
def backwards(self, orm): migrations.CreateModel(
# Deleting model 'Nonce' name='UserOpenID',
db.delete_table(u'django_openid_auth_nonce') fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
# Deleting model 'Association' ('claimed_id', models.TextField(unique=True, max_length=2047)),
db.delete_table(u'django_openid_auth_association') ('display_id', models.TextField(max_length=2047)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
# Deleting model 'UserOpenID' ],
db.delete_table(u'django_openid_auth_useropenid') options={
'permissions': (('account_verified', 'The OpenID has been verified'),),
},
models = { bases=(models.Model,),
u'auth.group': { ),
'Meta': {'object_name': 'Group'}, ]
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'django_openid_auth.association': {
'Meta': {'object_name': 'Association'},
'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'issued': ('django.db.models.fields.IntegerField', [], {}),
'lifetime': ('django.db.models.fields.IntegerField', [], {}),
'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
},
u'django_openid_auth.nonce': {
'Meta': {'object_name': 'Nonce'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'salt': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '2047'}),
'timestamp': ('django.db.models.fields.IntegerField', [], {})
},
u'django_openid_auth.useropenid': {
'Meta': {'object_name': 'UserOpenID'},
'claimed_id': ('django.db.models.fields.TextField', [], {'unique': 'True', 'max_length': '2047'}),
'display_id': ('django.db.models.fields.TextField', [], {'max_length': '2047'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
}
}
complete_apps = ['django_openid_auth']
\ No newline at end of file
...@@ -46,7 +46,7 @@ class Nonce(models.Model): ...@@ -46,7 +46,7 @@ class Nonce(models.Model):
class Association(models.Model): class Association(models.Model):
server_url = models.TextField(max_length=2047) server_url = models.TextField(max_length=2047)
handle = models.CharField(max_length=255) handle = models.CharField(max_length=255)
secret = models.TextField(max_length=255) # Stored base64 encoded secret = models.TextField(max_length=255) # Stored base64 encoded
issued = models.IntegerField() issued = models.IntegerField()
lifetime = models.IntegerField() lifetime = models.IntegerField()
assoc_type = models.TextField(max_length=64) assoc_type = models.TextField(max_length=64)
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Nonce'
db.create_table(u'django_openid_auth_nonce', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('server_url', self.gf('django.db.models.fields.CharField')(max_length=2047)),
('timestamp', self.gf('django.db.models.fields.IntegerField')()),
('salt', self.gf('django.db.models.fields.CharField')(max_length=40)),
))
db.send_create_signal(u'django_openid_auth', ['Nonce'])
# Adding model 'Association'
db.create_table(u'django_openid_auth_association', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('server_url', self.gf('django.db.models.fields.TextField')(max_length=2047)),
('handle', self.gf('django.db.models.fields.CharField')(max_length=255)),
('secret', self.gf('django.db.models.fields.TextField')(max_length=255)),
('issued', self.gf('django.db.models.fields.IntegerField')()),
('lifetime', self.gf('django.db.models.fields.IntegerField')()),
('assoc_type', self.gf('django.db.models.fields.TextField')(max_length=64)),
))
db.send_create_signal(u'django_openid_auth', ['Association'])
# Adding model 'UserOpenID'
db.create_table(u'django_openid_auth_useropenid', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
('claimed_id', self.gf('django.db.models.fields.TextField')(unique=True, max_length=2047)),
('display_id', self.gf('django.db.models.fields.TextField')(max_length=2047)),
))
db.send_create_signal(u'django_openid_auth', ['UserOpenID'])
def backwards(self, orm):
# Deleting model 'Nonce'
db.delete_table(u'django_openid_auth_nonce')
# Deleting model 'Association'
db.delete_table(u'django_openid_auth_association')
# Deleting model 'UserOpenID'
db.delete_table(u'django_openid_auth_useropenid')
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'django_openid_auth.association': {
'Meta': {'object_name': 'Association'},
'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'issued': ('django.db.models.fields.IntegerField', [], {}),
'lifetime': ('django.db.models.fields.IntegerField', [], {}),
'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
},
u'django_openid_auth.nonce': {
'Meta': {'object_name': 'Nonce'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'salt': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '2047'}),
'timestamp': ('django.db.models.fields.IntegerField', [], {})
},
u'django_openid_auth.useropenid': {
'Meta': {'object_name': 'UserOpenID'},
'claimed_id': ('django.db.models.fields.TextField', [], {'unique': 'True', 'max_length': '2047'}),
'display_id': ('django.db.models.fields.TextField', [], {'max_length': '2047'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
}
}
complete_apps = ['django_openid_auth']
\ No newline at end of file
...@@ -38,8 +38,10 @@ from django_openid_auth.models import Association, Nonce ...@@ -38,8 +38,10 @@ from django_openid_auth.models import Association, Nonce
class DjangoOpenIDStore(OpenIDStore): class DjangoOpenIDStore(OpenIDStore):
def __init__(self): def __init__(self):
self.max_nonce_age = 6 * 60 * 60 # Six hours super(DjangoOpenIDStore, self).__init__()
self.max_nonce_age = 6 * 60 * 60 # Six hours
def storeAssociation(self, server_url, association): def storeAssociation(self, server_url, association):
try: try:
......
...@@ -64,31 +64,28 @@ will be provided: ...@@ -64,31 +64,28 @@ will be provided:
@since: 2.1.1 @since: 2.1.1
""" """
from openid.message import registerNamespaceAlias, \
NamespaceAliasRegistrationError
from openid.extension import Extension
from openid import oidutil from openid import oidutil
from openid.extension import Extension
try: from openid.message import (
basestring #pylint:disable-msg=W0104 registerNamespaceAlias,
except NameError: NamespaceAliasRegistrationError,
# For Python 2.2 )
basestring = (str, unicode) #pylint:disable-msg=W0622
__all__ = [ __all__ = [
'TeamsRequest', 'TeamsRequest',
'TeamsResponse', 'TeamsResponse',
'ns_uri', 'ns_uri',
'supportsTeams', 'supportsTeams',
] ]
ns_uri = 'http://ns.launchpad.net/2007/openid-teams' ns_uri = 'http://ns.launchpad.net/2007/openid-teams'
try: try:
registerNamespaceAlias(ns_uri, 'lp') registerNamespaceAlias(ns_uri, 'lp')
except NamespaceAliasRegistrationError, e: except NamespaceAliasRegistrationError, e:
oidutil.log('registerNamespaceAlias(%r, %r) failed: %s' % (ns_uri, oidutil.log(
'lp', str(e),)) 'registerNamespaceAlias(%r, %r) failed: %s' % (ns_uri, 'lp', str(e)))
def supportsTeams(endpoint): def supportsTeams(endpoint):
"""Does the given endpoint advertise support for Launchpad Teams? """Does the given endpoint advertise support for Launchpad Teams?
...@@ -101,6 +98,7 @@ def supportsTeams(endpoint): ...@@ -101,6 +98,7 @@ def supportsTeams(endpoint):
""" """
return endpoint.usesExtension(ns_uri) return endpoint.usesExtension(ns_uri)
class TeamsNamespaceError(ValueError): class TeamsNamespaceError(ValueError):
"""The Launchpad teams namespace was not found and could not """The Launchpad teams namespace was not found and could not
be created using the expected name (there's another extension be created using the expected name (there's another extension
...@@ -115,6 +113,7 @@ class TeamsNamespaceError(ValueError): ...@@ -115,6 +113,7 @@ class TeamsNamespaceError(ValueError):
the message that is being processed. the message that is being processed.
""" """
def getTeamsNS(message): def getTeamsNS(message):
"""Extract the Launchpad teams namespace URI from the given """Extract the Launchpad teams namespace URI from the given
OpenID message. OpenID message.
...@@ -145,7 +144,8 @@ def getTeamsNS(message): ...@@ -145,7 +144,8 @@ def getTeamsNS(message):
# we know that ns_uri defined, because it's defined in the # we know that ns_uri defined, because it's defined in the
# else clause of the loop as well, so disable the warning # else clause of the loop as well, so disable the warning
return ns_uri #pylint:disable-msg=W0631 return ns_uri
class TeamsRequest(Extension): class TeamsRequest(Extension):
"""An object to hold the state of a Launchpad teams request. """An object to hold the state of a Launchpad teams request.
...@@ -154,7 +154,8 @@ class TeamsRequest(Extension): ...@@ -154,7 +154,8 @@ class TeamsRequest(Extension):
names that the RP is interested in. names that the RP is interested in.
@type required: [str] @type required: [str]
@group Consumer: requestField, requestTeams, getExtensionArgs, addToOpenIDRequest @group Consumer: requestField, requestTeams, getExtensionArgs,
addToOpenIDRequest
@group Server: fromOpenIDRequest, parseExtensionArgs @group Server: fromOpenIDRequest, parseExtensionArgs
""" """
...@@ -308,6 +309,7 @@ class TeamsRequest(Extension): ...@@ -308,6 +309,7 @@ class TeamsRequest(Extension):
return args return args
class TeamsResponse(Extension): class TeamsResponse(Extension):
"""Represents the data returned in a Launchpad teams response """Represents the data returned in a Launchpad teams response
inside of an OpenID C{id_res} response. This object will be inside of an OpenID C{id_res} response. This object will be
...@@ -394,7 +396,6 @@ class TeamsResponse(Extension): ...@@ -394,7 +396,6 @@ class TeamsResponse(Extension):
if "is_member" in args: if "is_member" in args:
is_member_str = args["is_member"] is_member_str = args["is_member"]
self.is_member = is_member_str.split(',') self.is_member = is_member_str.split(',')
#self.is_member = args["is_member"]
return self return self
...@@ -406,6 +407,5 @@ class TeamsResponse(Extension): ...@@ -406,6 +407,5 @@ class TeamsResponse(Extension):
@see: openid.extension @see: openid.extension
""" """
ns_args = {'is_member': ','.join(self.is_member),} ns_args = {'is_member': ','.join(self.is_member)}
return ns_args return ns_args
...@@ -26,18 +26,8 @@ ...@@ -26,18 +26,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
import unittest from .test_views import * # flake8: noqa
from test_views import * from .test_settings import *
from test_settings import * from .test_store import *
from test_store import * from .test_auth import *
from test_auth import * from .test_admin import *
from test_admin import *
def suite():
suite = unittest.TestSuite()
for name in ['test_auth', 'test_models', 'test_settings', 'test_store',
'test_views', 'test_admin']:
mod = __import__('%s.%s' % (__name__, name), {}, {}, ['suite'])
suite.addTest(mod.suite())
return suite
...@@ -25,35 +25,17 @@ ...@@ -25,35 +25,17 @@
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
"""
Tests for the django_openid_auth Admin login form replacement.
"""
import unittest """Tests for the django_openid_auth Admin login form replacement."""
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth.models import User
settings.OPENID_USE_AS_ADMIN_LOGIN = True
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings
def create_user(is_staff=False, authenticated=True): @override_settings(OPENID_USE_AS_ADMIN_LOGIN=True)
"""
Create and return a user, either the AnonymousUser or a normal Django user,
setting the is_staff attribute if appropriate.
"""
if not authenticated:
return AnonymousUser()
else:
user = User(
username=u'testing', email='testing@example.com',
is_staff=is_staff)
user.set_password(u'test')
user.save()
class SiteAdminTests(TestCase): class SiteAdminTests(TestCase):
""" """
TestCase for accessing /admin/ when the django_openid_auth form replacement TestCase for accessing /admin/ when the django_openid_auth form replacement
...@@ -65,23 +47,21 @@ class SiteAdminTests(TestCase): ...@@ -65,23 +47,21 @@ class SiteAdminTests(TestCase):
If the request has an authenticated user, who is not flagged as a If the request has an authenticated user, who is not flagged as a
staff member, then they get a failure response. staff member, then they get a failure response.
""" """
create_user() User.objects.create_user(
self.client.login(username='testing', password='test') username=u'testing', email='testing@example.com', password=u'test')
response = self.client.get('/admin/') assert self.client.login(username='testing', password='test')
self.assertTrue('User testing does not have admin access.' in response = self.client.get('/admin/', follow=True)
response.content, 'Missing error message in response') self.assertContains(
response,
'User testing does not have admin/staff access.', status_code=403)
def test_admin_site_with_openid_login_non_authenticated_user(self): def test_admin_site_with_openid_login_non_authenticated_user(self):
""" """
Unauthenticated users accessing the admin page should be directed to Unauthenticated users accessing the admin page should be directed to
the OpenID login url. the OpenID login url.
""" """
response = self.client.get('/admin/') response = self.client.get('/admin/', follow=True)
self.assertEqual(302, response.status_code) self.assertRedirects(
self.assertEqual('http://testserver' + getattr(settings, 'LOGIN_URL', response,
'/openid/login') + '?next=/admin/', getattr(settings, 'LOGIN_URL', '/openid/login') +
response['Location']) '?next=%2Fadmin%2F')
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
import unittest
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
...@@ -72,7 +70,3 @@ class UserOpenIDModelTestCase(TestCase): ...@@ -72,7 +70,3 @@ class UserOpenIDModelTestCase(TestCase):
self.assertFalse( self.assertFalse(
User.objects.get(username='someuser').has_perm( User.objects.get(username='someuser').has_perm(
'django_openid_auth.account_verified')) 'django_openid_auth.account_verified'))
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)
from unittest import skipIf, TestLoader from unittest import skipIf
from django import VERSION from django import VERSION
from django.conf import settings from django.conf import settings
...@@ -16,20 +16,8 @@ class SessionSerializerTest(TestCase): ...@@ -16,20 +16,8 @@ class SessionSerializerTest(TestCase):
[0] https://bit.ly/1myzetd [0] https://bit.ly/1myzetd
[1] https://github.com/openid/python-openid/issues/17 [1] https://github.com/openid/python-openid/issues/17
""" """
@skipIf(VERSION >= (1, 6, 0), "Old versions used the pickle serializer.") @skipIf(VERSION < (1, 5), "Django 1.4 does not provide SESSION_SERIALIZER")
def test_not_using_json_session_serializer(self):
# We use getattr because this setting did not exist in Django
# 1.4 (pickle serialization was hard coded)
serializer = getattr(settings, 'SESSION_SERIALIZER', '')
self.assertNotEqual(
serializer, 'django.contrib.sessions.serializers.JSONSerializer')
@skipIf(VERSION < (1, 6, 0), "Newer versions use JSON by default.")
def test_using_json_session_serializer(self): def test_using_json_session_serializer(self):
serializer = getattr(settings, 'SESSION_SERIALIZER', '') serializer = getattr(settings, 'SESSION_SERIALIZER', '')
self.assertEqual( self.assertEqual(
serializer, 'django.contrib.sessions.serializers.JSONSerializer') serializer, 'django.contrib.sessions.serializers.PickleSerializer')
def suite():
return TestLoader().loadTestsFromName(__name__)
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
import time import time
import unittest
from django.test import TestCase from django.test import TestCase
from openid.association import Association as OIDAssociation from openid.association import Association as OIDAssociation
...@@ -187,7 +186,3 @@ class OpenIDStoreTests(TestCase): ...@@ -187,7 +186,3 @@ class OpenIDStoreTests(TestCase):
# The second (non-expired) association is left behind. # The second (non-expired) association is left behind.
self.assertNotEqual(self.store.getAssociation('server-url', 'handle2'), self.assertNotEqual(self.store.getAssociation('server-url', 'handle2'),
None) None)
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)
...@@ -26,14 +26,16 @@ ...@@ -26,14 +26,16 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
from django.conf.urls import patterns, include
from django.http import HttpResponse from django.http import HttpResponse
from django.conf.urls import *
def get_user(request): def get_user(request):
return HttpResponse(request.user.username) return HttpResponse(request.user.username)
urlpatterns = patterns('',
urlpatterns = patterns(
'',
(r'^getuser/$', get_user), (r'^getuser/$', get_user),
(r'^openid/', include('django_openid_auth.urls')), (r'^openid/', include('django_openid_auth.urls')),
) )
...@@ -27,9 +27,10 @@ ...@@ -27,9 +27,10 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
from django.conf.urls import * from django.conf.urls import patterns, url
urlpatterns = patterns('django_openid_auth.views', urlpatterns = patterns(
'django_openid_auth.views',
url(r'^login/$', 'login_begin', name='openid-login'), url(r'^login/$', 'login_begin', name='openid-login'),
url(r'^complete/$', 'login_complete', name='openid-complete'), url(r'^complete/$', 'login_complete', name='openid-complete'),
url(r'^logo.gif$', 'logo', name='openid-logo'), url(r'^logo.gif$', 'logo', name='openid-logo'),
......
...@@ -62,6 +62,7 @@ from django_openid_auth.exceptions import ( ...@@ -62,6 +62,7 @@ from django_openid_auth.exceptions import (
next_url_re = re.compile('^/[-\w/]+$') next_url_re = re.compile('^/[-\w/]+$')
def is_valid_next_url(next): def is_valid_next_url(next):
# When we allow this: # When we allow this:
# /openid/?next=/welcome/ # /openid/?next=/welcome/
...@@ -78,8 +79,8 @@ def sanitise_redirect_url(redirect_to): ...@@ -78,8 +79,8 @@ def sanitise_redirect_url(redirect_to):
is_valid = False is_valid = False
elif '//' in redirect_to: elif '//' in redirect_to:
# Allow the redirect URL to be external if it's a permitted domain # Allow the redirect URL to be external if it's a permitted domain
allowed_domains = getattr(settings, allowed_domains = getattr(
"ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS", []) settings, "ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS", [])
s, netloc, p, q, f = urlsplit(redirect_to) s, netloc, p, q, f = urlsplit(redirect_to)
# allow it if netloc is blank or if the domain is allowed # allow it if netloc is blank or if the domain is allowed
if netloc: if netloc:
...@@ -113,11 +114,13 @@ def render_openid_request(request, openid_request, return_to, trust_root=None): ...@@ -113,11 +114,13 @@ def render_openid_request(request, openid_request, return_to, trust_root=None):
if openid_request.shouldSendRedirect(): if openid_request.shouldSendRedirect():
redirect_url = openid_request.redirectURL( redirect_url = openid_request.redirectURL(
trust_root, return_to) trust_root, return_to)
return HttpResponseRedirect(redirect_url) response = HttpResponseRedirect(redirect_url)
else: else:
form_html = openid_request.htmlMarkup( form_html = openid_request.htmlMarkup(
trust_root, return_to, form_tag_attrs={'id': 'openid_message'}) trust_root, return_to, form_tag_attrs={'id': 'openid_message'})
return HttpResponse(form_html, content_type='text/html;charset=UTF-8') response = HttpResponse(
form_html, content_type='text/html;charset=UTF-8')
return response
def default_render_failure(request, message, status=403, def default_render_failure(request, message, status=403,
...@@ -133,7 +136,7 @@ def default_render_failure(request, message, status=403, ...@@ -133,7 +136,7 @@ def default_render_failure(request, message, status=403,
def parse_openid_response(request): def parse_openid_response(request):
"""Parse an OpenID response from a Django request.""" """Parse an OpenID response from a Django request."""
# Short cut if there is no request parameters. # Short cut if there is no request parameters.
#if len(request.REQUEST) == 0: # if len(request.REQUEST) == 0:
# return None # return None
current_url = request.build_absolute_uri() current_url = request.build_absolute_uri()
...@@ -164,15 +167,15 @@ def login_begin(request, template_name='openid/login.html', ...@@ -164,15 +167,15 @@ def login_begin(request, template_name='openid/login.html',
# Invalid or no form data: # Invalid or no form data:
if openid_url is None: if openid_url is None:
return render_to_response(template_name, { context = {'form': login_form, redirect_field_name: redirect_to}
'form': login_form, return render_to_response(
redirect_field_name: redirect_to template_name, context,
}, context_instance=RequestContext(request)) context_instance=RequestContext(request))
consumer = make_consumer(request) consumer = make_consumer(request)
try: try:
openid_request = consumer.begin(openid_url) openid_request = consumer.begin(openid_url)
except DiscoveryFailure, exc: except DiscoveryFailure as exc:
return render_failure( return render_failure(
request, "OpenID discovery error: %s" % (str(exc),), status=500, request, "OpenID discovery error: %s" % (str(exc),), status=500,
exception=exc) exception=exc)
...@@ -222,11 +225,11 @@ def login_begin(request, template_name='openid/login.html', ...@@ -222,11 +225,11 @@ def login_begin(request, template_name='openid/login.html',
sreg_optional_fields.extend( sreg_optional_fields.extend(
getattr(settings, 'OPENID_SREG_EXTRA_FIELDS', [])) getattr(settings, 'OPENID_SREG_EXTRA_FIELDS', []))
sreg_optional_fields = [ sreg_optional_fields = [
field for field in sreg_optional_fields if ( field for field in sreg_optional_fields
not field in sreg_required_fields)] if field not in sreg_required_fields]
openid_request.addExtension( openid_request.addExtension(
sreg.SRegRequest(optional=sreg_optional_fields, sreg.SRegRequest(optional=sreg_optional_fields,
required=sreg_required_fields)) required=sreg_required_fields))
if getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False): if getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False):
preferred_auth = [ preferred_auth = [
...@@ -236,13 +239,16 @@ def login_begin(request, template_name='openid/login.html', ...@@ -236,13 +239,16 @@ def login_begin(request, template_name='openid/login.html',
openid_request.addExtension(pape_request) openid_request.addExtension(pape_request)
# Request team info # Request team info
teams_mapping_auto = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False) teams_mapping_auto = getattr(
teams_mapping_auto_blacklist = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', []) settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False)
teams_mapping_auto_blacklist = getattr(
settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', [])
launchpad_teams = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) launchpad_teams = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {})
if teams_mapping_auto: if teams_mapping_auto:
#ignore launchpad teams. use all django-groups # ignore launchpad teams. use all django-groups
launchpad_teams = dict() launchpad_teams = dict()
all_groups = Group.objects.exclude(name__in=teams_mapping_auto_blacklist) all_groups = Group.objects.exclude(
name__in=teams_mapping_auto_blacklist)
for group in all_groups: for group in all_groups:
launchpad_teams[group.name] = group.name launchpad_teams[group.name] = group.name
...@@ -270,9 +276,9 @@ def login_begin(request, template_name='openid/login.html', ...@@ -270,9 +276,9 @@ def login_begin(request, template_name='openid/login.html',
def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME, def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME,
render_failure=None): render_failure=None):
redirect_to = request.REQUEST.get(redirect_field_name, '') redirect_to = request.REQUEST.get(redirect_field_name, '')
render_failure = render_failure or \ render_failure = (
getattr(settings, 'OPENID_RENDER_FAILURE', None) or \ render_failure or getattr(settings, 'OPENID_RENDER_FAILURE', None) or
default_render_failure default_render_failure)
openid_response = parse_openid_response(request) openid_response = parse_openid_response(request)
if not openid_response: if not openid_response:
...@@ -288,10 +294,12 @@ def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME, ...@@ -288,10 +294,12 @@ def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME,
if user is not None: if user is not None:
if user.is_active: if user.is_active:
auth_login(request, user) auth_login(request, user)
response = HttpResponseRedirect(sanitise_redirect_url(redirect_to)) response = HttpResponseRedirect(
sanitise_redirect_url(redirect_to))
# Notify any listeners that we successfully logged in. # Notify any listeners that we successfully logged in.
openid_login_complete.send(sender=UserOpenID, request=request, openid_login_complete.send(
sender=UserOpenID, request=request,
openid_response=openid_response) openid_response=openid_response)
return response return response
......
...@@ -27,91 +27,44 @@ ...@@ -27,91 +27,44 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
# Django settings for example project. """
import django Django settings for example_consumer project.
django_version = django.get_version()
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = ( For more information on this file, see
# ('Your Name', 'your_email@domain.com'), https://docs.djangoproject.com/en/1.7/topics/settings/
)
MANAGERS = ADMINS For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
if django_version >= "1.2": # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
csrf_middleware = 'django.middleware.csrf.CsrfViewMiddleware' import os
DATABASES = { import django
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'sqlite.db',
}
}
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
else:
csrf_middleware = 'django.contrib.csrf.middleware.CsrfViewMiddleware'
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
)
DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
DATABASE_NAME = 'sqlite.db' # Or path to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. Choices can be found here:
# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
# although not all variations may be possible on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
LANGUAGE_CODE = 'en-us'
SITE_ID = 1 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# Absolute path to the directory that holds media. # Quick-start development settings - unsuitable for production
# Example: "/home/media/media.lawrence.com/" # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
MEDIA_ROOT = ''
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '34958734985734985734985798437'
# URL that handles the media served from MEDIA_ROOT. # SECURITY WARNING: don't run with debug turned on in production!
# Example: "http://media.lawrence.com" DEBUG = True
MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a TEMPLATE_DEBUG = True
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody. ALLOWED_HOSTS = []
SECRET_KEY = '34958734985734985734985798437'
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
csrf_middleware, 'django.middleware.csrf.CsrfViewMiddleware',
) )
ROOT_URLCONF = 'example_consumer.urls' # Application definition
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.auth', 'django.contrib.auth',
...@@ -119,9 +72,43 @@ INSTALLED_APPS = ( ...@@ -119,9 +72,43 @@ INSTALLED_APPS = (
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.admin', 'django.contrib.admin',
'django_openid_auth', 'django_openid_auth',
'south',
) )
if django.VERSION < (1, 7):
INSTALLED_APPS += ('south',)
ROOT_URLCONF = 'example_consumer.urls'
WSGI_APPLICATION = 'example_consumer.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL = '/static/'
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django_openid_auth.auth.OpenIDBackend', 'django_openid_auth.auth.OpenIDBackend',
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
...@@ -144,11 +131,11 @@ OPENID_VALID_VERIFICATION_SCHEMES = { ...@@ -144,11 +131,11 @@ OPENID_VALID_VERIFICATION_SCHEMES = {
# If set, always use this as the identity URL rather than asking the # If set, always use this as the identity URL rather than asking the
# user. This only makes sense if it is a server URL. # user. This only makes sense if it is a server URL.
OPENID_SSO_SERVER_URL = 'https://login.launchpad.net/' OPENID_SSO_SERVER_URL = 'https://login.ubuntu.com/'
# Tell django.contrib.auth to use the OpenID signin URLs. # Tell django.contrib.auth to use the OpenID signin URLs.
LOGIN_URL = '/openid/login/' LOGIN_URL = '/openid/login/'
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
# Should django_auth_openid be used to sign into the admin interface? # Should django_auth_openid be used to sign into the admin interface?
OPENID_USE_AS_ADMIN_LOGIN = False OPENID_USE_AS_ADMIN_LOGIN = True
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
from django.conf.urls import * from django.conf.urls import patterns, include, url
from django.contrib import admin from django.contrib import admin
import views import views
...@@ -35,11 +35,12 @@ import views ...@@ -35,11 +35,12 @@ import views
admin.autodiscover() admin.autodiscover()
urlpatterns = patterns('', urlpatterns = patterns(
(r'^$', views.index), '',
(r'^openid/', include('django_openid_auth.urls')), url(r'^$', views.index),
(r'^logout/$', 'django.contrib.auth.views.logout'), url(r'^openid/', include('django_openid_auth.urls')),
(r'^private/$', views.require_authentication), url(r'^logout/$', 'django.contrib.auth.views.logout'),
url(r'^private/$', views.require_authentication),
(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
) )
"""
WSGI config for demo project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
...@@ -3,7 +3,7 @@ import os ...@@ -3,7 +3,7 @@ import os
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_consumer.settings")
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
......
[tox] [tox]
envlist = envlist =
py2.7-django1.4, py2.7-django1.5, py2.7-django1.6 py2.7-django1.4, py2.7-django1.5, py2.7-django1.6, py2.7-django1.7, py2.7-django1.8
[testenv] [testenv]
commands = make check commands = python manage.py test django_openid_auth
deps=
mock
python-openid
# Python 2.7
[testenv:py2.7-django1.4] [testenv:py2.7-django1.4]
basepython = python2.7 basepython = python2.7
deps = django >= 1.4, < 1.5 deps =
python-openid django >= 1.4, < 1.5
south {[testenv]deps}
south==1.0
[testenv:py2.7-django1.5] [testenv:py2.7-django1.5]
basepython = python2.7 basepython = python2.7
deps = django >= 1.5, < 1.6 deps =
python-openid django >= 1.5, < 1.6
south {[testenv]deps}
south==1.0
[testenv:py2.7-django1.6] [testenv:py2.7-django1.6]
basepython = python2.7 basepython = python2.7
deps = django >= 1.6, < 1.7 deps =
python-openid django >= 1.6, < 1.7
south {[testenv]deps}
south==1.0
[testenv:py2.7-django1.7]
basepython = python2.7
deps =
django >= 1.7, < 1.8
{[testenv]deps}
[testenv:py2.7-django1.8]
basepython = python2.7
deps =
django >= 1.8, < 1.9
{[testenv]deps}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment