offline avatar offline committed 71953ab

application renamed to publicauth

Comments (0)

Files changed (44)

 Персональная страница проекта:
 
-http://bitbucket.org/offline/django-openauth/
+http://bitbucket.org/offline/django-publicauth/
 
 Проект имеет зависимости от следующих продуктов:
 
 hg+https://bitbucket.org/offline/django-annoying/#egg=django-annoying
-hg+https://bitbucket.org/offline/django-confirmation/#egg=django-confirmation
-hg+https://bitbucket.org/offline/django-flashcookie/#egg=django-flashcookie
-hg+https://bitbucket.org/offline/django-notify/#egg=django-notify
 python-openid
 

openauth/__init__.py

-from django.contrib.auth.models import User
-
-from openauth.models import SocialID
-from openauth import settings
-from openauth import lang
-
-
-class SocialBackend(object):
-    """
-    Add this Authentication Backend to 
-    AUTHENTICATION_BACKENDS tuple in your settings.py
-    """
-
-    def get_user(self, user_id):
-        try:
-            return User.objects.get(pk=user_id)
-        except User.DoesNotExist:
-            return None
-
-    def authenticate(self, identity=None, provider=None):
-        """
-        Authenticate user by social identity.
-        """
-        if identity:
-            try:
-                user = SocialID.objects.get(identity=identity, provider=provider).user
-                return user
-            except SocialID.DoesNotExist:
-                return None
-        else:
-            return None

openauth/admin.py

-from django.contrib import admin
-
-from openauth.models import SocialID
-
-
-class SocialIDAdmin(admin.ModelAdmin):
-    list_display = ['user', 'provider', 'identity']
-
-admin.site.register(SocialID, SocialIDAdmin)
-

openauth/backends/__init__.py

-from django.utils.translation import ugettext as _
-from django.contrib.auth.models import User
-from django.contrib import auth
-from django.conf import settings as global_settings
-
-from annoying.exceptions import Redirect
-
-from openauth.models import SocialID
-from openauth.utils import str_to_class
-from openauth import settings
-
-
-class BaseBackend(object):
-
-    PROFILE_MAPPING = property(lambda self: getattr(global_settings, "%s_PROFILE_MAPPING" % self.provider.upper(), {}))
-
-    def __init__(self, provider):
-        self.provider = provider
-        self._identity = None
-
-    def set_identity(self, identity):
-        self._identity = identity
-
-    def get_identity(self):
-        return self._identity
-
-    def begin(self, request, data):
-        pass
-
-    def complete(self, request):
-        """
-        Login user if its identity already exists,
-        Create new user in case that no extra fields are required
-        and user with such identity doesnt exists.
-        Merge accounts if user already logged in and identity is new.
-        """
-        pass
-    
-    def attach_account(self, request, user):
-        """
-        Attach SocialID account to regular django 
-        account and then login user.
-        """
-        SocialID.objects.create(user=user, identity=self.get_identity(), provider=self.provider)
-        request.flash['success'] =  _('OpenId record was added to your account')
-        auth.authenticate(identity=self.get_identity(), provider=self.provider)
-        auth.login(request, user)
-        raise Redirect(global_settings.LOGIN_REDIRECT_URL)
-
-    def login_user(self, request):
-        if settings.SOCIALID_ACTIVATION_REQUIRED and not request.user.is_active:
-            request.flash['error'] =  _('Your account is not activated. Please activate it first.')
-            raise Redirect("/")
-        user = auth.authenticate(identity=self.get_identity(), provider=self.provider)
-        if user:
-            request.flash['success'] =  _('You have successfully authenticated')
-            auth.login(request, user)
-            raise Redirect(global_settings.LOGIN_REDIRECT_URL)
-
-    def set_profile_fields(self, request, extra):
-        """
-        Try to fetch extra data from provider, if this data is enough
-        to validate EXTRA_FORM then call save method of form class and 
-        login user.
-        """
-        data = {}
-
-        for field in self.PROFILE_MAPPING:
-            data.update(self.extract_data(extra, field))
-
-        form = str_to_class(settings.SOCIALID_EXTRA_FORM)(data, fields=self.PROFILE_MAPPING)
-        if form.is_valid():
-            form.save(self.get_identity(), self.provider)
-            user = auth.authenticate(identity=self.get_identity(), provider=self.provider)
-            if user:
-                auth.login(request, user)
-                try:
-                    redirect_url = request.session['next_url']
-                    del request.session['next_url']
-                except KeyError:
-                    redirect_url = global_settings.LOGIN_REDIRECT_URL
-                raise Redirect(redirect_url)
-        else:
-            return data
-
-    def extract_data(self, data, field):
-        try:
-            return {self.PROFILE_MAPPING[field][0]: data.get(field, '')}
-        except AttributeError:
-            return {self.PROFILE_MAPPING[field][0]: ''}
-
-    def validate_response(self, request):
-        pass

openauth/backends/facebook.py

-from __future__ import absolute_import 
-
-from django.utils.translation import ugettext as _
-from django.contrib import auth
-
-from annoying.exceptions import Redirect
-
-from openauth.backends import BaseBackend
-from openauth import settings
-
-
-class FacebookBackend(BaseBackend):
-    
-    def validate_response(self, request):
-        if not request.facebook.validate_cookie_signature(request.COOKIES):
-            request.flash['error'] = _('Invalid response received from facebook server, please start the authentication process again')
-            raise Redirect('openauth-social-login')
-        else:
-            uid = request.facebook.api_key
-            self.set_identity(int(request.COOKIES.get('%s_user' % uid)))
-
-    def complete(self, request, response):
-        extra_fields = [i for i in self.PROFILE_MAPPING]
-        extra = request.facebook.users.getInfo([self.get_identity()], extra_fields)[0]
-        self.set_profile_fields(request, extra)
-
-        request.session['identity'] = self.get_identity()
-
-        raise Redirect('openauth-social-extra', 'facebook')
-

openauth/backends/google.py

