from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden from django import forms from django.template import loader, RequestContext from django.utils.html import escape from django.contrib.sites.models import Site from zilbo.common.openid.utils import getStore from zilbo.common.openid.models import AuthURL from django.contrib.auth.models import User from django.contrib.auth import login from django.conf import settings from random import choice #from openid.consumer.consumer import Consumer from openid.consumer import consumer from yadis.discover import DiscoveryFailure from urljr.fetchers import HTTPFetchingError class OpenIDFailure(Exception): "Something has gone wrong with the OpenID setup" pass def get_session(request): return { 'id': request.session.session_key } class OpenIDManipulator (forms.Manipulator): def __init__ (self): self.fields = (forms.TextField (field_name="openid_url", length=30, maxlength=50, is_required=True),) def openid_form (request, template_name = None, template_loader=loader, extra_lookup_kwargs={}, extra_context=None, context_processors=None, header={} ): if extra_context is None: extra_context = {} manipulator = OpenIDManipulator () errors = dict () if request.POST: new_data = request.POST.copy () openid_url = request.POST['openid_url'] # store = getStore() oidconsumer = consumer.Consumer( store= getStore(), session = get_session(request)) if not openid_url: errors['openid_url'] = ['You must enter an OpenID URL.'] if len (errors) == 0: try: req = oidconsumer.begin(openid_url) except HTTPFetchingError, exc: fmt = 'Error retrieving identity URL: %s' % ( escape(str(exc.why))) try: errors['openid_url'] = fmt % (escape (openid_url),) except TypeError: errors['openid_url'] = ["Error retrieving identity URL"] except DiscoveryFailure, exc: fmt = 'Error retrieving identity URL: %s' % ( escape(str(exc[0]))) try: errors['openid_url'] = fmt % (escape (openid_url),) except TypeError: errors['openid_url'] = ["Error retrieving identity URL"] except AttributeError: fmt = 'Error retrieving identity URL: %s' % ( escape(openid_url )) try: errors['openid_url'] = [fmt ] except TypeError: errors['openid_url'] = ["Error retrieving identity URL"] else: if req is None: fmt = 'No OpenID services found for %s' % ( escape(openid_url),) errors['openid_url'] = fmt % (escape (openid_url),) else: print req site = Site.objects.get_current() trust_root = "http://%s" % site.domain # trust_root = "http://localhost:8080" return_to = "%s/openid/process/%s/" % ( trust_root , req.token ) #return_to = "%s/openid/process/" % ( trust_root ) req.addExtensionArg( 'sreg','required', 'nickname,email') req.addExtensionArg( 'sreg','optional', 'fullname') req.addExtensionArg( 'sreg','policy_url', 'http://%s/privacy/' % site.domain ) redirect_url = req.redirectURL(trust_root, return_to) #print redirect_url return HttpResponseRedirect (redirect_url) else: new_data = {} errors = new_data = {} form = forms.FormWrapper (manipulator, new_data, errors) if not template_name: template_name = "openid/openid.html" t = template_loader.get_template(template_name) c = RequestContext(request, { 'form':form }, context_processors) response = HttpResponse(t.render(c)) if header != None: for key, value in header.items(): response[key] = value return response def make_random_userid( prefix='openid:',length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'): tries = 1000 while tries > 0 : trial = "%s%s" % ( prefix, ''.join( [choice( allowed_chars) for i in range(length)] ) ) try: User.objects.get( username= trial ) tries -= 1 except User.DoesNotExist: return trial raise OpenIDFailure("too Many Tries to create a UserID.. giving up") def process (request, token=None, template_name = None, template_loader=loader, extra_context=None, context_processors=None ): if extra_context is None: extra_context = {} oidconsumer = consumer.GenericConsumer( store= getStore()) try: info = oidconsumer.complete( request.GET, token ) except AttributeError: return HttpResponseForbidden("invalid token") auth_failed = True if info.status == consumer.FAILURE and info.identity_url: # In the case of failure, if info is non-None, it is the # URL that we were verifying. We include it in the error # message to help the user figure out what happened. fmt = "Verification of %s failed." message = fmt % (escape(info.identity_url),) elif info.status == consumer.SUCCESS: # Success means that the transaction completed without # error. If info is None, it means that the user cancelled # the verification. css_class = 'alert' # This is a successful verification attempt. If this # was a real application, we would do our login, # comment posting, etc. here. fmt = "You have successfully verified %s as your identity." message = fmt % (escape(info.identity_url),) args = info.extensionResponse( 'sreg' ) authUser = None try: authUser = AuthURL.objects.get( auth_url = info.identity_url ) except AuthURL.DoesNotExist: email=None first="" last="" if args.has_key('email'): email = args['email'].strip().lower() try: fail = User.objects.get( email = email ) message = "a user with that email address already exists" except User.DoesNotExist: if args.has_key('fullname'): try: (first,last) = args['fullname'].split(" ", 1 ) except ValueError: first = args['fullname'] last = "" if args.has_key('nickname'): try: fail = User.objects.get(username = args['nickname']) except User.DoesNotExist: u = User(username = args['nickname'], first_name = first, last_name = last, email= email, password = User.objects.make_random_password() ) u.save() else: nickname = make_random_userid( '%s_' % args['nickname'] ) u = User(username = nickname, first_name = first, last_name = last, email= email, password = User.objects.make_random_password() ) u.save() else: nickname = make_random_userid( 'openid:' ) u = User(username = nickname, first_name = first, last_name = last, email= email, password = User.objects.make_random_password() ) u.save() authUser = AuthURL( user = u, auth_url = info.identity_url ) authUser.save() except: message = "a user with that email address already exists" else: message = "We need a email address" if authUser: u = authUser.user u.backend = settings.AUTHENTICATION_BACKENDS[0] login( request, u ) request.user = u auth_failed = False elif info.status == consumer.CANCEL: # cancelled message = 'Verification cancelled' else: # Either we don't understand the code or there is no # openid_url included with the error. Give a generic # failure message. The library should supply debug # information in a log. # print request message = 'Verification failed.' if auth_failed: manipulator = OpenIDManipulator () errors = dict () errors['openid_url'] = [ escape( message)] new_data = {'openid_url': info.identity_url } form = forms.FormWrapper (manipulator, new_data, errors) if not template_name: template_name = "openid/openid.html" t = template_loader.get_template(template_name) c = RequestContext(request, { 'form':form }, context_processors) return HttpResponse(t.render(c)) request.user.message_set.create( message=message ) return HttpResponseRedirect ('/')