Commit 9d4964cc by swillison

Initial checkin

parent 3bc90ff8
This is currently incomplete.
class OpenIDMiddleware(object):
"""
Populate request.openid and request.openids with their openid. This comes
eithen from their cookie or from their session, depending on the presence
of OPENID_USE_SESSIONS.
"""
def process_request(self, request):
request.openids = request.session.get('openids', [])
if request.openids:
request.openid = request.openids[-1] # Last authenticated OpenID
else:
request.openid = None
from django.db import models
class Nonce(models.Model):
nonce = models.CharField(maxlength=8)
expires = models.IntegerField()
def __str__(self):
return "Nonce: %s" % self.nonce
class Association(models.Model):
server_url = models.TextField(maxlength=2047)
handle = models.CharField(maxlength=255)
secret = models.TextField(maxlength=255) # Stored base64 encoded
issued = models.IntegerField()
lifetime = models.IntegerField()
assoc_type = models.TextField(maxlength=64)
def __str__(self):
return "Association: %s, %s" % (self.server_url, self.handle)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Sign in with your OpenID</title>
</head>
<body>
<h1>Sign in with your OpenID</h1>
<form action="{{ action }}" method="post">
<p><input class="openid" type="text" name="openid_url"> <input type="submit" value="Sign in"></p>
</form>
</body>
</html>
\ No newline at end of file
from openid.store.interface import OpenIDStore
from openid.association import Association as OIDAssociation
import time, base64, md5
from django.conf import settings
from models import Association, Nonce
class OpenID:
def __init__(self, openid, issued, attrs=None, sreg=None):
self.openid = openid
self.issued = issued
self.attrs = attrs or {}
self.sreg = sreg or {}
def __repr__(self):
return '<OpenID: %s>' % self.openid
def __str__(self):
return self.openid
class DjangoOpenIDStore(OpenIDStore):
def __init__(self):
self.max_nonce_age = 6 * 60 * 60 # Six hours
def storeAssociation(self, server_url, association):
assoc = Association(
server_url = server_url,
handle = association.handle,
secret = base64.encodestring(association.secret),
issued = association.issued,
lifetime = association.issued,
assoc_type = association.assoc_type
)
assoc.save()
def getAssociation(self, server_url, handle=None):
assocs = []
if handle is not None:
assocs = Association.objects.filter(
server_url = server_url, handle = handle
)
else:
assocs = Association.objects.filter(
server_url = server_url
)
if not assocs:
return None
associations = []
for assoc in assocs:
association = OIDAssociation(
assoc.handle, base64.decodestring(assoc.secret), assoc.issued,
assoc.lifetime, assoc.assoc_type
)
if association.getExpiresIn() == 0:
self.removeAssociation(server_url, assoc.handle)
else:
associations.append((association.issued, association))
if not associations:
return None
return associations[-1][1]
def removeAssociation(self, server_url, handle):
assocs = list(Association.objects.filter(
server_url = server_url, handle = handle
))
assocs_exist = len(assocs) > 0
for assoc in assocs:
assoc.delete()
return assocs_exist
def storeNonce(self, nonce):
nonce, created = Nonce.objects.get_or_create(
nonce = nonce, defaults={'expires': int(time.time())}
)
def useNonce(self, nonce):
try:
nonce = Nonce.objects.get(nonce = nonce)
except Nonce.DoesNotExist:
return 0
# Now check nonce has not expired
nonce_age = int(time.time()) - nonce.expires
if nonce_age > self.max_nonce_age:
present = 0
else:
present = 1
nonce.delete()
return present
def getAuthKey(self):
# Use first AUTH_KEY_LEN characters of md5 hash of SECRET_KEY
return md5.new(settings.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN]
def isDumb(self):
return False
def from_openid_response(openid_response):
issued = int(time.time())
return OpenID(
openid_response.identity_url, issued, openid_response.signed_args,
openid_response.extensionResponse('sreg')
)
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response as render
from django.template import RequestContext
from django.conf import settings
import md5, time
from openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
from openid.consumer.discover import DiscoveryFailure
from util import OpenID, DjangoOpenIDStore, from_openid_response
from django.utils.html import escape
def get_url_host(request):
if request.is_secure():
protocol = 'https'
else:
protocol = 'http'
host = escape(request.META['HTTP_HOST'])
return '%s://%s' % (protocol, host)
def get_full_url(request):
if request.is_secure():
protocol = 'https'
else:
protocol = 'http'
host = escape(request.META['HTTP_HOST'])
return get_url_host(request) + request.get_full_path()
def is_valid_after_url(after):
# When we allow this:
# /openid/?after=/welcome/
# For security reasons we want to restrict the after= bit to being a local
# path, not a complete URL.
if not after.startswith('/'):
return False
if '://' in after:
return False
for c in after:
if c.isspace():
return False
return True
def begin(request, sreg=None, extension_args=None):
extension_args = extension_args or {}
if sreg:
extension_args['sreg.optional'] = sreg
trust_root = getattr(
settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
)
redirect_to = getattr(
settings, 'OPENID_REDIRECT_TO',
# If not explicitly set, assume current URL with complete/ appended
get_full_url(request).split('?')[0] + 'complete/'
)
if request.GET.get('after') and is_valid_after_url(request.GET['after']):
if '?' in redirect_to:
join = '&'
else:
join = '?'
redirect_to += join + 'after=' + urllib.urlencode(request.GET['after'])
user_url = request.POST.get('openid_url', None)
if not user_url:
return render('openid_signin.html')
consumer = Consumer(request.session, DjangoOpenIDStore())
try:
auth_request = consumer.begin(user_url)
except DiscoveryFailure:
raise Http404, "Discovery failure"
# Add extension args (for things like simple registration)
for name, value in extension_args.items():
namespace, key = name.split('.', 1)
auth_request.addExtensionArg(namespace, key, value)
redirect_url = auth_request.redirectURL(trust_root, redirect_to)
return HttpResponseRedirect(redirect_url)
def complete(request):
consumer = Consumer(request.session, DjangoOpenIDStore())
openid_response = consumer.complete(dict(request.GET.items()))
if openid_response.status == SUCCESS:
return success(request, openid_response.identity_url, openid_response)
elif openid_response.status == CANCEL:
return failure(request, 'The request was cancelled')
elif openid_response.status == FAILURE:
return failure(request, openid_response.message)
elif openid_response.status == SETUP_NEEDED:
return failure(request, 'Setup needed')
else:
assert False, "Bad openid status: %s" % openid_response.status
def success(request, identity_url, openid_response):
if 'openids' not in request.session.keys():
request.session['openids'] = []
# Eliminate any duplicates
request.session['openids'] = [
o for o in request.session['openids'] if o.openid != identity_url
]
request.session['openids'].append(from_openid_response(openid_response))
after = request.GET.get('after', '').strip()
if not after or not is_valid_after_url(after):
after = getattr(settings, 'OPENID_REDIRECT_AFTER', '/')
return HttpResponseRedirect(after)
def failure(request, message):
return render('openid_failure.html', {
'message': message
}) # , context_instance = RequestContext(request))
def signout(request):
request.session.openids = []
request.session.openid = None
next = request.GET.get('next', '/')
return HttpResponseRedirect(next)
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)
# Django settings for example project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
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
# 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.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT.
# Example: "http://media.lawrence.com"
MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = '34958734985734985734985798437'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
# 'django.template.loaders.eggs.load_template_source',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django_openidconsumer.middleware.OpenIDMiddleware',
)
ROOT_URLCONF = 'example.urls'
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 = (
'django.contrib.sessions',
'django_openidconsumer',
)
from django.conf.urls.defaults import *
import views
urlpatterns = patterns('',
(r'^$', views.index),
(r'^openid/$', 'django_openidconsumer.views.begin', {
'sreg': 'email,nickname'
}),
(r'^openid/complete/$', 'django_openidconsumer.views.complete'),
)
from django.http import HttpResponse
from pprint import pformat
from django.utils.html import escape
def index(request):
s = """
<p>OpenID is <pre>%s</pre>.</p>
<p><a href="/openid/">Sign in with OpenID</a></p><pre>
""" % escape(pformat(request.openid.__dict__.items()))
s += escape(pformat(request.session._session))
s += '\n\n\n'
s += escape(pformat(request.META))
return HttpResponse(s)
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