-from __future__ import absolute_import
-
-from openid.extensions.ax import FetchRequest, AttrInfo, FetchResponse
-
-from openauth.backends.openid import OpenIDBackend
-from openauth import settings
-
-
-class GoogleBackend(OpenIDBackend):
-    
-    def get_extra_data(self, resp):
-        return FetchResponse.fromSuccessResponse(resp)
-
-    def extract_data(self, data, field):
-        try:
-            return {self.PROFILE_MAPPING[field][0]: data.getSingle(settings.AX_URIS[field], '')}
-        except:
-            return {self.PROFILE_MAPPING[field]: ''}
-

openauth/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 openauth.backends import BaseBackend
-from openauth.utils import str_to_class
-from openauth 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('openauth-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('openauth-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('openauth-social-login')
-        if resp.status == consumer.CANCEL:
-            request.flash['warn'] = _('You have cancelled OpenID authentication')
-            raise Redirect('openauth-social-login')
-        elif resp.status == consumer.FAILURE:
-            request.flash['error'] =  _('OpenID authentication failed. Reason: %s') % resp.message
-            raise Redirect('openauth-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('openauth-social-extra', self.provider)
-
-    def get_extra_data(self, resp):
-        return SRegResponse.fromSuccessResponse(resp)
-

openauth/backends/twitter.py

-from __future__ import absolute_import 
-
-import urllib
-import urlparse
-
-from oauth.oauth import OAuthConsumer, OAuthToken, OAuthRequest, OAuthSignatureMethod_HMAC_SHA1
-
-from django.conf import settings as global_settings
-from django.utils.translation import ugettext as _
-from django.core.urlresolvers import reverse
-from django.contrib.auth.models import User
-from django.contrib import auth
-
-from annoying.exceptions import Redirect
-
-from openauth import settings
-from openauth.backends import BaseBackend
-from openauth.models import SocialID
-
-
-class TwitterBackend(BaseBackend):
-
-    CONSUMER_KEY = property(lambda self: getattr(global_settings, "%s_CONSUMER_KEY" % self.provider.upper()))
-    CONSUMER_SECRET = property(lambda self: getattr(global_settings, "%s_CONSUMER_SECRET" % self.provider.upper()))
-    REQUEST_TOKEN_URL = property(lambda self: getattr(global_settings, "%s_REQUEST_TOKEN_URL" % self.provider.upper()))
-    ACCESS_TOKEN_URL = property(lambda self: getattr(global_settings, "%s_ACCESS_TOKEN_URL" % self.provider.upper()))
-    AUTHORIZE_URL = property(lambda self: getattr(global_settings, "%s_AUTHORIZE_URL" % self.provider.upper()))
-
-    def begin(self, request, data):
-        consumer = OAuthConsumer(self.CONSUMER_KEY, self.CONSUMER_SECRET)
-        signature_method = OAuthSignatureMethod_HMAC_SHA1()
-        callback = request.build_absolute_uri(reverse('openauth-social-complete', args=[self.provider]))
-        oauth_req = OAuthRequest.from_consumer_and_token(consumer, callback=callback, http_url=self.REQUEST_TOKEN_URL)
-        oauth_req.sign_request(signature_method, consumer, None)
-        response = urllib.urlopen(oauth_req.to_url()).read()
-
-        token = OAuthToken.from_string(response) # instatiate token
-
-        oauth_req = OAuthRequest.from_consumer_and_token(consumer, token, http_url=self.AUTHORIZE_URL)
-        oauth_req.sign_request(signature_method, consumer, token)
-        raise Redirect(oauth_req.to_url())
-        
-
-    def complete(self, request, response):
-        signature_method = OAuthSignatureMethod_HMAC_SHA1()
-        data = request.GET.copy()
-        consumer = OAuthConsumer(self.CONSUMER_KEY, self.CONSUMER_SECRET)
-        oauth_token = data['oauth_token']
-        oauth_verifier = data['oauth_verifier']
-        oauth_req = OAuthRequest.from_consumer_and_token(consumer, http_url=self.ACCESS_TOKEN_URL)
-        oauth_req.set_parameter('oauth_token', oauth_token)
-        oauth_req.set_parameter('oauth_verifier', oauth_verifier)
-        oauth_req.sign_request(signature_method, consumer, None)
-        response = urllib.urlopen(oauth_req.to_url()).read()
-        self.set_identity(urlparse.parse_qs(response, keep_blank_values=False)['oauth_token'][0])
-        user = auth.authenticate(identity=self.get_identity(), provider=self.provider)
-
-        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('openauth-social-extra', self.provider)
-
-    def get_extra_data(self, response):
-        return urlparse.parse_qs(response, keep_blank_values=False)
-
-    def extract_data(self, data, field):
-        try:
-            return {self.PROFILE_MAPPING[field][0]: data.get(field, '')[0]}
-        except IndexError:
-            return {self.PROFILE_MAPPING[field][0]: ''}
-            
-

openauth/forms.py

-from django.utils.translation import ugettext as _
-from django.contrib.auth.models import User
-from django import forms
-
-from annoying.functions import get_object_or_None
-from annoying.decorators import autostrip
-
-from openauth.models import SocialID
-from openauth import settings
-
-
-class SocialIDExtraForm(forms.Form):
-    def __init__(self, *args, **kwargs):
-        """
-        Form with fields from backend PROFILE_MAPPINGS setting.
-        """
-        fields = kwargs.pop("fields", {})
-        for key, value in fields.values():
-            self.base_fields[key] = value
-        super(SocialIDExtraForm, self).__init__(*args, **kwargs)
-
-    def clean_username(self):
-        if get_object_or_None(User, username=self.cleaned_data['username']):
-            raise forms.ValidationError(_(u'This username name is already taken'))
-        return self.cleaned_data['username']
-
-
-    def save(self, identity, provider):
-        user = User.objects.create(username=self.cleaned_data['username'])
-        if settings.SOCIALID_ACTIVATION_REQUIRED:
-            user.is_active = False
-        user.save()
-        SocialID.objects.create(user=user, identity=identity, provider=provider)
-        return user
-
-SocialIDExtraForm = autostrip(SocialIDExtraForm)
-

openauth/lang.py

-from django.utils.translation import ugettext as _
-
-LOGOUT_BEFORE_REGISTRATION = _('You have to logout before new account registration')
-REGISTRATION_DISABLED = _('We are sorry, but registration is disabled. Come back later')
-PLEASE_ACTIVATE = _("You have successfully registered. Check your inbox for email with activation link.")
-ERROR_SENDING_MAIL = _('Unfortunately we could not send you email in current time. Please, try later')
-LOGIN_NOW = _("You have successfully registered. You can login now")
-MUST_ACTIVATE_FIRST = _("You must activate your account first. Please check you email for activation link")
-SUCCESSFULL_LOGIN = _('You have successfully logged-in')
-PLEASE_LOGOUT = _('Please logout before proceeding to this page')

openauth/models.py

-from django.db import models
-from django.contrib.auth.models import User
-
-
-class SocialID(models.Model):
-    user = models.ForeignKey(User)
-    identity = models.CharField(u'Social ID', max_length=255, unique=True)
-    provider = models.CharField(u'Social Authentication provider name', max_length=255)
-
-    def __unicode__(self):
-        return "%s -> %s" % (self.provider, self.identity)

openauth/settings.py

-import re
-
-from django import forms
-
-from annoying.functions import get_config
-
-
-### REGISTRATION_ALLOWED ###########################################################################
-# To disable registration, set it to False                                                         #
-REGISTRATION_ALLOWED = get_config("REGISTRATION_ALLOWED", True)                                    #
-####################################################################################################
-
-### SOCIALID_REGISTRATION_FORM #####################################################################
-# See REGISTRATION_FORM description above                                                          #
-SOCIALID_EXTRA_FORM = get_config("SOCIALID_EXTRA_FORM", "openauth.forms.SocialIDExtraForm")        #
-####################################################################################################
-
-### AX_URIS ########################################################################################
-# This dict contains mapping of SREG fields to AX uris, you probably don't need to change it       #
-# http://www.axschema.org/types/                                                                   #
-AX_URIS = {                                                                                        #
-    'nickname': 'http://axschema.org/namePerson/friendly',                                         #
-    'email': 'http://axschema.org/contact/email',                                                  #
-    'fullname': 'http://axschema.org/namePerson',                                                  #
-    'dob': 'http://axschema.org/birthDate',                                                        #
-    'gender': 'http://axschema.org/person/gender',                                                 #
-    'postcode': 'http://axschema.org/contact/postalCode/home',                                     #
-    'country': 'http://axschema.org/contact/country/home',                                         #
-    'language': 'http://axschema.org/pref/language',                                               #
-    'timezone': 'http://axschema.org/pref/timezone',                                               #
-}                                                                                                  #
-####################################################################################################
-
-### BACKEND_MAPPING ################################################################################
-BACKEND_MAPPING = get_config("BACKEND_MAPPING", {                                                  #
-    'openid': 'openauth.backends.openid.OpenIDBackend',                                            #
-    'google': 'openauth.backends.google.GoogleBackend',                                            #
-    'twitter': 'openauth.backends.twitter.TwitterBackend',                                         #
-    'facebook': 'openauth.backends.facebook.FacebookBackend',                                      #
-    }                                                                                              #
-)                                                                                                  #
-####################################################################################################
-
-REGISTRATION_DISABLED_REDIRECT = get_config("REGISTRATION_DISABLED_REDIRECT", "/")
-
-SOCIALID_ACTIVATION_REQUIRED = get_config("SOCIALID_ACTIVATION_REQUIRED", False)

openauth/templates/404.html

-{% extends "base.html" %}

openauth/templates/openauth/mail/registration.txt

-{% load i18n %}{% blocktrans %}Registration on {{ domain }}{% endblocktrans %}
-{% blocktrans %}Thanks for registration on {{ domain }}{% endblocktrans %}.
-{% blocktrans %}Please use following link to activate your account: {{ url }}{% endblocktrans %}

openauth/templates/openauth/mail/reset_password.txt

-Password restore on {{ domain }}
-
-Someone, hopefully you, requested password reset on {{ domain }}. 
-To approve request, please use following link: {{ url }}
-
-If you have not requested password reset or are not registered user of {{ domain }}, just ignore this email.

openauth/templates/openauth/social_extra.html

-{% extends 'base.html' %}
-{% load i18n %}
-
-{% block content %}
-<h2>{% trans "Registration with OpenID: last step" %}</h2>
-<p><label>{% trans "OpenID URL" %}:</label> {{ openid_url }}</p>
-<form method="post">
-    <formfield>
-        <legend>Регистрация через OpenID</legend>
-        <div class="wide">{{ form.as_p }}</div>
-        <p><input type="submit" value="{% trans "Submit" %}"/></p>
-    </formfield>
-</form>
-{% endblock %}

openauth/templates/openauth/social_login.html

-{% extends 'base.html' %}
-
-{% block content %}
-<form action="{% url openauth-social-login 'openid' %}" method="post" id="openid_login">
-    Openid URL
-    <input type="text" name="openid_url" />
-    <p><input type="submit" value="Continue"/></p>
-</form>
-
-<a href="{% url openauth-social-login 'google' %}?openid_url=https://www.google.com/accounts/o8/id">Google</a>
-<a href="{% url openauth-social-login 'twitter' %}">Twitter</a>
-
-
-<a href="#" onclick="return fb_login();" id="facebook">Login with facebook</a>
-
-<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script>
-<script type="text/javascript">
-    FB.init("{{ request.facebook.api_key }}", "{% url openauth-facebook-xdreceiver %}");
-
-    function fb_login() {
-        FB.Connect.requireSession(function(test) {
-            window.location = "{% url openauth-social-complete 'facebook' %}";
-        });
-        return false;
-    }
-</script>
-
-{% endblock %}
-
-

openauth/templates/openauth/xdreceiver.html

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-    <body>
-        <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
-    </body>
-</html>

openauth/urls.py

-from django.conf.urls.defaults import *
-from django.views.generic.simple import direct_to_template
-
-from openauth import views
-
-
-urlpatterns = patterns('',
-    url(r'^social-login/$', views.social_login, name='openauth-social-login'),
-    url(r'^social-login/(\w+)/$', views.social_login, name='openauth-social-login'),
-    url(r'^social-complete/(\w+)/$', views.social_complete, name='openauth-social-complete'),
-    url(r'^social-extra/(\w+)/$', views.social_extra, name='openauth-social-extra'),
-    url(r'^logout/$', views.logout, name='openauth-logout'),
-    url(r'^xdreceiver/$', direct_to_template, {'template': 'openauth/xdreceiver.html'}, name='openauth-facebook-xdreceiver'),
-)

openauth/utils.py

-import re
-
-from functools import wraps
-
-from django.core.exceptions import ImproperlyConfigured
-from django.utils.importlib import import_module
-from django.conf import global_settings
-from django.template.loader import get_template
-from django.template import Context
-from django.core.mail import send_mail
-
-from openauth import settings
-
-
-def parse_template(template_path, **kwargs):
-    """
-    Load and render template.
-
-    First line of template should contain the subject of email.
-    Return tuple with subject and content.
-    """
-
-    template = get_template(template_path)
-    context = Context(kwargs)
-    data = template.render(context).strip()
-    subject, content = re.split(r'\r?\n', data, 1)
-    return (subject.strip(), content.strip())
-
-
-def email_template(rcpt, template_path, **kwargs):
-    """
-    Load, render and email template.
-
-    **kwargs may contain variables for template rendering.
-    """
-
-    subject, content = parse_template(template_path, **kwargs)
-    count = send_mail(subject, content, global_settings.DEFAULT_FROM_EMAIL,
-                      [rcpt], fail_silently=True)
-    return bool(count)
-
-
-def str_to_class(str):
-    mod_str, cls_str = str.rsplit('.', 1)
-    mod = __import__(mod_str, globals(), locals(), ['foobar'])
-    cls = getattr(mod, cls_str)
-    return cls
-
-
-def uri_to_username(uri):
-    return re.sub('r[^0-9a-z]', '_', uri)
-
-
-def get_instance_from_path(path, *args, **kwargs):
-    """
-    Return an instance of a class, given the dotted
-    Python import path (as a string) to the backend class.
-
-    If the backend cannot be located (e.g., because no such module
-    exists, or because the module does not contain a class of the
-    appropriate name), ``django.core.exceptions.ImproperlyConfigured``
-    is raised.
-
-    """
-    i = path.rfind('.')
-    module, attr = path[:i], path[i+1:]
-    try:
-        mod = import_module(module)
-    except ImportError, e:
-        raise ImproperlyConfigured('Error loading registration backend %s: "%s"' % (module, e))
-    try:
-        backend_class = getattr(mod, attr)
-    except AttributeError:
-        raise ImproperlyConfigured('Module "%s" does not define a registration backend named "%s"' % (module, attr))
-
-    return backend_class(*args, **kwargs)
-
-def get_backend(name):
-    return get_instance_from_path(settings.BACKEND_MAPPING[name], name)

openauth/views.py

-from django.utils.translation import ugettext as _
-from django.shortcuts import redirect
-from django.http import Http404
-from django.contrib import auth 
-from django.conf import settings as global_settings
-
-from annoying.decorators import render_to
-
-from openauth.utils import str_to_class, get_backend
-from openauth import settings
-
-
-def logout(request):
-    auth.logout(request)
-    request.flash['success'] = _('You have been logged out')
-    return redirect("/")
-
-
-@render_to('openauth/social_login.html')
-def social_login(request, provider=None):
-    """
-    Display authentication form. This is also the first step
-    in social registration. The actual login is in social_complete 
-    function below.
-    """
-    if provider:
-        # merge data from POST and GET methods
-        data = request.GET.copy()
-        data.update(request.POST)
-
-        request.session['next_url'] = request.GET.get("next") or global_settings.LOGIN_REDIRECT_URL
-        
-        # start the authentication process 
-        backend = get_backend(provider)
-        backend.begin(request, data)
-
-    return {}
-
-
-def social_complete(request, provider):
-    """
-    Complete SocialID authorization process.
-    If SocialID was successfuly authenticated:
-     * if no user with such ID exists and current user is authenticated then
-       assign SocialID to this user.
-     * if user with such ID exists and current user is anonimouse then login 
-       as this user.
-     * if no user with such ID exists and user must fill extra fields, 
-       redirect him to registration form.
-    """
-    backend = get_backend(provider)
-    response = backend.validate_response(request)
-    if request.user.is_authenticated():
-        backend.login_user(request)
-        backend.attach_account(request, request.user)
-    else:
-        backend.login_user(request)
-        if not settings.REGISTRATION_ALLOWED:
-            request.flash['warning'] =  openauth.lang.REGISTRATION_DISABLED
-            return redirect(settings.REGISTRATION_DISABLED_REDIRECT)
-    backend.complete(request, response)
-
-
-@render_to('openauth/social_extra.html')
-def social_extra(request, provider):
-    """                                                
-    Handle registration of new user with extra data for profile
-    """                                                          
-    try:
-        identity = request.session['identity']
-    except KeyError:
-        raise Http404
-
-    if request.method == "POST":
-        form = str_to_class(settings.SOCIALID_EXTRA_FORM)(request.POST)
-        if form.is_valid():
-            user = form.save(identity, provider)
-            del request.session['identity']
-            user = auth.authenticate(identity=identity, provider=provider)
-            if user:
-                auth.login(request, user)
-                next_url = request.session['next_url']
-                del request.session['next_url']
-                return redirect(next_url)
-    else:
-        initial = request.session['extra']
-        form = str_to_class(settings.SOCIALID_EXTRA_FORM)(initial=initial)
-
-    return {'form': form}
-

publicauth/.project

+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>openauth</name>
+	<comment></comment>
+	<projects>
+		<project>confirmation</project>
+		<project>copz</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>

publicauth/.pydevproject

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/openauth</path>
+</pydev_pathproperty>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
+<path>/home/offline/Development/projects/django-confirmation</path>
+<path>/home/offline/Development/projects/django-notify</path>
+</pydev_pathproperty>
+</pydev_project>

publicauth/__init__.py

+from django.contrib.auth.models import User
+
+from publicauth.models import PublicID
+from publicauth import settings
+from publicauth import lang
+
+
+class PublicBackend(object):
+    """
+    Add this Authentication Backend to 
+    AUTHENTICATION_BACKENDS tuple in your settings.py
+    """
+
+    def get_user(self, user_id):
+        try:
+            return User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            return None
+
+    def authenticate(self, identity=None, provider=None):
+        """
+        Authenticate user by public identity.
+        """
+        if identity:
+            try:
+                user = PublicID.objects.get(identity=identity, provider=provider).user
+                return user
+            except PublicID.DoesNotExist:
+                return None
+        else:
+            return None

publicauth/admin.py

+from django.contrib import admin
+
+from publicauth.models import PublicID
+
+
+class PublicIDAdmin(admin.ModelAdmin):
+    list_display = ['user', 'provider', 'identity']
+admin.site.register(PublicID, PublicIDAdmin)
+

publicauth/backends/__init__.py

+from django.utils.translation import ugettext as _
+from django.contrib.auth.models import User
+from django.contrib import auth
+from django.conf import settings as global_settings
+
+from annoying.exceptions import Redirect
+
+from publicauth.models import PublicID
+from publicauth.utils import str_to_class
+from publicauth import settings
+
+
+class BaseBackend(object):
+
+    PROFILE_MAPPING = property(lambda self: getattr(global_settings, "%s_PROFILE_MAPPING" % self.provider.upper(), {}))
+
+    def __init__(self, provider):
+        self.provider = provider
+        self._identity = None
+
+    def set_identity(self, identity):
+        self._identity = identity
+
+    def get_identity(self):
+        return self._identity
+
+    def begin(self, request, data):
+        pass
+
+    def complete(self, request):
+        """
+        Login user if its identity already exists,
+        Create new user in case that no extra fields are required
+        and user with such identity doesnt exists.
+        Merge accounts if user already logged in and identity is new.
+        """
+        pass
+    
+    def attach_account(self, request, user):
+        """
+        Attach PublicID account to regular django 
+        account and then login user.
+        """
+        PublicID.objects.create(user=user, identity=self.get_identity(), provider=self.provider)
+        request.flash['success'] =  _('OpenId record was added to your account')
+        auth.authenticate(identity=self.get_identity(), provider=self.provider)
+        auth.login(request, user)
+        raise Redirect(global_settings.LOGIN_REDIRECT_URL)
+
+    def login_user(self, request):
+        if settings.PUBLICID_ACTIVATION_REQUIRED and not request.user.is_active:
+            request.flash['error'] =  _('Your account is not activated. Please activate it first.')
+            raise Redirect("/")
+        user = auth.authenticate(identity=self.get_identity(), provider=self.provider)
+        if user:
+            request.flash['success'] =  _('You have successfully authenticated')
+            auth.login(request, user)
+            raise Redirect(global_settings.LOGIN_REDIRECT_URL)
+
+    def set_profile_fields(self, request, extra):
+        """
+        Try to fetch extra data from provider, if this data is enough
+        to validate EXTRA_FORM then call save method of form class and 
+        login user.
+        """
+        data = {}
+
+        for field in self.PROFILE_MAPPING:
+            data.update(self.extract_data(extra, field))
+
+        form = str_to_class(settings.PUBLICID_EXTRA_FORM)(data, fields=self.PROFILE_MAPPING)
+        if form.is_valid():
+            form.save(self.get_identity(), self.provider)
+            user = auth.authenticate(identity=self.get_identity(), provider=self.provider)
+            if user:
+                auth.login(request, user)
+                try:
+                    redirect_url = request.session['next_url']
+                    del request.session['next_url']
+                except KeyError:
+                    redirect_url = global_settings.LOGIN_REDIRECT_URL
+                raise Redirect(redirect_url)
+        else:
+            return data
+
+    def extract_data(self, data, field):
+        try:
+            return {self.PROFILE_MAPPING[field][0]: data.get(field, '')}
+        except AttributeError:
+            return {self.PROFILE_MAPPING[field][0]: ''}
+
+    def validate_response(self, request):
+        pass

publicauth/backends/facebook.py

+from __future__ import absolute_import 
+
+from django.utils.translation import ugettext as _
+from django.contrib import auth
+
+from annoying.exceptions import Redirect
+
+from publicauth.backends import BaseBackend
+from publicauth import settings
+
+
+class FacebookBackend(BaseBackend):
+    
+    def validate_response(self, request):
+        if not request.facebook.validate_cookie_signature(request.COOKIES):
+            request.flash['error'] = _('Invalid response received from facebook server, please start the authentication process again')
+            raise Redirect('publicauth-social-login')
+        else:
+            uid = request.facebook.api_key
+            self.set_identity(int(request.COOKIES.get('%s_user' % uid)))
+
+    def complete(self, request, response):
+        extra_fields = [i for i in self.PROFILE_MAPPING]
+        extra = request.facebook.users.getInfo([self.get_identity()], extra_fields)[0]
+        self.set_profile_fields(request, extra)
+
+        request.session['identity'] = self.get_identity()
+
+        raise Redirect('publicauth-social-extra', 'facebook')
+

publicauth/backends/google.py

+from __future__ import absolute_import
+
+from openid.extensions.ax import FetchRequest, AttrInfo, FetchResponse
+
+from publicauth.backends.openid import OpenIDBackend
+from publicauth import settings
+
+
+class GoogleBackend(OpenIDBackend):
+    
+    def get_extra_data(self, resp):
+        return FetchResponse.fromSuccessResponse(resp)
+
+    def extract_data(self, data, field):
+        try:
+            return {self.PROFILE_MAPPING[field][0]: data.getSingle(settings.AX_URIS[field], '')}
+        except:
+            return {self.PROFILE_MAPPING[field]: ''}
+

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)
+

publicauth/backends/twitter.py

+from __future__ import absolute_import 
+
+import urllib
+import urlparse
+
+from oauth.oauth import OAuthConsumer, OAuthToken, OAuthRequest, OAuthSignatureMethod_HMAC_SHA1
+
+from django.conf import settings as global_settings
+from django.utils.translation import ugettext as _
+from django.core.urlresolvers import reverse
+from django.contrib.auth.models import User
+from django.contrib import auth
+
+from annoying.exceptions import Redirect
+
+from publicauth import settings
+from publicauth.backends import BaseBackend
+from publicauth.models import PublicID
+
+
+class TwitterBackend(BaseBackend):
+
+    CONSUMER_KEY = property(lambda self: getattr(global_settings, "%s_CONSUMER_KEY" % self.provider.upper()))
+    CONSUMER_SECRET = property(lambda self: getattr(global_settings, "%s_CONSUMER_SECRET" % self.provider.upper()))
+    REQUEST_TOKEN_URL = property(lambda self: getattr(global_settings, "%s_REQUEST_TOKEN_URL" % self.provider.upper()))
+    ACCESS_TOKEN_URL = property(lambda self: getattr(global_settings, "%s_ACCESS_TOKEN_URL" % self.provider.upper()))
+    AUTHORIZE_URL = property(lambda self: getattr(global_settings, "%s_AUTHORIZE_URL" % self.provider.upper()))
+
+    def begin(self, request, data):
+        consumer = OAuthConsumer(self.CONSUMER_KEY, self.CONSUMER_SECRET)
+        signature_method = OAuthSignatureMethod_HMAC_SHA1()
+        callback = request.build_absolute_uri(reverse('publicauth-social-complete', args=[self.provider]))
+        oauth_req = OAuthRequest.from_consumer_and_token(consumer, callback=callback, http_url=self.REQUEST_TOKEN_URL)
+        oauth_req.sign_request(signature_method, consumer, None)
+        response = urllib.urlopen(oauth_req.to_url()).read()
+
+        token = OAuthToken.from_string(response) # instatiate token
+
+        oauth_req = OAuthRequest.from_consumer_and_token(consumer, token, http_url=self.AUTHORIZE_URL)
+        oauth_req.sign_request(signature_method, consumer, token)
+        raise Redirect(oauth_req.to_url())
+        
+
+    def complete(self, request, response):
+        signature_method = OAuthSignatureMethod_HMAC_SHA1()
+        data = request.GET.copy()
+        consumer = OAuthConsumer(self.CONSUMER_KEY, self.CONSUMER_SECRET)
+        oauth_token = data['oauth_token']
+        oauth_verifier = data['oauth_verifier']
+        oauth_req = OAuthRequest.from_consumer_and_token(consumer, http_url=self.ACCESS_TOKEN_URL)
+        oauth_req.set_parameter('oauth_token', oauth_token)
+        oauth_req.set_parameter('oauth_verifier', oauth_verifier)
+        oauth_req.sign_request(signature_method, consumer, None)
+        response = urllib.urlopen(oauth_req.to_url()).read()
+        self.set_identity(urlparse.parse_qs(response, keep_blank_values=False)['oauth_token'][0])
+        user = auth.authenticate(identity=self.get_identity(), provider=self.provider)
+
+        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, response):
+        return urlparse.parse_qs(response, keep_blank_values=False)
+
+    def extract_data(self, data, field):
+        try:
+            return {self.PROFILE_MAPPING[field][0]: data.get(field, '')[0]}
+        except IndexError:
+            return {self.PROFILE_MAPPING[field][0]: ''}
+            
+

