Commit b5f6cb7f by swillison

Ready for launch

parent 9d4964cc
This is currently incomplete. This is currently incomplete.
TODO:
- Docs
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>OpenID failed</title>
</head>
<body>
<h1>OpenID failed</h1>
<p>{{ message|escape }}</p>
</body>
</html>
\ No newline at end of file
...@@ -3,6 +3,13 @@ ...@@ -3,6 +3,13 @@
<html> <html>
<head> <head>
<title>Sign in with your OpenID</title> <title>Sign in with your OpenID</title>
<style type="text/css">
input.openid {
background: url({{ action }}?logo=1) no-repeat;
background-position: 0 50%;
padding-left: 16px;
}
</style>
</head> </head>
<body> <body>
<h1>Sign in with your OpenID</h1> <h1>Sign in with your OpenID</h1>
......
from openid.store.interface import OpenIDStore from openid.store.interface import OpenIDStore
from openid.association import Association as OIDAssociation from openid.association import Association as OIDAssociation
from yadis import xri
import time, base64, md5 import time, base64, md5
from django.conf import settings from django.conf import settings
...@@ -11,8 +13,11 @@ class OpenID: ...@@ -11,8 +13,11 @@ class OpenID:
self.issued = issued self.issued = issued
self.attrs = attrs or {} self.attrs = attrs or {}
self.sreg = sreg or {} self.sreg = sreg or {}
self.is_iname = (xri.identifierScheme(openid) == 'XRI')
def __repr__(self): def __repr__(self):
return '<OpenID: %s>' % self.openid return '<OpenID: %s>' % self.openid
def __str__(self): def __str__(self):
return self.openid return self.openid
......
from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.http import HttpResponse, HttpResponseRedirect, get_host
from django.shortcuts import render_to_response as render from django.shortcuts import render_to_response as render
from django.template import RequestContext from django.template import RequestContext
from django.conf import settings from django.conf import settings
import md5, time import md5, re, time
from openid.consumer.consumer import Consumer, \ from openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
from openid.consumer.discover import DiscoveryFailure from openid.consumer.discover import DiscoveryFailure
from yadis import xri
from util import OpenID, DjangoOpenIDStore, from_openid_response from util import OpenID, DjangoOpenIDStore, from_openid_response
from django.utils.html import escape from django.utils.html import escape
...@@ -16,7 +18,7 @@ def get_url_host(request): ...@@ -16,7 +18,7 @@ def get_url_host(request):
protocol = 'https' protocol = 'https'
else: else:
protocol = 'http' protocol = 'http'
host = escape(request.META['HTTP_HOST']) host = escape(get_host(request))
return '%s://%s' % (protocol, host) return '%s://%s' % (protocol, host)
def get_full_url(request): def get_full_url(request):
...@@ -27,49 +29,58 @@ def get_full_url(request): ...@@ -27,49 +29,58 @@ def get_full_url(request):
host = escape(request.META['HTTP_HOST']) host = escape(request.META['HTTP_HOST'])
return get_url_host(request) + request.get_full_path() return get_url_host(request) + request.get_full_path()
def is_valid_after_url(after): next_url_re = re.compile('^/[-\w/]+$')
def is_valid_next_url(next):
# When we allow this: # When we allow this:
# /openid/?after=/welcome/ # /openid/?next=/welcome/
# For security reasons we want to restrict the after= bit to being a local # For security reasons we want to restrict the next= bit to being a local
# path, not a complete URL. # path, not a complete URL.
if not after.startswith('/'): return bool(next_url_re.match(next))
return False
if '://' in after: def begin(request, sreg=None, extension_args=None, redirect_to=None):
return False if request.GET.get('logo'):
for c in after: # Makes for a better demo
if c.isspace(): return HttpResponse(
return False OPENID_LOGO_BASE_64.decode('base64'), mimetype='image/gif'
return True )
def begin(request, sreg=None, extension_args=None):
extension_args = extension_args or {} extension_args = extension_args or {}
if sreg: if sreg:
extension_args['sreg.optional'] = sreg extension_args['sreg.optional'] = sreg
trust_root = getattr( trust_root = getattr(
settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/' settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
) )
redirect_to = getattr( redirect_to = redirect_to or getattr(
settings, 'OPENID_REDIRECT_TO', settings, 'OPENID_REDIRECT_TO',
# If not explicitly set, assume current URL with complete/ appended # If not explicitly set, assume current URL with complete/ appended
get_full_url(request).split('?')[0] + 'complete/' get_full_url(request).split('?')[0] + 'complete/'
) )
# In case they were lazy...
if not redirect_to.startswith('http://'):
redirect_to = get_url_host(request) + redirect_to
if request.GET.get('after') and is_valid_after_url(request.GET['after']): if request.GET.get('next') and is_valid_next_url(request.GET['next']):
if '?' in redirect_to: if '?' in redirect_to:
join = '&' join = '&'
else: else:
join = '?' join = '?'
redirect_to += join + 'after=' + urllib.urlencode(request.GET['after']) redirect_to += join + 'next=' + urllib.urlencode(request.GET['next'])
user_url = request.POST.get('openid_url', None) user_url = request.POST.get('openid_url', None)
if not user_url: if not user_url:
return render('openid_signin.html') return render('openid_signin.html', {'action': request.path})
if xri.identifierScheme(user_url) == 'XRI' and getattr(
settings, 'OPENID_DISALLOW_INAMES', False
):
return failure(request, 'i-names are not supported')
consumer = Consumer(request.session, DjangoOpenIDStore()) consumer = Consumer(request.session, DjangoOpenIDStore())
try: try:
auth_request = consumer.begin(user_url) auth_request = consumer.begin(user_url)
except DiscoveryFailure: except DiscoveryFailure:
raise Http404, "Discovery failure" return failure(request, "The OpenID was invalid")
# Add extension args (for things like simple registration) # Add extension args (for things like simple registration)
for name, value in extension_args.items(): for name, value in extension_args.items():
...@@ -103,19 +114,30 @@ def success(request, identity_url, openid_response): ...@@ -103,19 +114,30 @@ def success(request, identity_url, openid_response):
] ]
request.session['openids'].append(from_openid_response(openid_response)) request.session['openids'].append(from_openid_response(openid_response))
after = request.GET.get('after', '').strip() next = request.GET.get('next', '').strip()
if not after or not is_valid_after_url(after): if not next or not is_valid_next_url(next):
after = getattr(settings, 'OPENID_REDIRECT_AFTER', '/') next = getattr(settings, 'OPENID_REDIRECT_NEXT', '/')
return HttpResponseRedirect(after) return HttpResponseRedirect(next)
def failure(request, message): def failure(request, message):
return render('openid_failure.html', { return render('openid_failure.html', {
'message': message 'message': message
}) # , context_instance = RequestContext(request)) })
def signout(request): def signout(request):
request.session.openids = [] request.session['openids'] = []
request.session.openid = None
next = request.GET.get('next', '/') next = request.GET.get('next', '/')
if not is_valid_next_url(next):
next = '/'
return HttpResponseRedirect(next) return HttpResponseRedirect(next)
# Logo from http://openid.net/login-bg.gif
# Embedded here for convenience; you should serve this as a static file
OPENID_LOGO_BASE_64 = """
R0lGODlhEAAQAMQAAO3t7eHh4srKyvz8/P5pDP9rENLS0v/28P/17tXV1dHEvPDw8M3Nzfn5+d3d
3f5jA97Syvnv6MfLzcfHx/1mCPx4Kc/S1Pf189C+tP+xgv/k1N3OxfHy9NLV1/39/f///yH5BAAA
AAAALAAAAAAQABAAAAVq4CeOZGme6KhlSDoexdO6H0IUR+otwUYRkMDCUwIYJhLFTyGZJACAwQcg
EAQ4kVuEE2AIGAOPQQAQwXCfS8KQGAwMjIYIUSi03B7iJ+AcnmclHg4TAh0QDzIpCw4WGBUZeikD
Fzk0lpcjIQA7
"""
...@@ -3,8 +3,11 @@ import views ...@@ -3,8 +3,11 @@ import views
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^$', views.index), (r'^$', views.index),
(r'^openid/$', 'django_openidconsumer.views.begin', { (r'^openid/$', 'django_openidconsumer.views.begin'),
'sreg': 'email,nickname' (r'^openid/with-sreg/$', 'django_openidconsumer.views.begin', {
'sreg': 'email,nickname',
'redirect_to': '/openid/complete/',
}), }),
(r'^openid/complete/$', 'django_openidconsumer.views.complete'), (r'^openid/complete/$', 'django_openidconsumer.views.complete'),
(r'^openid/signout/$', 'django_openidconsumer.views.signout'),
) )
...@@ -4,11 +4,30 @@ from pprint import pformat ...@@ -4,11 +4,30 @@ from pprint import pformat
from django.utils.html import escape from django.utils.html import escape
def index(request): def index(request):
s = """ s = []
<p>OpenID is <pre>%s</pre>.</p> if request.openid:
<p><a href="/openid/">Sign in with OpenID</a></p><pre> s.append('<p>You are signed in as <strong>%s</strong>' % escape(
""" % escape(pformat(request.openid.__dict__.items())) str(request.openid)
s += escape(pformat(request.session._session)) ))
s += '\n\n\n'
s += escape(pformat(request.META)) if request.openid.is_iname:
return HttpResponse(s) s.append(' (an i-name)')
s.append('</p>')
if request.openid.sreg:
s.append('<p>sreg data: %s</p>' % escape(str(request.openid.sreg)))
if len(request.openids) > 1:
s.append('<p>Also signed in as %s</p>' % ', '.join([
escape(str(o)) for o in request.openids[:-1]
]))
s.append('<a href="/openid/">Sign in with OpenID</a>')
s.append(' | <a href="/openid/with-sreg/">')
s.append('Sign in with OpenID using simple registration</a>')
if request.openid:
s.append(' | <a href="/openid/signout/">Sign out</a>')
s.append('</p>')
return HttpResponse('\n'.join(s))
<p>The <tt class="docutils literal"><span class="pre">django_openidconsumer</span></tt> package contains all of the code needed to set up
your Django application as an OpenID consumer. You can use it to allow OpenID
users to sign in to your site without having to create a new username and
password.</p>
<div class="section">
<h2><a id="overview">Overview</a></h2>
<p>The OpenID consumer system consists of:</p>
<ul class="simple">
<li>Views for you to hook in to your application.</li>
<li>Database models implementing the persistence layer of an OpenID consumer.</li>
<li>Middleware that makes <tt class="docutils literal"><span class="pre">request.openid</span></tt> and <tt class="docutils literal"><span class="pre">request.openids</span></tt>
properties available to your application views.</li>
</ul>
</div>
<div class="section">
<h2><a id="dependencies">Dependencies</a></h2>
<p><tt class="docutils literal"><span class="pre">django_openidconsumer</span></tt> uses the <a class="reference" href="http://www.openidenabled.com/openid/libraries/python/">python-openid library</a>, which must be
installed separately somewhere on the Python path. You should install the 1.2.0
&#8220;combo&#8221; package which includes the <tt class="docutils literal"><span class="pre">yadis</span></tt> and <tt class="docutils literal"><span class="pre">urljr</span></tt> libraries.</p>
<p>The package also depends on the availability of Django&#8217;s <a class="reference" href="http://www.djangoproject.com/documentation/sessions/">session support</a>.</p>
</div>
<div class="section">
<h2><a id="installation">Installation</a></h2>
<p>Having ensured that both the <tt class="docutils literal"><span class="pre">python-openid</span></tt> library and the <tt class="docutils literal"><span class="pre">django_openidconsumer</span></tt> package are available on your Python path, you can
add OpenID consumer support to an application by doing the following:</p>
<ol class="arabic">
<li><p class="first">Put <tt class="docutils literal"><span class="pre">django_openidconsumer</span></tt> in your <tt class="docutils literal"><span class="pre">INSTALLED_APPS</span></tt> setting.</p>
</li>
<li><p class="first">Run the command <tt class="docutils literal"><span class="pre">manage.py</span> <span class="pre">syncdb</span></tt> to create the necessary tables.</p>
</li>
<li><p class="first">Add <tt class="docutils literal"><span class="pre">django_openidconsumer.middleware.OpenIDMiddleware</span></tt> to your list
of <tt class="docutils literal"><span class="pre">MIDDLEWARE_CLASSES</span></tt>, somewhere after the Session middleware.</p>
</li>
<li><p class="first">Add the following views to your urlconf:</p>
<pre class="literal-block">
(r'^openid/$', 'django_openidconsumer.views.begin'),
(r'^openid/complete/$', 'django_openidconsumer.views.complete'),
(r'^openid/signout/$', 'django_openidconsumer.views.signout'),
</pre>
</li>
</ol>
<p>You will then be able to browse to <tt class="docutils literal"><span class="pre">example.com/openid/</span></tt> and sign in using
an OpenID.</p>
</div>
<div class="section">
<h2><a id="using-the-openid-middleware">Using the OpenID middleware</a></h2>
<p>With the Middleware installed, your views will have access to the user&#8217;s OpenID
as the <tt class="docutils literal"><span class="pre">request.openid</span></tt> property. This will be <tt class="docutils literal"><span class="pre">None</span></tt> if the user has not
yet authenticated; otherwise it will be a <tt class="docutils literal"><span class="pre">django_openidconsumer.util.OpenID</span></tt>
instance.</p>
<p>If you want the user&#8217;s OpenID as a string, call the <tt class="docutils literal"><span class="pre">str()</span></tt> builtin on the
OpenID instance:</p>
<pre class="literal-block">
def example_view(request):
if request.openid:
return HttpResponse(&quot;OpenID is %s&quot; % escape(str(request.openid)))
else:
return HttpResponse(&quot;No OpenID&quot;)
</pre>
<p>Users can sign in with more than one OpenID. This is supported by the
<tt class="docutils literal"><span class="pre">request.openids</span></tt> property, which is a list of <tt class="docutils literal"><span class="pre">OpenID</span></tt> objects in the order
in which they were authenticated. <tt class="docutils literal"><span class="pre">request.openid</span></tt> merely returns the last
item in this list.</p>
</div>
<div class="section">
<h2><a id="using-simple-registration">Using simple registration</a></h2>
<p>Simple registration (or <a class="reference" href="http://openid.net/specs/openid-simple-registration-extension-1_0.html">sreg</a>) is an extension to the OpenID specification
that allows you to request extra details about a user from their OpenID
provider. It is frequently used to pre-populate registration forms with
information such as the user&#8217;s name, e-mail address or date of birth.</p>
<p>Be aware that not all OpenID providers support sreg, and there is no guarantee
that the information you have requested will be returned. Simple registration
should be used as a convenience for your users rather than as a required step in
your authentication process.</p>
<p>Available simple registration fields are <tt class="docutils literal"><span class="pre">nickname</span></tt>, <tt class="docutils literal"><span class="pre">email</span></tt>, <tt class="docutils literal"><span class="pre">fullname</span></tt>,
<tt class="docutils literal"><span class="pre">dob</span></tt>, <tt class="docutils literal"><span class="pre">gender</span></tt>, <tt class="docutils literal"><span class="pre">postcode</span></tt>, <tt class="docutils literal"><span class="pre">country</span></tt>, <tt class="docutils literal"><span class="pre">language</span></tt> and <tt class="docutils literal"><span class="pre">timezone</span></tt>.
Full details are available in the <a class="reference" href="http://openid.net/specs/openid-simple-registration-extension-1_0.html">spec</a>.</p>
<p>To request this information, pass the fields that you wish to retrieve as an
additional <tt class="docutils literal"><span class="pre">sreg</span></tt> argument to the <tt class="docutils literal"><span class="pre">django_openidconsumer.views.begin</span></tt> view:</p>
<pre class="literal-block">
(r'^openid/$', 'django_openidconsumer.views.begin', {
'sreg': 'email,nickname'
}),
</pre>
<p>Any simple registration fields that are returned will be available in a
dictionary as the <tt class="docutils literal"><span class="pre">sreg</span></tt> property of the OpenID object:</p>
<pre class="literal-block">
def example_sreg(request):
if request.openid and request.openid.sreg.has_key('email'):
return HttpResponse(&quot;Your e-mail address is: %s&quot; % escape(
request.openid.sreg['email']
))
else:
return HttpResponse(&quot;No e-mail address&quot;)
</pre>
</div>
<div class="section">
<h2><a id="customisation">Customisation</a></h2>
<p><tt class="docutils literal"><span class="pre">django_openidconsumer</span></tt> uses two templates:</p>
<dl class="docutils">
<dt><tt class="docutils literal"><span class="pre">openid_signin.html</span></tt></dt>
<dd>The form presented to the user when they sign in.</dd>
<dt><tt class="docutils literal"><span class="pre">openid_failure.html</span></tt></dt>
<dd>The template used to display an error message when something goes wrong.</dd>
</dl>
<p>You can over-ride the default templates by creating templates of the same name
and placing them somewhere on your template path. You can find the example
templates in the <tt class="docutils literal"><span class="pre">django_openidconsumer/templates</span></tt> directory.</p>
<p>The OpenID specification strongly recommends that any OpenID registration form
has a <tt class="docutils literal"><span class="pre">name</span></tt> attribute of <tt class="docutils literal"><span class="pre">openid_url</span></tt> to aid browser autocompletion, and
displays the <a class="reference" href="http://openid.net/login-bg.gif">OpenID logo</a> inline in the form field using the following CSS:</p>
<pre class="literal-block">
input.openid {
background: url(/path/to/login-bg.gif) no-repeat;
background-position: 0 50%;
padding-left: 16px;
}
</pre>
<p>By default, the package expects the <tt class="docutils literal"><span class="pre">django_openidconsumer.views.complete</span></tt>
view to be located at <tt class="docutils literal"><span class="pre">/openid/complete/</span></tt>. This is the view that the OpenID
provider will redirect the user to after they have authenticated. If you want to
put it somewhere else you can either pass an extra <tt class="docutils literal"><span class="pre">redirect_to</span></tt> argument to
<tt class="docutils literal"><span class="pre">django_openidconsumer.views.begin</span></tt> or add an <tt class="docutils literal"><span class="pre">OPENID_REDIRECT_TO</span></tt> setting
to <tt class="docutils literal"><span class="pre">settings.py</span></tt>.</p>
<p>You can pass a <tt class="docutils literal"><span class="pre">?next=</span></tt> query string argument containing a relative URL to
the <tt class="docutils literal"><span class="pre">begin</span></tt> view to control where the user will be redirected to having
returned to your site. You can also set the default redirection location
using the <tt class="docutils literal"><span class="pre">OPENID_REDIRECT_NEXT</span></tt> setting; if you do set set a default the user
will be redirected to your homepage.</p>
</div>
<div class="section">
<h2><a id="i-names">i-names</a></h2>
<p><a class="reference" href="http://www.inames.net/">i-names</a> are part of the OpenID 2.0 specification, which is currently being
developed. They are supported by the python-openid library, and hence are also
supported by <tt class="docutils literal"><span class="pre">django_openidconsumer</span></tt>. You can tell if an OpenID is an i-name
by checking the <tt class="docutils literal"><span class="pre">request.openid.is_iname</span></tt> property.</p>
<p>If you wish to disable i-name support, you can do so by adding the following to
your <tt class="docutils literal"><span class="pre">settings.py</span></tt>:</p>
<pre class="literal-block">
OPENID_DISALLOW_INAMES = True
</pre>
</div>
================
OpenID in Django
================
The ``django_openidconsumer`` package contains all of the code needed to set up
your Django application as an OpenID consumer. You can use it to allow OpenID
users to sign in to your site without having to create a new username and
password.
Overview
========
The OpenID consumer system consists of:
* Views for you to hook in to your application.
* Database models implementing the persistence layer of an OpenID consumer.
* Middleware that makes ``request.openid`` and ``request.openids``
properties available to your application views.
Dependencies
============
``django_openidconsumer`` uses the `python-openid library`_, which must be
installed separately somewhere on the Python path. You should install the 1.2.0
"combo" package which includes the ``yadis`` and ``urljr`` libraries.
The package also depends on the availability of Django's `session support`_.
.. _python-openid library: http://www.openidenabled.com/openid/libraries/python/
.. _session support: http://www.djangoproject.com/documentation/sessions/
Installation
============
Having ensured that both the ``python-openid`` library and the ``django_openidconsumer`` package are available on your Python path, you can
add OpenID consumer support to an application by doing the following:
1. Put ``django_openidconsumer`` in your ``INSTALLED_APPS`` setting.
2. Run the command ``manage.py syncdb`` to create the necessary tables.
3. Add ``django_openidconsumer.middleware.OpenIDMiddleware`` to your list
of ``MIDDLEWARE_CLASSES``, somewhere after the Session middleware.
4. Add the following views to your urlconf::
(r'^openid/$', 'django_openidconsumer.views.begin'),
(r'^openid/complete/$', 'django_openidconsumer.views.complete'),
(r'^openid/signout/$', 'django_openidconsumer.views.signout'),
You will then be able to browse to ``example.com/openid/`` and sign in using
an OpenID.
Using the OpenID middleware
===========================
With the Middleware installed, your views will have access to the user's OpenID
as the ``request.openid`` property. This will be ``None`` if the user has not
yet authenticated; otherwise it will be a ``django_openidconsumer.util.OpenID``
instance.
If you want the user's OpenID as a string, call the ``str()`` builtin on the
OpenID instance::
def example_view(request):
if request.openid:
return HttpResponse("OpenID is %s" % escape(str(request.openid)))
else:
return HttpResponse("No OpenID")
Users can sign in with more than one OpenID. This is supported by the
``request.openids`` property, which is a list of ``OpenID`` objects in the order
in which they were authenticated. ``request.openid`` merely returns the last
item in this list.
Using simple registration
=========================
Simple registration (or `sreg`_) is an extension to the OpenID specification
that allows you to request extra details about a user from their OpenID
provider. It is frequently used to pre-populate registration forms with
information such as the user's name, e-mail address or date of birth.
.. _sreg: http://openid.net/specs/openid-simple-registration-extension-1_0.html
Be aware that not all OpenID providers support sreg, and there is no guarantee
that the information you have requested will be returned. Simple registration
should be used as a convenience for your users rather than as a required step in
your authentication process.
Available simple registration fields are ``nickname``, ``email``, ``fullname``,
``dob``, ``gender``, ``postcode``, ``country``, ``language`` and ``timezone``.
Full details are available in the `spec`_.
.. _spec: http://openid.net/specs/openid-simple-registration-extension-1_0.html
To request this information, pass the fields that you wish to retrieve as an
additional ``sreg`` argument to the ``django_openidconsumer.views.begin`` view::
(r'^openid/$', 'django_openidconsumer.views.begin', {
'sreg': 'email,nickname'
}),
Any simple registration fields that are returned will be available in a
dictionary as the ``sreg`` property of the OpenID object::
def example_sreg(request):
if request.openid and request.openid.sreg.has_key('email'):
return HttpResponse("Your e-mail address is: %s" % escape(
request.openid.sreg['email']
))
else:
return HttpResponse("No e-mail address")
Customisation
=============
``django_openidconsumer`` uses two templates:
``openid_signin.html``
The form presented to the user when they sign in.
``openid_failure.html``
The template used to display an error message when something goes wrong.
You can over-ride the default templates by creating templates of the same name
and placing them somewhere on your template path. You can find the example
templates in the ``django_openidconsumer/templates`` directory.
The OpenID specification strongly recommends that any OpenID registration form
has a ``name`` attribute of ``openid_url`` to aid browser autocompletion, and
displays the `OpenID logo`_ inline in the form field using the following CSS::
input.openid {
background: url(/path/to/login-bg.gif) no-repeat;
background-position: 0 50%;
padding-left: 16px;
}
.. _OpenID logo: http://openid.net/login-bg.gif
By default, the package expects the ``django_openidconsumer.views.complete``
view to be located at ``/openid/complete/``. This is the view that the OpenID
provider will redirect the user to after they have authenticated. If you want to
put it somewhere else you can either pass an extra ``redirect_to`` argument to
``django_openidconsumer.views.begin`` or add an ``OPENID_REDIRECT_TO`` setting
to ``settings.py``.
You can pass a ``?next=`` query string argument containing a relative URL to
the ``begin`` view to control where the user will be redirected to having
returned to your site. You can also set the default redirection location
using the ``OPENID_REDIRECT_NEXT`` setting; if you do set set a default the user
will be redirected to your homepage.
i-names
=======
`i-names`_ are part of the OpenID 2.0 specification, which is currently being
developed. They are supported by the python-openid library, and hence are also
supported by ``django_openidconsumer``. You can tell if an OpenID is an i-name
by checking the ``request.openid.is_iname`` property.
.. _i-names: http://www.inames.net/
If you wish to disable i-name support, you can do so by adding the following to
your ``settings.py``::
OPENID_DISALLOW_INAMES = True
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