1
from django.http import HttpResponse, HttpResponseRedirect, Http404
1
from django.http import HttpResponse, HttpResponseRedirect, get_host
2
2
from django.shortcuts import render_to_response as render
3
3
from django.template import RequestContext
4
4
from django.conf import settings
7
7
from openid.consumer.consumer import Consumer, \
8
8
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
9
9
from openid.consumer.discover import DiscoveryFailure
10
12
from util import OpenID, DjangoOpenIDStore, from_openid_response
12
14
from django.utils.html import escape
27
29
host = escape(request.META['HTTP_HOST'])
28
30
return get_url_host(request) + request.get_full_path()
30
def is_valid_after_url(after):
32
next_url_re = re.compile('^/[-\w/]+$')
34
def is_valid_next_url(next):
31
35
# When we allow this:
32
# /openid/?after=/welcome/
33
# For security reasons we want to restrict the after= bit to being a local
36
# /openid/?next=/welcome/
37
# For security reasons we want to restrict the next= bit to being a local
34
38
# path, not a complete URL.
35
if not after.startswith('/'):
39
return bool(next_url_re.match(next))
44
def begin(request, sreg=None, extension_args=None):
41
def begin(request, sreg=None, extension_args=None, redirect_to=None):
42
if request.GET.get('logo'):
43
# Makes for a better demo
45
OPENID_LOGO_BASE_64.decode('base64'), mimetype='image/gif'
45
48
extension_args = extension_args or {}
47
50
extension_args['sreg.optional'] = sreg
48
51
trust_root = getattr(
49
52
settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
51
redirect_to = getattr(
54
redirect_to = redirect_to or getattr(
52
55
settings, 'OPENID_REDIRECT_TO',
53
56
# If not explicitly set, assume current URL with complete/ appended
54
57
get_full_url(request).split('?')[0] + 'complete/'
59
# In case they were lazy...
60
if not redirect_to.startswith('http://'):
61
redirect_to = get_url_host(request) + redirect_to
57
if request.GET.get('after') and is_valid_after_url(request.GET['after']):
63
if request.GET.get('next') and is_valid_next_url(request.GET['next']):
58
64
if '?' in redirect_to:
62
redirect_to += join + 'after=' + urllib.urlencode(request.GET['after'])
68
redirect_to += join + 'next=' + urllib.urlencode(request.GET['next'])
64
user_url = request.POST.get('openid_url', None)
70
user_url = request.POST.get('openid_url', None)
66
return render('openid_signin.html')
72
return render('openid_signin.html', {'action': request.path})
74
if xri.identifierScheme(user_url) == 'XRI' and getattr(
75
settings, 'OPENID_DISALLOW_INAMES', False
77
return failure(request, 'i-names are not supported')
68
79
consumer = Consumer(request.session, DjangoOpenIDStore())
70
81
auth_request = consumer.begin(user_url)
71
82
except DiscoveryFailure:
72
raise Http404, "Discovery failure"
83
return failure(request, "The OpenID was invalid")
74
85
# Add extension args (for things like simple registration)
75
86
for name, value in extension_args.items():
104
115
request.session['openids'].append(from_openid_response(openid_response))
106
after = request.GET.get('after', '').strip()
107
if not after or not is_valid_after_url(after):
108
after = getattr(settings, 'OPENID_REDIRECT_AFTER', '/')
117
next = request.GET.get('next', '').strip()
118
if not next or not is_valid_next_url(next):
119
next = getattr(settings, 'OPENID_REDIRECT_NEXT', '/')
110
return HttpResponseRedirect(after)
121
return HttpResponseRedirect(next)
112
123
def failure(request, message):
113
124
return render('openid_failure.html', {
114
125
'message': message
115
}) # , context_instance = RequestContext(request))
117
128
def signout(request):
118
request.session.openids = []
119
request.session.openid = None
129
request.session['openids'] = []
120
130
next = request.GET.get('next', '/')
131
if not is_valid_next_url(next):
121
133
return HttpResponseRedirect(next)
135
# Logo from http://openid.net/login-bg.gif
136
# Embedded here for convenience; you should serve this as a static file
137
OPENID_LOGO_BASE_64 = """
138
R0lGODlhEAAQAMQAAO3t7eHh4srKyvz8/P5pDP9rENLS0v/28P/17tXV1dHEvPDw8M3Nzfn5+d3d
139
3f5jA97Syvnv6MfLzcfHx/1mCPx4Kc/S1Pf189C+tP+xgv/k1N3OxfHy9NLV1/39/f///yH5BAAA
140
AAAALAAAAAAQABAAAAVq4CeOZGme6KhlSDoexdO6H0IUR+otwUYRkMDCUwIYJhLFTyGZJACAwQcg
141
EAQ4kVuEE2AIGAOPQQAQwXCfS8KQGAwMjIYIUSi03B7iJ+AcnmclHg4TAh0QDzIpCw4WGBUZeikD