publicauth/forms.py

+from django.utils.translation import ugettext as _
+from django.contrib.auth.models import User
+from django import forms
+
+from annoying.functions import get_object_or_None
+from annoying.decorators import autostrip
+
+from publicauth.models import PublicID
+from publicauth import settings
+
+
+class PublicIDExtraForm(forms.Form):
+    def __init__(self, *args, **kwargs):
+        """
+        Form with fields from backend PROFILE_MAPPINGS setting.
+        """
+        fields = kwargs.pop("fields", {})
+        for key, value in fields.values():
+            self.base_fields[key] = value
+        super(PublicIDExtraForm, self).__init__(*args, **kwargs)
+
+    def clean_username(self):
+        if get_object_or_None(User, username=self.cleaned_data['username']):
+            raise forms.ValidationError(_(u'This username name is already taken'))
+        return self.cleaned_data['username']
+
+    def save(self, identity, provider):
+        user = User.objects.create(username=self.cleaned_data['username'])
+        if settings.PUBLICID_ACTIVATION_REQUIRED:
+            user.is_active = False
+        user.save()
+        PublicID.objects.create(user=user, identity=identity, provider=provider)
+        return user
+
+PublicIDExtraForm = autostrip(PublicIDExtraForm)
+

publicauth/lang.py

