Source

django-publicauth / publicauth / backends / openid.py

from __future__ import absolute_import 

from openid.consumer import consumer, discover
from openid.extensions.sreg import SRegRequest, SRegResponse
from openid.extensions.ax import FetchRequest, AttrInfo, FetchResponse

from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.contrib import auth
from django import forms

from annoying.exceptions import Redirect

from publicauth.backends import BaseBackend
from publicauth.utils import str_to_class
from publicauth import settings


class OpenIDBackend(BaseBackend):

    def begin(self, request, data):
        openid_url = data['openid_url'].strip()
        if not openid_url.startswith("http"):
            openid_url = "http://%s" % openid_url
        return_url = request.build_absolute_uri(reverse('publicauth-social-complete', args=[self.provider]))
        request.session['openid_return_to'] = return_url
        client = consumer.Consumer(request.session, None)

        try:
            openid_request = client.begin(openid_url)
            sreg_extra = [i for i in self.PROFILE_MAPPING]
            sreg = SRegRequest(required=sreg_extra)
            openid_request.addExtension(sreg)
            ax_msg = FetchRequest()
            for detail in self.PROFILE_MAPPING:
                ax_msg.add(AttrInfo(settings.AX_URIS[detail], required=True))
            openid_request.addExtension(ax_msg)

            redirect_url = openid_request.redirectURL(realm='http://' + request.get_host(), return_to=return_url)
            raise Redirect(redirect_url)

        except discover.DiscoveryFailure:
            request.flash['error'] = _('Could not find OpenID server')
            raise Redirect('publicauth-social-login')


    def validate_response(self, request):
        """
        Validate response from OpenID server.
        Set identity in case of successfull validation.
        """
        client = consumer.Consumer(request.session, None)
        data = request.GET.copy()
        data.update(request.POST)

        try:
            resp = client.complete(data, request.session['openid_return_to'])
        except KeyError:
            request.flash['error'] = _('Invalid response received from OpenID server, please start the authentication process again')
            raise Redirect('publicauth-social-login')
        if resp.status == consumer.CANCEL:
            request.flash['warn'] = _('You have cancelled OpenID authentication')
            raise Redirect('publicauth-social-login')
        elif resp.status == consumer.FAILURE:
            request.flash['error'] =  _('OpenID authentication failed. Reason: %s') % resp.message
            raise Redirect('publicauth-social-login')
        elif resp.status == consumer.SUCCESS:
            self.set_identity(resp.identity_url)
            del request.session['openid_return_to']
            return resp

    def complete(self, request, response):
        extra = self.get_extra_data(response)
        data = self.set_profile_fields(request, extra)
        request.session['extra'] = data
        request.session['identity'] = self.get_identity()
        raise Redirect('publicauth-social-extra', self.provider)

    def get_extra_data(self, resp):
        return SRegResponse.fromSuccessResponse(resp)