From 7f9677026a420955b29294b32e969704d122f996 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mat=C3=ADas=20Aguirre?= Date: Fri, 12 Nov 2010 17:37:50 -0200 Subject: [PATCH] Small docstrings, code a little pylinted and checked --- social_auth/__init__.py | 4 ++++ social_auth/admin.py | 1 + social_auth/auth.py | 23 ++++++++++++++++++++++- social_auth/backends.py | 9 +++++++++ social_auth/base.py | 11 +++++++++-- social_auth/conf.py | 1 + social_auth/models.py | 10 +++++++--- social_auth/oauth.py | 7 ++----- social_auth/store.py | 14 ++++++++++---- social_auth/urls.py | 1 + social_auth/views.py | 5 ++++- 11 files changed, 70 insertions(+), 16 deletions(-) diff --git a/social_auth/__init__.py b/social_auth/__init__.py index e69de29..a6eb315 100644 --- a/social_auth/__init__.py +++ b/social_auth/__init__.py @@ -0,0 +1,4 @@ +""" +Django-social-auth application, allows OpenId or OAuth user +registration/authentication just adding a few configurations. +""" diff --git a/social_auth/admin.py b/social_auth/admin.py index d2d5d51..d8dde01 100644 --- a/social_auth/admin.py +++ b/social_auth/admin.py @@ -1,3 +1,4 @@ +"""Admin settings""" from django.contrib import admin from .models import UserSocialAuth, Nonce, Association diff --git a/social_auth/auth.py b/social_auth/auth.py index b3cedaa..1df8706 100644 --- a/social_auth/auth.py +++ b/social_auth/auth.py @@ -1,3 +1,4 @@ +"""Authentication handling class""" import cgi import urllib import httplib @@ -8,7 +9,6 @@ from openid.extensions import sreg, ax from django.conf import settings from django.utils import simplejson from django.contrib.auth import authenticate -from django.core.urlresolvers import reverse from .base import BaseAuth from .store import DjangoOpenIDStore @@ -23,6 +23,7 @@ from .conf import AX_ATTRS, SREG_ATTR, OPENID_ID_FIELD, SESSION_NAME, \ class OpenIdAuth(BaseAuth): + """OpenId process handling""" def auth_url(self): openid_request = self.setup_request() # Construct completion URL, including page we should redirect to @@ -55,6 +56,7 @@ class OpenIdAuth(BaseAuth): raise ValueError, 'Unknown OpenID response type: %r' % response.status def setup_request(self): + """Setup request""" openid_request = self.openid_request() # Request some user details. If the provider advertises support # for attribute exchange, use that. @@ -76,11 +78,15 @@ class OpenIdAuth(BaseAuth): @property def uses_redirect(self): + """Return true if openid request will be handled with redirect or + HTML content will be returned. + """ if not hasattr(self, '_uses_redirect'): setattr(self, '_uses_redirect', self.openid_request().shouldSendRedirect()) return getattr(self, '_uses_redirect', True) def openid_request(self): + """Return openid request""" if not hasattr(self, '_openid_request'): openid_url = self.openid_url() try: @@ -92,6 +98,9 @@ class OpenIdAuth(BaseAuth): return getattr(self, '_openid_request', None) def openid_url(self): + """Return service provider URL. + This base class is generic accepting a POST parameter that specifies + provider URL.""" if self.request.method != 'POST' or OPENID_ID_FIELD not in self.request.POST: raise ValueError, 'Missing openid identifier' return self.request.POST[OPENID_ID_FIELD] @@ -100,17 +109,21 @@ class OpenIdAuth(BaseAuth): class GoogleAuth(OpenIdAuth): """Google OpenID authentication""" def openid_url(self): + """Return Google OpenID service url""" return OPENID_GOOGLE_URL class YahooAuth(OpenIdAuth): """Yahoo OpenID authentication""" def openid_url(self): + """Return Yahoo OpenID service url""" return OPENID_YAHOO_URL class BaseOAuth(BaseAuth): + """OAuth base class""" def __init__(self, request, redirect): + """Init method""" super(BaseOAuth, self).__init__(request, redirect) self.redirect_uri = self.request.build_absolute_uri(self.redirect) @@ -139,15 +152,18 @@ class TwitterAuth(BaseOAuth): return authenticate(response=data, twitter=True) def unauthorized_token(self): + """Return request for unauthorized token (first stage)""" request = self.oauth_request(token=None, url=TWITTER_REQUEST_TOKEN_URL) response = self.fetch_response(request) return OAuthToken.from_string(response) def access_token(self, token): + """Return request for access token value""" request = self.oauth_request(token, TWITTER_ACCESS_TOKEN_URL) return OAuthToken.from_string(self.fetch_response(request)) def user_data(self, access_token): + """Return user data provided""" request = self.oauth_request(access_token, TWITTER_CHECK_AUTH) json = self.fetch_response(request) try: @@ -156,6 +172,7 @@ class TwitterAuth(BaseOAuth): return None def oauth_request(self, token, url): + """Generate OAuth request, setups callback url""" params = {'oauth_callback': self.redirect_uri} if 'oauth_verifier' in self.request.GET: params['oauth_verifier'] = self.request.GET['oauth_verifier'] @@ -168,12 +185,14 @@ class TwitterAuth(BaseOAuth): return request def fetch_response(self, request): + """Executes request and fetchs service response""" self.connection.request(request.http_method, request.to_url()) response = self.connection.getresponse() return response.read() @property def connection(self): + """Setups connection""" conn = getattr(self, '_connection', None) if conn is None: conn = httplib.HTTPSConnection(TWITTER_SERVER) @@ -182,6 +201,7 @@ class TwitterAuth(BaseOAuth): @property def consumer(self): + """Setups consumer""" cons = getattr(self, '_consumer', None) if cons is None: cons = OAuthConsumer(settings.TWITTER_CONSUMER_KEY, @@ -225,6 +245,7 @@ class FacebookAuth(BaseOAuth): raise ValueError, 'Authentication error' def user_data(self, access_token): + """Loads user data from service""" params = {'access_token': access_token} url = FACEBOOK_CHECK_AUTH + '?' + urllib.urlencode(params) try: diff --git a/social_auth/backends.py b/social_auth/backends.py index 21634d4..2709c44 100644 --- a/social_auth/backends.py +++ b/social_auth/backends.py @@ -1,3 +1,6 @@ +""" +Authentication backeds for django.contrib.auth AUTHENTICATION_BACKENDS setting +""" from openid.extensions import ax, sreg from .base import SocialAuthBackend @@ -16,10 +19,12 @@ class TwitterBackend(OAuthBackend): name = 'twitter' def authenticate(self, **kwargs): + """Authenticate user only if this was a Twitter request""" if kwargs.pop('twitter', False): return super(TwitterBackend, self).authenticate(**kwargs) def get_user_details(self, response): + """Return user details from Twitter account""" return {'email': '', # not supplied 'username': response['screen_name'], 'fullname': response['name'], @@ -32,10 +37,12 @@ class FacebookBackend(OAuthBackend): name = 'facebook' def authenticate(self, **kwargs): + """Authenticate user only if this was a Facebook request""" if kwargs.pop('facebook', False): return super(FacebookBackend, self).authenticate(**kwargs) def get_user_details(self, response): + """Return user details from Facebook account""" return {'email': response.get('email', ''), 'username': response['name'], 'fullname': response['name'], @@ -53,9 +60,11 @@ class OpenIDBackend(SocialAuthBackend): return super(OpenIDBackend, self).authenticate(**kwargs) def get_user_id(self, details, response): + """Return user unique id provided by service""" return response.identity_url def get_user_details(self, response): + """Return user details from an OpenID request""" values = {'email': '', 'username': '', 'fullname': '', diff --git a/social_auth/base.py b/social_auth/base.py index 03628ec..8762f69 100644 --- a/social_auth/base.py +++ b/social_auth/base.py @@ -1,3 +1,4 @@ +"""Some base classes""" import os import md5 @@ -64,7 +65,11 @@ class SocialAuthBackend(ModelBackend): return user def get_username(self, details): + """Return an unique username, if SOCIAL_AUTH_FORCE_RANDOM_USERNAME + setting is True, then username will be a random 30 chars md5 hash + """ def get_random_username(): + """Return hash from random string cut at 30 chars""" return md5.md5(str(os.urandom(10))).hexdigest()[:30] if getattr(settings, 'SOCIAL_AUTH_FORCE_RANDOM_USERNAME', False): @@ -86,10 +91,11 @@ class SocialAuthBackend(ModelBackend): return username def create_user(self, response, details): + """Create user with unique username""" username = self.get_username(details) user = User.objects.create_user(username, details.get('email', '')) - self.update_user_details(user, details) - self.associate_auth(user, response, details) + self.update_user_details(user, details) # load details + self.associate_auth(user, response, details) # save account association return user def associate_auth(self, user, response, details): @@ -109,6 +115,7 @@ class SocialAuthBackend(ModelBackend): return user_oauth def update_user_details(self, user, details): + """Update user details with new (maybe) data""" first_name = details.get('firstname') or user.first_name last_name = details.get('lastname') or user.last_name email = details.get('email') or user.email diff --git a/social_auth/conf.py b/social_auth/conf.py index c1515de..25dc555 100644 --- a/social_auth/conf.py +++ b/social_auth/conf.py @@ -1,3 +1,4 @@ +"""Conf settings""" # Twitter configuration TWITTER_SERVER = 'api.twitter.com' TWITTER_REQUEST_TOKEN_URL = 'https://%s/oauth/request_token' % TWITTER_SERVER diff --git a/social_auth/models.py b/social_auth/models.py index 106e60b..bf64d9b 100644 --- a/social_auth/models.py +++ b/social_auth/models.py @@ -1,24 +1,28 @@ +"""Social auth models""" from django.db import models from django.contrib.auth.models import User class UserSocialAuth(models.Model): """Social Auth association model""" - user = models.ForeignKey(User) + user = models.ForeignKey(User, related_name='social_auth') provider = models.CharField(max_length=32) - uid = models.CharField(max_length=2048) + uid = models.TextField() class Meta: + """Meta data""" unique_together = ('provider', 'uid') class Nonce(models.Model): - server_url = models.CharField(max_length=2047) + """One use numbers""" + server_url = models.TextField() timestamp = models.IntegerField() salt = models.CharField(max_length=40) class Association(models.Model): + """OpenId account association""" server_url = models.TextField(max_length=2047) handle = models.CharField(max_length=255) secret = models.TextField(max_length=255) # Stored base64 encoded diff --git a/social_auth/oauth.py b/social_auth/oauth.py index fd1f6a5..ad75b9f 100644 --- a/social_auth/oauth.py +++ b/social_auth/oauth.py @@ -273,7 +273,7 @@ class OAuthServer(object): self.signature_methods = signature_methods or {} def set_data_store(self, oauth_data_store): - self.data_store = data_store + self.data_store = oauth_data_store def get_data_store(self): return self.data_store @@ -290,7 +290,6 @@ class OAuthServer(object): token = self._get_token(oauth_request, 'request') except OAuthError: # no token required for the initial token request - version = self._get_version(oauth_request) consumer = self._get_consumer(oauth_request) self._check_signature(oauth_request, consumer, None) # fetch a new token @@ -300,7 +299,6 @@ class OAuthServer(object): # process an access_token request # returns the access token on success def fetch_access_token(self, oauth_request): - version = self._get_version(oauth_request) consumer = self._get_consumer(oauth_request) # get the request token token = self._get_token(oauth_request, 'request') @@ -311,7 +309,6 @@ class OAuthServer(object): # verify an api call, checks all the parameters def verify_request(self, oauth_request): # -> consumer and token - version = self._get_version(oauth_request) consumer = self._get_consumer(oauth_request) # get the access token token = self._get_token(oauth_request, 'access') @@ -387,7 +384,7 @@ class OAuthServer(object): if not valid_sig: key, base = signature_method.build_signature_base_string(oauth_request, consumer, token) raise OAuthError('Invalid signature. Expected signature base string: %s' % base) - built = signature_method.build_signature(oauth_request, consumer, token) + signature_method.build_signature(oauth_request, consumer, token) def _check_timestamp(self, timestamp): # verify that timestamp is recentish diff --git a/social_auth/store.py b/social_auth/store.py index b5db453..faab961 100644 --- a/social_auth/store.py +++ b/social_auth/store.py @@ -1,3 +1,4 @@ +"""OpenId storage that saves to django models""" import time import base64 @@ -9,10 +10,14 @@ from .models import Association, Nonce class DjangoOpenIDStore(OpenIDStore): + """Storage class""" def __init__(self): + """Init method""" + super(DjangoOpenIDStore, self).__init__() self.max_nonce_age = 6 * 60 * 60 # Six hours def storeAssociation(self, server_url, association): + """Store new assocition if doesn't exist""" args = {'server_url': server_url, 'handle': association.handle} try: assoc = Association.objects.get(**args) @@ -25,6 +30,7 @@ class DjangoOpenIDStore(OpenIDStore): assoc.save() def getAssociation(self, server_url, handle=None): + """Return stored assocition""" args = {'server_url': server_url} if handle is not None: args['handle'] = handle @@ -49,9 +55,9 @@ class DjangoOpenIDStore(OpenIDStore): return associations[0] def useNonce(self, server_url, timestamp, salt): + """Generate one use number and return if it was created""" if abs(timestamp - time.time()) > SKEW: return False - nonce, created = Nonce.objects.get_or_create(server_url=server_url, - timestamp=timestamp, - salt=salt) - return created + return Nonce.objects.get_or_create(server_url=server_url, + timestamp=timestamp, + salt=salt)[1] diff --git a/social_auth/urls.py b/social_auth/urls.py index a7e1312..fb595af 100644 --- a/social_auth/urls.py +++ b/social_auth/urls.py @@ -1,3 +1,4 @@ +"""URLs module""" from django.conf.urls.defaults import patterns, url from .views import auth, complete diff --git a/social_auth/views.py b/social_auth/views.py index 6cf0e00..d71bd47 100644 --- a/social_auth/views.py +++ b/social_auth/views.py @@ -1,3 +1,4 @@ +"""Views""" from django.conf import settings from django.http import HttpResponseRedirect, HttpResponse, \ HttpResponseServerError @@ -7,6 +8,7 @@ from django.contrib.auth import login, REDIRECT_FIELD_NAME from .auth import TwitterAuth, FacebookAuth, OpenIdAuth, GoogleAuth, YahooAuth +# Authenticatin backeds BACKENDS = { 'twitter': TwitterAuth, 'facebook': FacebookAuth, @@ -15,8 +17,8 @@ BACKENDS = { 'openid': OpenIdAuth, } - def auth(request, backend): + """Authentication starting process""" if backend not in BACKENDS: return HttpResponseServerError('Incorrect authentication service') request.session[REDIRECT_FIELD_NAME] = request.GET.get(REDIRECT_FIELD_NAME, @@ -31,6 +33,7 @@ def auth(request, backend): def complete(request, backend): + """Authentication complete process""" if backend not in BACKENDS: return HttpResponseServerError('Incorrect authentication service') backend = BACKENDS[backend](request, request.path) -- 2.39.5