+from django.utils.translation import ugettext as _
+
+LOGOUT_BEFORE_REGISTRATION = _('You have to logout before new account registration')
+REGISTRATION_DISABLED = _('We are sorry, but registration is disabled. Come back later')
+PLEASE_ACTIVATE = _("You have successfully registered. Check your inbox for email with activation link.")
+ERROR_SENDING_MAIL = _('Unfortunately we could not send you email in current time. Please, try later')
+LOGIN_NOW = _("You have successfully registered. You can login now")
+MUST_ACTIVATE_FIRST = _("You must activate your account first. Please check you email for activation link")
+SUCCESSFULL_LOGIN = _('You have successfully logged-in')
+PLEASE_LOGOUT = _('Please logout before proceeding to this page')

publicauth/models.py

+from django.db import models
+from django.contrib.auth.models import User
+
+
+class PublicID(models.Model):
+    user = models.ForeignKey(User)
+    identity = models.CharField(u'Public ID', max_length=255, unique=True)
+    provider = models.CharField(u'Public authentication provider name', max_length=255)
+
+    def __unicode__(self):
+        return "%s -> %s" % (self.provider, self.identity)

publicauth/settings.py

+import re
+
+from django import forms
+
+from annoying.functions import get_config
+
+
+### REGISTRATION_ALLOWED ###########################################################################
+# To disable registration, set it to False                                                         #
+REGISTRATION_ALLOWED = get_config("REGISTRATION_ALLOWED", True)                                    #
+####################################################################################################
+
+### PUBLICID_REGISTRATION_FORM #####################################################################
+# See REGISTRATION_FORM description above                                                          #
+PUBLICID_EXTRA_FORM = get_config("PUBLICID_EXTRA_FORM", "publicauth.forms.PublicIDExtraForm")      #
+####################################################################################################
+
+### AX_URIS ########################################################################################
+# This dict contains mapping of SREG fields to AX uris, you probably don't need to change it       #
+# http://www.axschema.org/types/                                                                   #
+AX_URIS = {                                                                                        #
+    'nickname': 'http://axschema.org/namePerson/friendly',                                         #
+    'email': 'http://axschema.org/contact/email',                                                  #
+    'fullname': 'http://axschema.org/namePerson',                                                  #
+    'dob': 'http://axschema.org/birthDate',                                                        #
+    'gender': 'http://axschema.org/person/gender',                                                 #
+    'postcode': 'http://axschema.org/contact/postalCode/home',                                     #
+    'country': 'http://axschema.org/contact/country/home',                                         #
+    'language': 'http://axschema.org/pref/language',                                               #
+    'timezone': 'http://axschema.org/pref/timezone',                                               #
+}                                                                                                  #
+####################################################################################################
+
+### BACKEND_MAPPING ################################################################################
+BACKEND_MAPPING = get_config("BACKEND_MAPPING", {                                                  #
+    'openid': 'publicauth.backends.openid.OpenIDBackend',                                          #
+    'google': 'publicauth.backends.google.GoogleBackend',                                          #
+    'twitter': 'publicauth.backends.twitter.TwitterBackend',                                       #
+    'facebook': 'publicauth.backends.facebook.FacebookBackend',                                    #
+    }                                                                                              #
+)                                                                                                  #
+####################################################################################################
+
+REGISTRATION_DISABLED_REDIRECT = get_config("REGISTRATION_DISABLED_REDIRECT", "/")
+
+PUBLICID_ACTIVATION_REQUIRED = get_config("PUBLICID_ACTIVATION_REQUIRED", False)

