from django import newforms as forms
from openid.consumer.discover import discover, DiscoveryFailure
from openid.fetchers import HTTPFetchingError
from openid.yadis import xri
def identifierScheme(identifier):
"""Wrap openid.yadis.xri.identifierScheme to keep URI/URL consistent."""
scheme = xri.identifierScheme(identifier)
if scheme == 'XRI':
return scheme
return 'URL'
class OpenIDField(forms.CharField):
"""Field to normalize and validate an OpenID.
Adds 'http://' prefix to URLs that don't have a scheme, appends trailing '/'
if no path is provided, strips URL fragments and follows HTTP redirects.
Strips 'xri://' prefix from XRIs.
http://openid.net/specs/openid-authentication-2_0.html#normalization
"""
default_error_messages = {
'discovery': u"This %s doesn't appear to be an OpenID.",
'invalid': u'Enter a valid OpenID.',
'invalid_link': u'This URL appears to be a broken link.',
'required': u'Enter an OpenID.'
}
def __init__(self, max_length=255, *args, **kwargs):
super(OpenIDField, self).__init__(max_length, *args, **kwargs)
def clean(self, value):
value = super(OpenIDField, self).clean(value)
if value in forms.fields.EMPTY_VALUES:
return u''
scheme = identifierScheme(value)
if scheme == 'XRI' and value.startswith('xri://'):
value = value[6:]
try:
claimed_id, endpoints = discover(value)
except DiscoveryFailure:
# resource not found
raise forms.ValidationError(self.error_messages['invalid_link'])
except HTTPFetchingError:
# server not found or invalid URL
raise forms.ValidationError(self.error_messages['invalid'])
else:
# valid URL/XRI with no OpenID endpoints
if not endpoints:
raise forms.ValidationError(
self.error_messages['discovery'] % scheme
)
self.endpoints = endpoints
return claimed_id
def widget_attrs(self, widget):
# CSS hook for http://openid.net/logos/
return {'class': 'openid'}
Comments