publicauth/templates/404.html

+{% extends "base.html" %}

publicauth/templates/openauth/mail/registration.txt

+{% load i18n %}{% blocktrans %}Registration on {{ domain }}{% endblocktrans %}
+{% blocktrans %}Thanks for registration on {{ domain }}{% endblocktrans %}.
+{% blocktrans %}Please use following link to activate your account: {{ url }}{% endblocktrans %}

publicauth/templates/openauth/mail/reset_password.txt

+Password restore on {{ domain }}
+
+Someone, hopefully you, requested password reset on {{ domain }}. 
+To approve request, please use following link: {{ url }}
+
+If you have not requested password reset or are not registered user of {{ domain }}, just ignore this email.

publicauth/templates/openauth/social_extra.html

+{% extends 'base.html' %}
+{% load i18n %}
+
+{% block content %}
+<h2>{% trans "Registration with OpenID: last step" %}</h2>
+<p><label>{% trans "OpenID URL" %}:</label> {{ openid_url }}</p>
+<form method="post">
+    <formfield>
+        <legend>Регистрация через OpenID</legend>
+        <div class="wide">{{ form.as_p }}</div>
+        <p><input type="submit" value="{% trans "Submit" %}"/></p>
+    </formfield>
+</form>
+{% endblock %}

publicauth/templates/openauth/social_login.html

+{% extends 'base.html' %}
+
+{% block content %}
+<form action="{% url openauth-social-login 'openid' %}" method="post" id="openid_login">
+    Openid URL
+    <input type="text" name="openid_url" />
+    <p><input type="submit" value="Continue"/></p>
+</form>
+
+<a href="{% url openauth-social-login 'google' %}?openid_url=https://www.google.com/accounts/o8/id">Google</a>
+<a href="{% url openauth-social-login 'twitter' %}">Twitter</a>
+
+
+<a href="#" onclick="return fb_login();" id="facebook">Login with facebook</a>
+
+<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script>
+<script type="text/javascript">
+    FB.init("{{ request.facebook.api_key }}", "{% url openauth-facebook-xdreceiver %}");
+
+    function fb_login() {
+        FB.Connect.requireSession(function(test) {
+            window.location = "{% url openauth-social-complete 'facebook' %}";
+        });
+        return false;
+    }
+</script>
+
+{% endblock %}
+
+

publicauth/templates/openauth/xdreceiver.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <body>
+        <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
+    </body>
+</html>

publicauth/urls.py

+from django.conf.urls.defaults import *
+from django.views.generic.simple import direct_to_template
+
+from publicauth import views
+
+
+urlpatterns = patterns('',
+    url(r'^begin/$', views.begin, name='publicauth-begin'),
+    url(r'^begin/(\w+)/$', views.begin, name='publicauth-begin'),
+    url(r'^complete/(\w+)/$', views.complete, name='publicauth-complete'),
+    url(r'^extra/(\w+)/$', views.extra, name='publicauth-extra'),
+    url(r'^logout/$', views.logout, name='publicauth-logout'),
+    url(r'^xdreceiver/$', direct_to_template, {'template': 'publicauth/xdreceiver.html'}, name='publicauth-facebook-xdreceiver'),
+)

publicauth/utils.py

+import re
+
+from functools import wraps
+
+from django.core.exceptions import ImproperlyConfigured
+from django.utils.importlib import import_module
+from django.conf import global_settings
+from django.template.loader import get_template
+from django.template import Context
+from django.core.mail import send_mail
+
+from publicauth import settings
+
+
+def parse_template(template_path, **kwargs):
+    """
+    Load and render template.
+
+    First line of template should contain the subject of email.
+    Return tuple with subject and content.
+    """
+
+    template = get_template(template_path)
+    context = Context(kwargs)
+    data = template.render(context).strip()
+    subject, content = re.split(r'\r?\n', data, 1)
+    return (subject.strip(), content.strip())
+
+
+def email_template(rcpt, template_path, **kwargs):
+    """
+    Load, render and email template.
+
+    **kwargs may contain variables for template rendering.
+    """
+
+    subject, content = parse_template(template_path, **kwargs)
+    count = send_mail(subject, content, global_settings.DEFAULT_FROM_EMAIL,
+                      [rcpt], fail_silently=True)
+    return bool(count)
+
+
+def str_to_class(str):
+    mod_str, cls_str = str.rsplit('.', 1)
+    mod = __import__(mod_str, globals(), locals(), ['foobar'])
+    cls = getattr(mod, cls_str)
+    return cls
+
+
+def uri_to_username(uri):
+    return re.sub('r[^0-9a-z]', '_', uri)
+
+
+def get_instance_from_path(path, *args, **kwargs):
+    """
+    Return an instance of a class, given the dotted
+    Python import path (as a string) to the backend class.
+
+    If the backend cannot be located (e.g., because no such module
+    exists, or because the module does not contain a class of the
+    appropriate name), ``django.core.exceptions.ImproperlyConfigured``
+    is raised.
+
+    """
+    i = path.rfind('.')
+    module, attr = path[:i], path[i+1:]
+    try:
+        mod = import_module(module)
+    except ImportError, e:
+        raise ImproperlyConfigured('Error loading registration backend %s: "%s"' % (module, e))
+    try:
+        backend_class = getattr(mod, attr)
+    except AttributeError:
+        raise ImproperlyConfigured('Module "%s" does not define a registration backend named "%s"' % (module, attr))
+
+    return backend_class(*args, **kwargs)
+
+def get_backend(name):
+    return get_instance_from_path(settings.BACKEND_MAPPING[name], name)

publicauth/views.py

+from django.utils.translation import ugettext as _
+from django.shortcuts import redirect
+from django.http import Http404
+from django.contrib import auth 
+from django.conf import settings as global_settings
+
+from annoying.decorators import render_to
+
+from publicauth.utils import str_to_class, get_backend
+from publicauth import settings
+
+
+def logout(request):
+    auth.logout(request)
+    request.flash['success'] = _('You have been logged out')
+    return redirect("/")
+
+
+@render_to('publicauth/begin.html')
+def begin(request, provider=None):
+    """
+    Display authentication form. This is also the first step
+    in registration. The actual login is in social_complete 
+    function below.
+    """
+    if provider:
+        # merge data from POST and GET methods
+        data = request.GET.copy()
+        data.update(request.POST)
+
+        request.session['next_url'] = request.GET.get("next") or global_settings.LOGIN_REDIRECT_URL
+        
+        # start the authentication process 
+        backend = get_backend(provider)
+        backend.begin(request, data)
+
+    return {}
+
+
+def complete(request, provider):
+    """
+    Complete PublicID authorization process.
+    If PublicID was successfuly authenticated:
+     * if no user with such ID exists and current user is authenticated then
+       assign PublicID to this user.
+     * if user with such ID exists and current user is anonimouse then login 
+       as this user.
+     * if no user with such ID exists and user must fill extra fields, 
+       redirect him to registration form.
+    """
+    backend = get_backend(provider)
+    response = backend.validate_response(request)
+    if request.user.is_authenticated():
+        backend.login_user(request)
+        backend.attach_account(request, request.user)
+    else:
+        backend.login_user(request)
+        if not settings.REGISTRATION_ALLOWED:
+            request.flash['warning'] =  publicauth.lang.REGISTRATION_DISABLED
+            return redirect(settings.REGISTRATION_DISABLED_REDIRECT)
+    backend.complete(request, response)
+
+
+@render_to('publicauth/extra.html')
+def extra(request, provider):
+    """                                                
+    Handle registration of new user with extra data for profile
+    """                                                          
+    try:
+        identity = request.session['identity']
+    except KeyError:
+        raise Http404
+
+    if request.method == "POST":
+        form = str_to_class(settings.PUBLICID_EXTRA_FORM)(request.POST)
+        if form.is_valid():
+            user = form.save(identity, provider)
+            del request.session['identity']
+            user = auth.authenticate(identity=identity, provider=provider)
+            if user:
+                auth.login(request, user)
+                next_url = request.session['next_url']
+                del request.session['next_url']
+                return redirect(next_url)
+    else:
+        initial = request.session['extra']
+        form = str_to_class(settings.PUBLICID_EXTRA_FORM)(initial=initial)
+
+    return {'form': form}
+
 from setuptools import setup, find_packages
 
 setup(
-    name = "django-openauth",
+    name = "django-publicauth",
     version = "0.0.1",
     packages = find_packages(),
     author = "Anderson",
     author_email = "self.anderson@gmail.com",
-    description = "django registration, profile and authentication application.",
+    description = "django authentication application.",
     long_description = """
         **Download:**
 
-            - hg clone https://offline@bitbucket.org/offline/django-openauth/
+            - hg clone https://offline@bitbucket.org/offline/django-publicauth/
 
     """,
     license = "BSD",
     keywords = "django",
-    url = "http://bitbucket.org/offline/django-openauth/wiki/Home",
+    url = "http://bitbucket.org/offline/django-publicauth/wiki/Home",
 )
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.