diff options
-rw-r--r-- | django_authopenid/__init__.py | 40 | ||||
-rw-r--r-- | django_authopenid/admin.py | 9 | ||||
-rw-r--r-- | django_authopenid/forms.py | 321 | ||||
-rw-r--r-- | django_authopenid/middleware.py | 28 | ||||
-rw-r--r-- | django_authopenid/mimeparse.py | 160 | ||||
-rw-r--r-- | django_authopenid/models.py | 80 | ||||
-rwxr-xr-x | django_authopenid/urls.py | 62 | ||||
-rw-r--r-- | django_authopenid/util.py | 135 | ||||
-rwxr-xr-x | django_authopenid/views.py | 1169 | ||||
-rwxr-xr-x | fbconnect/__init__.py | 0 | ||||
-rwxr-xr-x | fbconnect/fb.py | 96 | ||||
-rwxr-xr-x | fbconnect/forms.py | 8 | ||||
-rwxr-xr-x | fbconnect/models.py | 6 | ||||
-rwxr-xr-x | fbconnect/pjson.py | 313 | ||||
-rwxr-xr-x | fbconnect/tests.py | 23 | ||||
-rwxr-xr-x | fbconnect/urls.py | 19 | ||||
-rwxr-xr-x | fbconnect/views.py | 112 |
17 files changed, 0 insertions, 2581 deletions
diff --git a/django_authopenid/__init__.py b/django_authopenid/__init__.py deleted file mode 100644 index ff040ed7..00000000 --- a/django_authopenid/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2007, 2008, Benoît Chesneau -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# * notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# * notice, this list of conditions and the following disclaimer in the -# * documentation and/or other materials provided with the -# * distribution. Neither the name of the <ORGANIZATION> nor the names -# * of its contributors may be used to endorse or promote products -# * derived from this software without specific prior written -# * permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -""" -Django authentification application to *with openid using django auth contrib/. - -This application allow a user to connect to you website with : - * legacy account : username/password - * openid url -""" - -__version__ = "0.9.4" diff --git a/django_authopenid/admin.py b/django_authopenid/admin.py deleted file mode 100644 index f64ee579..00000000 --- a/django_authopenid/admin.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.contrib import admin -from django_authopenid.models import UserAssociation - - -class UserAssociationAdmin(admin.ModelAdmin): - """User association admin class""" -admin.site.register(UserAssociation, UserAssociationAdmin)
\ No newline at end of file diff --git a/django_authopenid/forms.py b/django_authopenid/forms.py deleted file mode 100644 index 2f34986c..00000000 --- a/django_authopenid/forms.py +++ /dev/null @@ -1,321 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2007, 2008, Benoît Chesneau -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# * notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# * notice, this list of conditions and the following disclaimer in the -# * documentation and/or other materials provided with the -# * distribution. Neither the name of the <ORGANIZATION> nor the names -# * of its contributors may be used to endorse or promote products -# * derived from this software without specific prior written -# * permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -from django import forms -from django.contrib.auth.models import User -from django.contrib.auth import authenticate -from django.utils.translation import ugettext as _ -from django.conf import settings -import types -import re -from django.utils.safestring import mark_safe -from recaptcha_django import ReCaptchaField -from forum.utils.forms import NextUrlField, UserNameField, UserEmailField, SetPasswordForm -EXTERNAL_LOGIN_APP = settings.LOAD_EXTERNAL_LOGIN_APP() - -# needed for some linux distributions like debian -try: - from openid.yadis import xri -except ImportError: - from yadis import xri - -from forum.utils.forms import clean_next -from django_authopenid.models import ExternalLoginData - -__all__ = ['OpenidSigninForm', 'ClassicLoginForm', 'OpenidVerifyForm', - 'OpenidRegisterForm', 'ClassicRegisterForm', 'ChangePasswordForm', - 'ChangeEmailForm', 'EmailPasswordForm', 'DeleteForm', - 'ChangeOpenidForm'] - -class OpenidSigninForm(forms.Form): - """ signin form """ - openid_url = forms.CharField(max_length=255, widget=forms.widgets.TextInput(attrs={'class': 'openid-login-input', 'size':80})) - next = NextUrlField() - - def clean_openid_url(self): - """ test if openid is accepted """ - if 'openid_url' in self.cleaned_data: - openid_url = self.cleaned_data['openid_url'] - if xri.identifierScheme(openid_url) == 'XRI' and getattr( - settings, 'OPENID_DISALLOW_INAMES', False - ): - raise forms.ValidationError(_('i-names are not supported')) - return self.cleaned_data['openid_url'] - -class ClassicLoginForm(forms.Form): - """ legacy account signin form """ - next = NextUrlField() - username = UserNameField(required=False,skip_clean=True) - password = forms.CharField(max_length=128, - widget=forms.widgets.PasswordInput(attrs={'class':'required login'}), - required=False) - - def __init__(self, data=None, files=None, auto_id='id_%s', - prefix=None, initial=None): - super(ClassicLoginForm, self).__init__(data, files, auto_id, - prefix, initial) - self.user_cache = None - - def _clean_nonempty_field(self,field): - value = None - if field in self.cleaned_data: - value = str(self.cleaned_data[field]).strip() - if value == '': - value = None - self.cleaned_data[field] = value - return value - - def clean_username(self): - return self._clean_nonempty_field('username') - - def clean_password(self): - return self._clean_nonempty_field('password') - - def clean(self): - """ - this clean function actually cleans username and password - - test if password is valid for this username - this is really the "authenticate" function - also openid_auth is not an authentication backend - since it's written in a way that does not comply with - the Django convention - """ - - error_list = [] - username = self.cleaned_data['username'] - password = self.cleaned_data['password'] - - self.user_cache = None - if username and password: - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - pw_ok = False - try: - pw_ok = EXTERNAL_LOGIN_APP.api.check_password(username,password) - except forms.ValidationError, e: - error_list.extend(e.messages) - if pw_ok: - external_user = ExternalLoginData.objects.get(external_username=username) - if external_user.user == None: - return self.cleaned_data - user = external_user.user - openid_logins = user.userassociation_set.all() - - if len(openid_logins) > 0: - msg1 = _('Account with this name already exists on the forum') - msg2 = _('can\'t have two logins to the same account yet, sorry.') - error_list.append(msg1) - error_list.append(msg2) - self._errors['__all__'] = forms.util.ErrorList(error_list) - return self.cleaned_data - else: - #synchronize password with external login - user.set_password(password) - user.save() - #this auth will always succeed - self.user_cache = authenticate(username=user.username,\ - password=password) - else: - #keep self.user_cache == None - #nothing to do, error message will be set below - pass - else: - self.user_cache = authenticate(username=username, password=password) - - if self.user_cache is None: - del self.cleaned_data['username'] - del self.cleaned_data['password'] - error_list.insert(0,(_("Please enter valid username and password " - "(both are case-sensitive)."))) - elif self.user_cache.is_active == False: - error_list.append(_("This account is inactive.")) - if len(error_list) > 0: - error_list.insert(0,_('Login failed.')) - elif password == None and username == None: - error_list.append(_('Please enter username and password')) - elif password == None: - error_list.append(_('Please enter your password')) - elif username == None: - error_list.append(_('Please enter user name')) - if len(error_list) > 0: - self._errors['__all__'] = forms.util.ErrorList(error_list) - return self.cleaned_data - - def get_user(self): - """ get authenticated user """ - return self.user_cache - - -class OpenidRegisterForm(forms.Form): - """ openid signin form """ - next = NextUrlField() - username = UserNameField() - email = UserEmailField() - -class OpenidVerifyForm(forms.Form): - """ openid verify form (associate an openid with an account) """ - next = NextUrlField() - username = UserNameField(must_exist=True) - password = forms.CharField(max_length=128, - widget=forms.widgets.PasswordInput(attrs={'class':'required login'})) - - def __init__(self, data=None, files=None, auto_id='id_%s', - prefix=None, initial=None): - super(OpenidVerifyForm, self).__init__(data, files, auto_id, - prefix, initial) - self.user_cache = None - - def clean_password(self): - """ test if password is valid for this user """ - if 'username' in self.cleaned_data and \ - 'password' in self.cleaned_data: - self.user_cache = authenticate( - username = self.cleaned_data['username'], - password = self.cleaned_data['password'] - ) - if self.user_cache is None: - raise forms.ValidationError(_("Please enter a valid \ - username and password. Note that both fields are \ - case-sensitive.")) - elif self.user_cache.is_active == False: - raise forms.ValidationError(_("This account is inactive.")) - return self.cleaned_data['password'] - - def get_user(self): - """ get authenticated user """ - return self.user_cache - -class ClassicRegisterForm(SetPasswordForm): - """ legacy registration form """ - - next = NextUrlField() - username = UserNameField() - email = UserEmailField() - #fields password1 and password2 are inherited - recaptcha = ReCaptchaField() - -class ChangePasswordForm(SetPasswordForm): - """ change password form """ - oldpw = forms.CharField(widget=forms.PasswordInput(attrs={'class':'required'}), - label=mark_safe(_('Current password'))) - - def __init__(self, data=None, user=None, *args, **kwargs): - if user is None: - raise TypeError("Keyword argument 'user' must be supplied") - super(ChangePasswordForm, self).__init__(data, *args, **kwargs) - self.user = user - - def clean_oldpw(self): - """ test old password """ - if not self.user.check_password(self.cleaned_data['oldpw']): - raise forms.ValidationError(_("Old password is incorrect. \ - Please enter the correct password.")) - return self.cleaned_data['oldpw'] - -class ChangeEmailForm(forms.Form): - """ change email form """ - email = UserEmailField(skip_clean=True) - - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, \ - initial=None, user=None): - super(ChangeEmailForm, self).__init__(data, files, auto_id, - prefix, initial) - self.user = user - - def clean_email(self): - """ check if email don't exist """ - if 'email' in self.cleaned_data: - if settings.EMAIL_UNIQUE == True: - try: - user = User.objects.get(email = self.cleaned_data['email']) - if self.user and self.user == user: - return self.cleaned_data['email'] - except User.DoesNotExist: - return self.cleaned_data['email'] - except User.MultipleObjectsReturned: - raise forms.ValidationError(u'There is already more than one \ - account registered with that e-mail address. Please try \ - another.') - raise forms.ValidationError(u'This email is already registered \ - in our database. Please choose another.') - else: - return self.cleaned_data['email'] - -class ChangeopenidForm(forms.Form): - """ change openid form """ - openid_url = forms.CharField(max_length=255, - widget=forms.TextInput(attrs={'class': "required" })) - - def __init__(self, data=None, user=None, *args, **kwargs): - if user is None: - raise TypeError("Keyword argument 'user' must be supplied") - super(ChangeopenidForm, self).__init__(data, *args, **kwargs) - self.user = user - -class DeleteForm(forms.Form): - """ confirm form to delete an account """ - confirm = forms.CharField(widget=forms.CheckboxInput(attrs={'class':'required'})) - password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'required'})) - - def __init__(self, data=None, files=None, auto_id='id_%s', - prefix=None, initial=None, user=None): - super(DeleteForm, self).__init__(data, files, auto_id, prefix, initial) - self.test_openid = False - self.user = user - - def clean_password(self): - """ check if we have to test a legacy account or not """ - if 'password' in self.cleaned_data: - if not self.user.check_password(self.cleaned_data['password']): - self.test_openid = True - return self.cleaned_data['password'] - - -class EmailPasswordForm(forms.Form): - """ send new password form """ - username = UserNameField(skip_clean=True,label=mark_safe(_('Your user name (<i>required</i>)'))) - - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None): - super(EmailPasswordForm, self).__init__(data, files, auto_id, - prefix, initial) - self.user_cache = None - - def clean_username(self): - """ get user for this username """ - if 'username' in self.cleaned_data: - try: - self.user_cache = User.objects.get( - username = self.cleaned_data['username']) - except: - raise forms.ValidationError(_("Incorrect username.")) - return self.cleaned_data['username'] diff --git a/django_authopenid/middleware.py b/django_authopenid/middleware.py deleted file mode 100644 index 2be8da90..00000000 --- a/django_authopenid/middleware.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -from django_authopenid import mimeparse -from django.http import HttpResponseRedirect -from django.core.urlresolvers import reverse -from django.conf import settings -import logging - -__all__ = ["OpenIDMiddleware"] - -class OpenIDMiddleware(object): - """ - Populate request.openid. This comes either from cookie or from - session, depending on the presence of OPENID_USE_SESSIONS. - """ - def process_request(self, request): - request.openid = request.session.get('openid', None) - logging.debug('openid in session is: %s' % str(request.openid)) - - def process_response(self, request, response): - if response.status_code != 200 or len(response.content) < 200: - return response - path = request.get_full_path() - if path == "/" and request.META.has_key('HTTP_ACCEPT') and \ - mimeparse.best_match(['text/html', 'application/xrds+xml'], - request.META['HTTP_ACCEPT']) == 'application/xrds+xml': - logging.debug('redirecting to yadis_xrdf:%s' % reverse('yadis_xrdf')) - return HttpResponseRedirect(reverse('yadis_xrdf')) - return response diff --git a/django_authopenid/mimeparse.py b/django_authopenid/mimeparse.py deleted file mode 100644 index ab02eab0..00000000 --- a/django_authopenid/mimeparse.py +++ /dev/null @@ -1,160 +0,0 @@ -"""MIME-Type Parser - -This module provides basic functions for handling mime-types. It can handle -matching mime-types against a list of media-ranges. See section 14.1 of -the HTTP specification [RFC 2616] for a complete explaination. - - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 - -Contents: - - parse_mime_type(): Parses a mime-type into it's component parts. - - parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q' quality parameter. - - quality(): Determines the quality ('q') of a mime-type when compared against a list of media-ranges. - - quality_parsed(): Just like quality() except the second parameter must be pre-parsed. - - best_match(): Choose the mime-type with the highest quality ('q') from a list of candidates. -""" - -__version__ = "0.1.1" -__author__ = 'Joe Gregorio' -__email__ = "joe@bitworking.org" -__credits__ = "" - -def parse_mime_type(mime_type): - """Carves up a mime_type and returns a tuple of the - (type, subtype, params) where 'params' is a dictionary - of all the parameters for the media range. - For example, the media range 'application/xhtml;q=0.5' would - get parsed into: - - ('application', 'xhtml', {'q', '0.5'}) - """ - parts = mime_type.split(";") - params = dict([tuple([s.strip() for s in param.split("=")])\ - for param in parts[1:] ]) - (type, subtype) = parts[0].split("/") - return (type.strip(), subtype.strip(), params) - -def parse_media_range(range): - """Carves up a media range and returns a tuple of the - (type, subtype, params) where 'params' is a dictionary - of all the parameters for the media range. - For example, the media range 'application/*;q=0.5' would - get parsed into: - - ('application', '*', {'q', '0.5'}) - - In addition this function also guarantees that there - is a value for 'q' in the params dictionary, filling it - in with a proper default if necessary. - """ - (type, subtype, params) = parse_mime_type(range) - if not params.has_key('q') or not params['q'] or \ - not float(params['q']) or float(params['q']) > 1\ - or float(params['q']) < 0: - params['q'] = '1' - return (type, subtype, params) - -def quality_parsed(mime_type, parsed_ranges): - """Find the best match for a given mime_type against - a list of media_ranges that have already been - parsed by parse_media_range(). Returns the - 'q' quality parameter of the best match, 0 if no - match was found. This function bahaves the same as quality() - except that 'parsed_ranges' must be a list of - parsed media ranges. """ - best_fitness = -1 - best_match = "" - best_fit_q = 0 - (target_type, target_subtype, target_params) =\ - parse_media_range(mime_type) - for (type, subtype, params) in parsed_ranges: - param_matches = reduce(lambda x, y: x+y, [1 for (key, value) in \ - target_params.iteritems() if key != 'q' and \ - params.has_key(key) and value == params[key]], 0) - if (type == target_type or type == '*' or target_type == '*') and \ - (subtype == target_subtype or subtype == '*' or target_subtype == '*'): - fitness = (type == target_type) and 100 or 0 - fitness += (subtype == target_subtype) and 10 or 0 - fitness += param_matches - if fitness > best_fitness: - best_fitness = fitness - best_fit_q = params['q'] - - return float(best_fit_q) - -def quality(mime_type, ranges): - """Returns the quality 'q' of a mime_type when compared - against the media-ranges in ranges. For example: - - >>> quality('text/html','text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5') - 0.7 - - """ - parsed_ranges = [parse_media_range(r) for r in ranges.split(",")] - return quality_parsed(mime_type, parsed_ranges) - -def best_match(supported, header): - """Takes a list of supported mime-types and finds the best - match for all the media-ranges listed in header. The value of - header must be a string that conforms to the format of the - HTTP Accept: header. The value of 'supported' is a list of - mime-types. - - >>> best_match(['application/xbel+xml', 'text/xml'], 'text/*;q=0.5,*/*; q=0.1') - 'text/xml' - """ - parsed_header = [parse_media_range(r) for r in header.split(",")] - weighted_matches = [(quality_parsed(mime_type, parsed_header), mime_type)\ - for mime_type in supported] - weighted_matches.sort() - return weighted_matches[-1][0] and weighted_matches[-1][1] or '' - -if __name__ == "__main__": - import unittest - - class TestMimeParsing(unittest.TestCase): - - def test_parse_media_range(self): - self.assert_(('application', 'xml', {'q': '1'}) == parse_media_range('application/xml;q=1')) - self.assertEqual(('application', 'xml', {'q': '1'}), parse_media_range('application/xml')) - self.assertEqual(('application', 'xml', {'q': '1'}), parse_media_range('application/xml;q=')) - self.assertEqual(('application', 'xml', {'q': '1'}), parse_media_range('application/xml ; q=')) - self.assertEqual(('application', 'xml', {'q': '1', 'b': 'other'}), parse_media_range('application/xml ; q=1;b=other')) - self.assertEqual(('application', 'xml', {'q': '1', 'b': 'other'}), parse_media_range('application/xml ; q=2;b=other')) - - def test_rfc_2616_example(self): - accept = "text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5" - self.assertEqual(1, quality("text/html;level=1", accept)) - self.assertEqual(0.7, quality("text/html", accept)) - self.assertEqual(0.3, quality("text/plain", accept)) - self.assertEqual(0.5, quality("image/jpeg", accept)) - self.assertEqual(0.4, quality("text/html;level=2", accept)) - self.assertEqual(0.7, quality("text/html;level=3", accept)) - - def test_best_match(self): - mime_types_supported = ['application/xbel+xml', 'application/xml'] - # direct match - self.assertEqual(best_match(mime_types_supported, 'application/xbel+xml'), 'application/xbel+xml') - # direct match with a q parameter - self.assertEqual(best_match(mime_types_supported, 'application/xbel+xml; q=1'), 'application/xbel+xml') - # direct match of our second choice with a q parameter - self.assertEqual(best_match(mime_types_supported, 'application/xml; q=1'), 'application/xml') - # match using a subtype wildcard - self.assertEqual(best_match(mime_types_supported, 'application/*; q=1'), 'application/xml') - # match using a type wildcard - self.assertEqual(best_match(mime_types_supported, '*/*'), 'application/xml') - - mime_types_supported = ['application/xbel+xml', 'text/xml'] - # match using a type versus a lower weighted subtype - self.assertEqual(best_match(mime_types_supported, 'text/*;q=0.5,*/*; q=0.1'), 'text/xml') - # fail to match anything - self.assertEqual(best_match(mime_types_supported, 'text/html,application/atom+xml; q=0.9'), '') - - def test_support_wildcards(self): - mime_types_supported = ['image/*', 'application/xml'] - # match using a type wildcard - self.assertEqual(best_match(mime_types_supported, 'image/png'), 'image/*') - # match using a wildcard for both requested and supported - self.assertEqual(best_match(mime_types_supported, 'image/*'), 'image/*') - - unittest.main()
\ No newline at end of file diff --git a/django_authopenid/models.py b/django_authopenid/models.py deleted file mode 100644 index a12c2fec..00000000 --- a/django_authopenid/models.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -from django.conf import settings -from django.contrib.auth.models import User -from django.db import models - -import hashlib, random, sys, os, time - -__all__ = ['Nonce', 'Association', 'UserAssociation', - 'UserPasswordQueueManager', 'UserPasswordQueue'] - -class Nonce(models.Model): - """ openid nonce """ - server_url = models.CharField(max_length=255) - timestamp = models.IntegerField() - salt = models.CharField(max_length=40) - - def __unicode__(self): - return u"Nonce: %s" % self.id - - -class Association(models.Model): - """ association openid url and lifetime """ - server_url = models.TextField(max_length=2047) - handle = models.CharField(max_length=255) - secret = models.TextField(max_length=255) # Stored base64 encoded - issued = models.IntegerField() - lifetime = models.IntegerField() - assoc_type = models.TextField(max_length=64) - - def __unicode__(self): - return u"Association: %s, %s" % (self.server_url, self.handle) - -class UserAssociation(models.Model): - """ - model to manage association between openid and user - """ - openid_url = models.CharField(blank=False, max_length=255) - user = models.ForeignKey(User, unique=True) - - def __unicode__(self): - return "Openid %s with user %s" % (self.openid_url, self.user) - -class UserPasswordQueueManager(models.Manager): - """ manager for UserPasswordQueue object """ - def get_new_confirm_key(self): - "Returns key that isn't being used." - # The random module is seeded when this Apache child is created. - # Use SECRET_KEY as added salt. - while 1: - confirm_key = hashlib.md5("%s%s%s%s" % ( - random.randint(0, sys.maxint - 1), os.getpid(), - time.time(), settings.SECRET_KEY)).hexdigest() - try: - self.get(confirm_key=confirm_key) - except self.model.DoesNotExist: - break - return confirm_key - - -class UserPasswordQueue(models.Model): - """ - model for new password queue. - """ - user = models.ForeignKey(User, unique=True) - new_password = models.CharField(max_length=30) - confirm_key = models.CharField(max_length=40) - - objects = UserPasswordQueueManager() - - def __unicode__(self): - return self.user.username - -class ExternalLoginData(models.Model): - """this class was added by Evgeny to associate - external authentication user with django user - probably it just does not belong here... (EF) - """ - external_username = models.CharField(max_length=40, unique=True, null=False) - external_session_data = models.TextField() - user = models.ForeignKey(User, null=True) diff --git a/django_authopenid/urls.py b/django_authopenid/urls.py deleted file mode 100755 index e1986d19..00000000 --- a/django_authopenid/urls.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -from django.conf.urls.defaults import patterns, url -from django.utils.translation import ugettext as _ -from django.conf import settings - -#print 'stuff to import %s' % settings.EXTERNAL_LOGIN_APP.__name__ + '.views' -#try: -# settings.EXTERNAL_LOGIN_APP = __import__('mediawiki.views') -#print 'stuff to import %s' % settings.EXTERNAL_LOGIN_APP.__name__ + '.views' -#try: -# print 'imported fine' -# print settings.EXTERNAL_LOGIN_APP.__dict__.keys() -#except: -# print 'dammit!' -#from mediawiki.views import signup_view -#settings.EXTERNAL_LOGIN_APP.views.signup_view() - -#print settings.EXTERNAL_LOGIN_APP.__dict__.keys() -urlpatterns = patterns('django_authopenid.views', - # yadis rdf - url(r'^yadis.xrdf$', 'xrdf', name='yadis_xrdf'), - # manage account registration - url(r'^%s$' % _('signin/'), 'signin', name='user_signin'), - url(r'^%s%s$' % (_('signin/'),_('newquestion/')), 'signin', kwargs = {'newquestion':True}, name='user_signin_new_question'), - url(r'^%s%s$' % (_('signin/'),_('newanswer/')), 'signin', kwargs = {'newanswer':True}, name='user_signin_new_answer'), - url(r'^%s$' % _('signout/'), 'signout', name='user_signout'), - url(r'^%s%s$' % (_('signin/'), _('complete/')), 'complete_signin', - name='user_complete_signin'), - url(r'^%s$' % _('register/'), 'register', name='user_register'), - url(r'^%s$' % _('signup/'), 'signup', name='user_signup'), - #disable current sendpw function - url(r'^%s$' % _('sendpw/'), 'sendpw', name='user_sendpw'), - url(r'^%s%s$' % (_('password/'), _('confirm/')), 'confirmchangepw', name='user_confirmchangepw'), - - # manage account settings - url(r'^$', _('account_settings'), name='user_account_settings'), - url(r'^%s$' % _('password/'), 'changepw', name='user_changepw'), - url(r'^%s%s$' % (_('email/'),_('validate/')), 'changeemail', name='user_validateemail',kwargs = {'action':'validate'}), - url(r'^%s%s$' % (_('email/'), _('change/')), 'changeemail', name='user_changeemail'), - url(r'^%s%s$' % (_('email/'), _('sendkey/')), 'send_email_key', name='send_email_key'), - url(r'^%s%s(?P<id>\d+)/(?P<key>[\dabcdef]{32})/$' % (_('email/'), _('verify/')), 'verifyemail', name='user_verifyemail'), - url(r'^%s$' % _('openid/'), 'changeopenid', name='user_changeopenid'), - url(r'^%s$' % _('delete/'), 'delete', name='user_delete'), -) - -#todo move these out of this file completely -if settings.USE_EXTERNAL_LEGACY_LOGIN: - from forum.forms import NotARobotForm - EXTERNAL_LOGIN_APP = settings.LOAD_EXTERNAL_LOGIN_APP() - urlpatterns += patterns('', - url('^%s$' % _('external-login/forgot-password/'),\ - 'django_authopenid.views.external_legacy_login_info', \ - name='user_external_legacy_login_issues'), - url('^%s$' % _('external-login/signup/'), \ - EXTERNAL_LOGIN_APP.views.signup,\ - name='user_external_legacy_login_signup'), -# url('^%s$' % _('external-login/signup/'), \ -# EXTERNAL_LOGIN_APP.forms.RegisterFormWizard( \ -# [EXTERNAL_LOGIN_APP.forms.RegisterForm, \ -# NotARobotForm]),\ -# name='user_external_legacy_login_signup'), - ) diff --git a/django_authopenid/util.py b/django_authopenid/util.py deleted file mode 100644 index cd2c2e2c..00000000 --- a/django_authopenid/util.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- coding: utf-8 -*- -from openid.store.interface import OpenIDStore -from openid.association import Association as OIDAssociation -from openid.extensions import sreg -import openid.store - -from django.db.models.query import Q -from django.conf import settings -from django.core.urlresolvers import reverse - -# needed for some linux distributions like debian -try: - from openid.yadis import xri -except: - from yadis import xri - -import time, base64, hashlib, operator, logging -from forum.utils.forms import clean_next, get_next_url - -from models import Association, Nonce - -__all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next'] - -class OpenID: - def __init__(self, openid_, issued, attrs=None, sreg_=None): - logging.debug('init janrain openid object') - self.openid = openid_ - self.issued = issued - self.attrs = attrs or {} - self.sreg = sreg_ or {} - self.is_iname = (xri.identifierScheme(openid_) == 'XRI') - - def __repr__(self): - return '<OpenID: %s>' % self.openid - - def __str__(self): - return self.openid - -class DjangoOpenIDStore(OpenIDStore): - def __init__(self): - self.max_nonce_age = 6 * 60 * 60 # Six hours - - def storeAssociation(self, server_url, association): - assoc = Association( - server_url = server_url, - handle = association.handle, - secret = base64.encodestring(association.secret), - issued = association.issued, - lifetime = association.issued, - assoc_type = association.assoc_type - ) - assoc.save() - - def getAssociation(self, server_url, handle=None): - assocs = [] - if handle is not None: - assocs = Association.objects.filter( - server_url = server_url, handle = handle - ) - else: - assocs = Association.objects.filter( - server_url = server_url - ) - if not assocs: - return None - associations = [] - for assoc in assocs: - association = OIDAssociation( - assoc.handle, base64.decodestring(assoc.secret), assoc.issued, - assoc.lifetime, assoc.assoc_type - ) - if association.getExpiresIn() == 0: - self.removeAssociation(server_url, assoc.handle) - else: - associations.append((association.issued, association)) - if not associations: - return None - return associations[-1][1] - - def removeAssociation(self, server_url, handle): - assocs = list(Association.objects.filter( - server_url = server_url, handle = handle - )) - assocs_exist = len(assocs) > 0 - for assoc in assocs: - assoc.delete() - return assocs_exist - - def useNonce(self, server_url, timestamp, salt): - if abs(timestamp - time.time()) > openid.store.nonce.SKEW: - return False - - query = [ - Q(server_url__exact=server_url), - Q(timestamp__exact=timestamp), - Q(salt__exact=salt), - ] - try: - ononce = Nonce.objects.get(reduce(operator.and_, query)) - except Nonce.DoesNotExist: - ononce = Nonce( - server_url=server_url, - timestamp=timestamp, - salt=salt - ) - ononce.save() - return True - - ononce.delete() - - return False - - def cleanupNonce(self): - Nonce.objects.filter(timestamp<int(time.time()) - nonce.SKEW).delete() - - def cleanupAssociations(self): - Association.objects.extra(where=['issued + lifetimeint<(%s)' % time.time()]).delete() - - def getAuthKey(self): - # Use first AUTH_KEY_LEN characters of md5 hash of SECRET_KEY - return hashlib.md5(settings.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN] - - def isDumb(self): - return False - -def from_openid_response(openid_response): - """ return openid object from response """ - issued = int(time.time()) - sreg_resp = sreg.SRegResponse.fromSuccessResponse(openid_response) \ - or [] - - return OpenID( - openid_response.identity_url, issued, openid_response.signed_fields, - dict(sreg_resp) - ) diff --git a/django_authopenid/views.py b/django_authopenid/views.py deleted file mode 100755 index 7c7d9e07..00000000 --- a/django_authopenid/views.py +++ /dev/null @@ -1,1169 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2007, 2008, Benoît Chesneau -# Copyright (c) 2007 Simon Willison, original work on django-openid -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# * notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# * notice, this list of conditions and the following disclaimer in the -# * documentation and/or other materials provided with the -# * distribution. Neither the name of the <ORGANIZATION> nor the names -# * of its contributors may be used to endorse or promote products -# * derived from this software without specific prior written -# * permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from django.http import HttpResponseRedirect, get_host, Http404, \ - HttpResponseServerError -from django.shortcuts import render_to_response -from django.template import RequestContext, loader, Context -from django.conf import settings -from django.contrib.auth.models import User -from django.contrib.auth.decorators import login_required -from django.contrib.auth import authenticate -from django.core.urlresolvers import reverse -from django.utils.encoding import smart_unicode -from django.utils.html import escape -from django.utils.translation import ugettext as _ -from django.utils.http import urlquote_plus -from django.utils.safestring import mark_safe -from django.core.mail import send_mail -from django.views.defaults import server_error - -from openid.consumer.consumer import Consumer, \ - SUCCESS, CANCEL, FAILURE, SETUP_NEEDED -from openid.consumer.discover import DiscoveryFailure -from openid.extensions import sreg -# needed for some linux distributions like debian -try: - from openid.yadis import xri -except ImportError: - from yadis import xri - -import re -import urllib - -from forum.forms import SimpleEmailSubscribeForm -from django_authopenid.util import OpenID, DjangoOpenIDStore, from_openid_response -from django_authopenid.models import UserAssociation, UserPasswordQueue, ExternalLoginData -from django_authopenid.forms import OpenidSigninForm, ClassicLoginForm, OpenidRegisterForm, \ - OpenidVerifyForm, ClassicRegisterForm, ChangePasswordForm, ChangeEmailForm, \ - ChangeopenidForm, DeleteForm, EmailPasswordForm -import logging -from forum.utils.forms import get_next_url - -EXTERNAL_LOGIN_APP = settings.LOAD_EXTERNAL_LOGIN_APP() - -def login(request,user): - from django.contrib.auth import login as _login - from forum.models import user_logged_in #custom signal - - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - EXTERNAL_LOGIN_APP.api.login(request,user) - - #1) get old session key - session_key = request.session.session_key - #2) login and get new session key - _login(request,user) - #3) send signal with old session key as argument - logging.debug('logged in user %s with session key %s' % (user.username, session_key)) - user_logged_in.send(user=user,session_key=session_key,sender=None) - -def logout(request): - from django.contrib.auth import logout as _logout#for login I've added wrapper below - called login - _logout(request) - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - EXTERNAL_LOGIN_APP.api.logout(request) - -def get_url_host(request): - if request.is_secure(): - protocol = 'https' - else: - protocol = 'http' - host = escape(get_host(request)) - return '%s://%s' % (protocol, host) - -def get_full_url(request): - return get_url_host(request) + request.get_full_path() - -def ask_openid(request, openid_url, redirect_to, on_failure=None, - sreg_request=None): - """ basic function to ask openid and return response """ - request.encoding = 'UTF-8' - on_failure = on_failure or signin_failure - - trust_root = getattr( - settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/' - ) - if xri.identifierScheme(openid_url) == 'XRI' and getattr( - settings, 'OPENID_DISALLOW_INAMES', False - ): - msg = _("i-names are not supported") - logging.debug('openid failed becaise i-names are not supported') - return on_failure(request, msg) - consumer = Consumer(request.session, DjangoOpenIDStore()) - try: - auth_request = consumer.begin(openid_url) - except DiscoveryFailure: - msg = _(u"OpenID %(openid_url)s is invalid" % {'openid_url':openid_url}) - logging.debug(msg) - return on_failure(request, msg) - - logging.debug('openid seemed to work') - if sreg_request: - logging.debug('adding sreg_request - wtf it is?') - auth_request.addExtension(sreg_request) - redirect_url = auth_request.redirectURL(trust_root, redirect_to) - logging.debug('redirecting to %s' % redirect_url) - return HttpResponseRedirect(redirect_url) - -def complete(request, on_success=None, on_failure=None, return_to=None): - """ complete openid signin """ - on_success = on_success or default_on_success - on_failure = on_failure or default_on_failure - - logging.debug('in django_authopenid.complete') - - consumer = Consumer(request.session, DjangoOpenIDStore()) - # make sure params are encoded in utf8 - params = dict((k,smart_unicode(v)) for k, v in request.GET.items()) - openid_response = consumer.complete(params, return_to) - - if openid_response.status == SUCCESS: - logging.debug('SUCCESS') - return on_success(request, openid_response.identity_url, - openid_response) - elif openid_response.status == CANCEL: - logging.debug('CANCEL') - return on_failure(request, 'The request was canceled') - elif openid_response.status == FAILURE: - logging.debug('FAILURE') - return on_failure(request, openid_response.message) - elif openid_response.status == SETUP_NEEDED: - logging.debug('SETUP NEEDED') - return on_failure(request, 'Setup needed') - else: - logging.debug('BAD OPENID STATUS') - assert False, "Bad openid status: %s" % openid_response.status - -def default_on_success(request, identity_url, openid_response): - """ default action on openid signin success """ - logging.debug('') - request.session['openid'] = from_openid_response(openid_response) - logging.debug('performing default action on openid success %s' % get_next_url(request)) - return HttpResponseRedirect(get_next_url(request)) - -def default_on_failure(request, message): - """ default failure action on signin """ - logging.debug('default openid failure action') - return render_to_response('openid_failure.html', { - 'message': message - }) - - -def not_authenticated(func): - """ decorator that redirect user to next page if - he is already logged.""" - def decorated(request, *args, **kwargs): - if request.user.is_authenticated(): - return HttpResponseRedirect(get_next_url(request)) - return func(request, *args, **kwargs) - return decorated - -@not_authenticated -def signin(request,newquestion=False,newanswer=False): - """ - signin page. It manages the legacy authentification (user/password) - and openid authentification - - url: /signin/ - - template : authopenid/signin.htm - """ - logging.debug('in signin view') - request.encoding = 'UTF-8' - on_failure = signin_failure - email_feeds_form = SimpleEmailSubscribeForm() - next = get_next_url(request) - form_signin = OpenidSigninForm(initial={'next':next}) - form_auth = ClassicLoginForm(initial={'next':next}) - - if request.method == 'POST': - #'blogin' - password login - if 'blogin' in request.POST.keys(): - logging.debug('processing classic login form submission') - form_auth = ClassicLoginForm(request.POST) - if form_auth.is_valid(): - #have login and password and need to login through external website - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - username = form_auth.cleaned_data['username'] - password = form_auth.cleaned_data['password'] - next = form_auth.cleaned_data['next'] - if form_auth.get_user() == None: - #need to create internal user - - #1) save login and password temporarily in session - request.session['external_username'] = username - request.session['external_password'] = password - - #2) try to extract user email and nickname from external service - email = EXTERNAL_LOGIN_APP.api.get_email(username,password) - screen_name = EXTERNAL_LOGIN_APP.api.get_screen_name(username,password) - - #3) see if username clashes with some existing user - #if so, we have to prompt the user to pick a different name - username_taken = User.is_username_taken(screen_name) - - email_feeds_form = SimpleEmailSubscribeForm() - form_data = {'username':screen_name,'email':email,'next':next} - form = OpenidRegisterForm(initial=form_data) - template_data = {'form1':form,'username':screen_name,\ - 'email_feeds_form':email_feeds_form,\ - 'provider':mark_safe(settings.EXTERNAL_LEGACY_LOGIN_PROVIDER_NAME),\ - 'login_type':'legacy',\ - 'gravatar_faq_url':reverse('faq') + '#gravatar',\ - 'external_login_name_is_taken':username_taken} - return render_to_response('authopenid/complete.html',template_data,\ - context_instance=RequestContext(request)) - else: - #user existed, external password is ok - user = form_auth.get_user() - login(request,user) - response = HttpResponseRedirect(get_next_url(request)) - EXTERNAL_LOGIN_APP.api.set_login_cookies(response,user) - return response - else: - #regular password authentication - user = form_auth.get_user() - login(request, user) - return HttpResponseRedirect(get_next_url(request)) - - elif 'bnewaccount' in request.POST.keys(): - logging.debug('processing classic (login/password) create account form submission') - #register externally logged in password user with a new local account - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - form = OpenidRegisterForm(request.POST) - email_feeds_form = SimpleEmailSubscribeForm(request.POST) - form1_is_valid = form.is_valid() - form2_is_valid = email_feeds_form.is_valid() - if form1_is_valid and form2_is_valid: - #create the user - username = form.cleaned_data['username'] - password = request.session.get('external_password',None) - email = form.cleaned_data['email'] - if password and username: - User.objects.create_user(username,email,password) - user = authenticate(username=username,password=password) - EXTERNAL_LOGIN_APP.api.connect_local_user_to_external_user(user,username,password) - external_username = request.session['external_username'] - eld = ExternalLoginData.objects.get(external_username=external_username) - eld.user = user - eld.save() - login(request,user) - email_feeds_form.save(user) - del request.session['external_username'] - del request.session['external_password'] - response = HttpResponseRedirect(reverse('index')) - EXTERNAL_LOGIN_APP.api.set_login_cookies(response, user) - return response - else: - if password: - del request.session['external_username'] - if username: - del request.session['external_password'] - return HttpResponseServerError() - else: - username = request.POST.get('username',None) - provider = mark_safe(settings.EXTERNAL_LEGACY_LOGIN_PROVIDER_NAME) - username_taken = User.is_username_taken(username) - data = {'login_type':'legacy','form1':form,'username':username,\ - 'email_feeds_form':email_feeds_form,'provider':provider,\ - 'gravatar_faq_url':reverse('faq') + '#gravatar',\ - 'external_login_name_is_taken':username_taken} - return render_to_response('authopenid/complete.html',data, - context_instance=RequestContext(request)) - else: - raise Http404 - - elif 'bsignin' in request.POST.keys() or 'openid_username' in request.POST.keys(): - logging.debug('processing signin with openid submission') - form_signin = OpenidSigninForm(request.POST) - if form_signin.is_valid(): - logging.debug('OpenidSigninForm is valid') - next = form_signin.cleaned_data['next'] - sreg_req = sreg.SRegRequest(optional=['nickname', 'email']) - redirect_to = "%s%s?%s" % ( - get_url_host(request), - reverse('user_complete_signin'), - urllib.urlencode({'next':next}) - ) - return ask_openid(request, - form_signin.cleaned_data['openid_url'], - redirect_to, - on_failure=signin_failure, - sreg_request=sreg_req) - else: - logging.debug('OpenidSigninForm is NOT valid! -> redisplay login view') - - #if request is GET - if request.method == 'GET': - logging.debug('request method was GET') - question = None - if newquestion == True: - from forum.models import AnonymousQuestion as AQ - session_key = request.session.session_key - logging.debug('retrieving anonymously posted question associated with session %s' % session_key) - qlist = AQ.objects.filter(session_key=session_key).order_by('-added_at') - if len(qlist) > 0: - question = qlist[0] - answer = None - if newanswer == True: - from forum.models import AnonymousAnswer as AA - session_key = request.session.session_key - logging.debug('retrieving posted answer associated with session %s' % session_key) - alist = AA.objects.filter(session_key=session_key).order_by('-added_at') - if len(alist) > 0: - answer = alist[0] - - logging.debug('showing signin view') - return render_to_response('authopenid/signin.html', { - 'question':question, - 'answer':answer, - 'form1': form_auth, - 'form2': form_signin, - 'msg': request.GET.get('msg',''), - 'sendpw_url': reverse('user_sendpw'), - 'fb_api_key': settings.FB_API_KEY, - }, context_instance=RequestContext(request)) - -def complete_signin(request): - """ in case of complete signin with openid """ - logging.debug('')#blank log just for the trace - return complete(request, signin_success, signin_failure, - get_url_host(request) + reverse('user_complete_signin')) - -def signin_success(request, identity_url, openid_response): - """ - openid signin success. - - If the openid is already registered, the user is redirected to - url set par next or in settings with OPENID_REDIRECT_NEXT variable. - If none of these urls are set user is redirectd to /. - - if openid isn't registered user is redirected to register page. - """ - - logging.debug('') - openid_ = from_openid_response(openid_response) #create janrain OpenID object - request.session['openid'] = openid_ - try: - logging.debug('trying to get user associated with this openid...') - rel = UserAssociation.objects.get(openid_url__exact = str(openid_)) - logging.debug('success') - except: - logging.debug('failed --> try to register brand new user') - # try to register this new user - return register(request) - user_ = rel.user - if user_.is_active: - user_.backend = "django.contrib.auth.backends.ModelBackend" - logging.debug('user is active --> attached django auth ModelBackend --> calling login') - login(request, user_) - logging.debug('success') - else: - logging.debug('user is inactive, do not log them in') - logging.debug('redirecting to %s' % get_next_url(request)) - return HttpResponseRedirect(get_next_url(request)) - -def is_association_exist(openid_url): - """ test if an openid is already in database """ - is_exist = True - try: - uassoc = UserAssociation.objects.get(openid_url__exact = openid_url) - except: - is_exist = False - logging.debug(str(is_exist)) - return is_exist - -@not_authenticated -def register(request): - """ - register an openid. - - If user is already a member he can associate its openid with - its account. - - A new account could also be created and automaticaly associated - to the openid. - - url : /complete/ - - template : authopenid/complete.html - """ - - logging.debug('') - openid_ = request.session.get('openid', None) - next = get_next_url(request) - if not openid_: - logging.debug('oops, no openid in session --> go back to signin') - return HttpResponseRedirect(reverse('user_signin') + '?next=%s' % next) - - nickname = openid_.sreg.get('nickname', '') - email = openid_.sreg.get('email', '') - form1 = OpenidRegisterForm(initial={ - 'next': next, - 'username': nickname, - 'email': email, - }) - form2 = OpenidVerifyForm(initial={ - 'next': next, - 'username': nickname, - }) - email_feeds_form = SimpleEmailSubscribeForm() - - user_ = None - is_redirect = False - logging.debug('request method is %s' % request.method) - if request.method == 'POST': - if 'bnewaccount' in request.POST.keys(): - logging.debug('trying to create new account associated with openid') - form1 = OpenidRegisterForm(request.POST) - email_feeds_form = SimpleEmailSubscribeForm(request.POST) - if not form1.is_valid(): - logging.debug('OpenidRegisterForm is INVALID') - elif not email_feeds_form.is_valid(): - logging.debug('SimpleEmailSubscribeForm is INVALID') - else: - logging.debug('OpenidRegisterForm and SimpleEmailSubscribeForm are valid') - next = form1.cleaned_data['next'] - is_redirect = True - logging.debug('creatng new django user %s ...' % form1.cleaned_data['username']) - tmp_pwd = User.objects.make_random_password() - user_ = User.objects.create_user(form1.cleaned_data['username'], - form1.cleaned_data['email'], tmp_pwd) - - user_.set_unusable_password() - # make association with openid - logging.debug('creating new openid user association %s <--> %s' \ - % (user_.username, str(openid_))) - uassoc = UserAssociation(openid_url=str(openid_), user_id=user_.id) - uassoc.save() - - # login - user_.backend = "django.contrib.auth.backends.ModelBackend" - logging.debug('logging the user in') - login(request, user_) - logging.debug('saving email feed settings') - email_feeds_form.save(user_) - elif 'bverify' in request.POST.keys(): - logging.debug('processing OpenidVerify form') - form2 = OpenidVerifyForm(request.POST) - if form2.is_valid(): - logging.debug('form is valid') - is_redirect = True - next = form2.cleaned_data['next'] - user_ = form2.get_user() - logging.debug('creating new openid user association %s <--> %s' \ - % (user_.username, str(openid_))) - uassoc = UserAssociation(openid_url=str(openid_), - user_id=user_.id) - uassoc.save() - logging.debug('logging the user in') - login(request, user_) - - #check if we need to post a question that was added anonymously - #this needs to be a function call becase this is also done - #if user just logged in and did not need to create the new account - - if user_ != None: - if settings.EMAIL_VALIDATION == 'on': - logging.debug('sending email validation') - send_new_email_key(user_,nomessage=True) - output = validation_email_sent(request) - set_email_validation_message(user_) #message set after generating view - return output - if user_.is_authenticated(): - logging.debug('success, send user to main page') - return HttpResponseRedirect(reverse('index')) - else: - logging.debug('have really strange error') - raise Exception('openid login failed')#should not ever get here - - openid_str = str(openid_) - bits = openid_str.split('/') - base_url = bits[2] #assume this is base url - url_bits = base_url.split('.') - provider_name = url_bits[-2].lower() - - providers = {'yahoo':'<font color="purple">Yahoo!</font>', - 'flickr':'<font color="#0063dc">flick</font><font color="#ff0084">r</font>™', - 'google':'Google™', - 'aol':'<font color="#31658e">AOL</font>', - 'myopenid':'MyOpenID', - } - if provider_name not in providers: - provider_logo = provider_name - logging.error('openid provider named "%s" has no pretty customized logo' % provider_name) - else: - provider_logo = providers[provider_name] - - logging.debug('printing authopenid/complete.html output') - return render_to_response('authopenid/complete.html', { - 'form1': form1, - 'form2': form2, - 'email_feeds_form': email_feeds_form, - 'provider':mark_safe(provider_logo), - 'username': nickname, - 'email': email, - 'login_type':'openid', - 'gravatar_faq_url':reverse('faq') + '#gravatar', - }, context_instance=RequestContext(request)) - -def signin_failure(request, message): - """ - falure with openid signin. Go back to signin page. - - template : "authopenid/signin.html" - """ - logging.debug('') - next = get_next_url(request) - form_signin = OpenidSigninForm(initial={'next': next}) - form_auth = ClassicLoginForm(initial={'next': next}) - - return render_to_response('authopenid/signin.html', { - 'msg': message, - 'form1': form_auth, - 'form2': form_signin, - }, context_instance=RequestContext(request)) - -@not_authenticated -def signup(request): - """ - signup page. Create a legacy account - - url : /signup/" - - templates: authopenid/signup.html, authopenid/confirm_email.txt - """ - logging.debug('') - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - logging.debug('handling external legacy login registration') - return HttpResponseRedirect(reverse('user_external_legacy_login_signup')) - next = get_next_url(request) - logging.debug('request method was %s' % request.method) - if request.method == 'POST': - form = ClassicRegisterForm(request.POST) - email_feeds_form = SimpleEmailSubscribeForm(request.POST) - - #validation outside if to remember form values - form1_is_valid = form.is_valid() - form2_is_valid = email_feeds_form.is_valid() - if form1_is_valid and form2_is_valid: - next = form.cleaned_data['next'] - username = form.cleaned_data['username'] - password = form.cleaned_data['password1'] - email = form.cleaned_data['email'] - - user_ = User.objects.create_user( username,email,password ) - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - EXTERNAL_LOGIN_APP.api.create_user(username,email,password) - - user_.backend = "django.contrib.auth.backends.ModelBackend" - login(request, user_) - email_feeds_form.save(user_) - - # send email - subject = _("Welcome email subject line") - message_template = loader.get_template( - 'authopenid/confirm_email.txt' - ) - message_context = Context({ - 'signup_url': settings.APP_URL + reverse('user_signin'), - 'username': username, - 'password': password, - }) - message = message_template.render(message_context) - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, - [user_.email]) - logging.debug('new user with login and password created!') - return HttpResponseRedirect(next) - else: - logging.debug('create classic account forms were invalid') - else: - form = ClassicRegisterForm(initial={'next':next}) - email_feeds_form = SimpleEmailSubscribeForm() - logging.debug('printing legacy signup form') - return render_to_response('authopenid/signup.html', { - 'form': form, - 'email_feeds_form': email_feeds_form - }, context_instance=RequestContext(request)) - #what if request is not posted? - -@login_required -def signout(request): - """ - signout from the website. Remove openid from session and kill it. - - url : /signout/" - """ - logging.debug('') - try: - logging.debug('deleting openid session var') - del request.session['openid'] - except KeyError: - logging.debug('failed') - pass - logout(request) - logging.debug('user logged out') - return HttpResponseRedirect(get_next_url(request)) - -def xrdf(request): - url_host = get_url_host(request) - logging.debug('what does this do??') - return_to = [ - "%s%s" % (url_host, reverse('user_complete_signin')) - ] - return render_to_response('authopenid/yadis.xrdf', { - 'return_to': return_to - }, context_instance=RequestContext(request)) - -@login_required -def account_settings(request): - """ - index pages to changes some basic account settings : - - change password - - change email - - associate a new openid - - delete account - - url : / - - template : authopenid/settings.html - """ - logging.debug('') - msg = request.GET.get('msg', '') - is_openid = True - - try: - uassoc = UserAssociation.objects.get( - user__username__exact=request.user.username - ) - except: - is_openid = False - - - return render_to_response('authopenid/settings.html', { - 'msg': msg, - 'is_openid': is_openid - }, context_instance=RequestContext(request)) - -@login_required -def changepw(request): - """ - change password view. - - url : /changepw/ - template: authopenid/changepw.html - """ - logging.debug('') - user_ = request.user - - if user_.has_usable_password(): - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - return HttpResponseRedirect(reverse('user_external_legacy_login_issues')) - else: - raise Http404 - - if request.POST: - form = ChangePasswordForm(request.POST, user=user_) - if form.is_valid(): - user_.set_password(form.cleaned_data['password1']) - user_.save() - msg = _("Password changed.") - redirect = "%s?msg=%s" % ( - reverse('user_account_settings'), - urlquote_plus(msg)) - return HttpResponseRedirect(redirect) - else: - form = ChangePasswordForm(user=user_) - - return render_to_response('authopenid/changepw.html', {'form': form }, - context_instance=RequestContext(request)) - -def find_email_validation_messages(user): - msg_text = _('your email needs to be validated see %(details_url)s') \ - % {'details_url':reverse('faq') + '#validate'} - return user.message_set.filter(message__exact=msg_text) - -def set_email_validation_message(user): - messages = find_email_validation_messages(user) - msg_text = _('your email needs to be validated see %(details_url)s') \ - % {'details_url':reverse('faq') + '#validate'} - if len(messages) == 0: - user.message_set.create(message=msg_text) - -def clear_email_validation_message(user): - messages = find_email_validation_messages(user) - messages.delete() - -def set_new_email(user, new_email, nomessage=False): - if new_email != user.email: - user.email = new_email - user.email_isvalid = False - user.save() - if settings.EMAIL_VALIDATION == 'on': - send_new_email_key(user,nomessage=nomessage) - -def _send_email_key(user): - """private function. sends email containing validation key - to user's email address - """ - subject = _("Email verification subject line") - message_template = loader.get_template('authopenid/email_validation.txt') - import settings - message_context = Context({ - 'validation_link': settings.APP_URL + reverse('user_verifyemail', kwargs={'id':user.id,'key':user.email_key}) - }) - message = message_template.render(message_context) - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email]) - -def send_new_email_key(user,nomessage=False): - import random - random.seed() - user.email_key = '%032x' % random.getrandbits(128) - user.save() - _send_email_key(user) - if nomessage==False: - set_email_validation_message(user) - -@login_required -def send_email_key(request): - """ - url = /email/sendkey/ - - view that is shown right after sending email key - email sending is called internally - - raises 404 if email validation is off - if current email is valid shows 'key_not_sent' view of - authopenid/changeemail.html template - """ - - if settings.EMAIL_VALIDATION != 'off': - if request.user.email_isvalid: - return render_to_response('authopenid/changeemail.html', - { 'email': request.user.email, - 'action_type': 'key_not_sent', - 'change_link': reverse('user_changeemail')}, - context_instance=RequestContext(request) - ) - else: - send_new_email_key(request.user) - return validation_email_sent(request) - else: - raise Http404 - - -#internal server view used as return value by other views -def validation_email_sent(request): - logging.debug('') - return render_to_response('authopenid/changeemail.html', - { 'email': request.user.email, - 'change_email_url': reverse('user_changeemail'), - 'action_type': 'validate', }, - context_instance=RequestContext(request)) - -def verifyemail(request,id=None,key=None): - """ - view that is shown when user clicks email validation link - url = /email/verify/{{user.id}}/{{user.email_key}}/ - """ - logging.debug('') - if settings.EMAIL_VALIDATION != 'off': - user = User.objects.get(id=id) - if user: - if user.email_key == key: - user.email_isvalid = True - clear_email_validation_message(user) - user.save() - return render_to_response('authopenid/changeemail.html', { - 'action_type': 'validation_complete', - }, context_instance=RequestContext(request)) - else: - logging.error('hmm, no user found for email validation message - foul play?') - raise Http404 - -@login_required -def changeemail(request, action='change'): - """ - changeemail view. requires openid with request type GET - - url: /email/* - - template : authopenid/changeemail.html - """ - logging.debug('') - msg = request.GET.get('msg', None) - extension_args = {} - user_ = request.user - - if request.POST: - if 'cancel' in request.POST: - msg = _('your email was not changed') - request.user.message_set.create(message=msg) - return HttpResponseRedirect(get_next_url(request)) - form = ChangeEmailForm(request.POST, user=user_) - if form.is_valid(): - new_email = form.cleaned_data['email'] - if new_email != user_.email: - if settings.EMAIL_VALIDATION == 'on': - action = 'validate' - else: - action = 'done_novalidate' - set_new_email(user_, new_email,nomessage=True) - else: - action = 'keep' - - elif not request.POST and 'openid.mode' in request.GET: - redirect_to = get_url_host(request) + reverse('user_changeemail') - return complete(request, emailopenid_success, - emailopenid_failure, redirect_to) - else: - form = ChangeEmailForm(initial={'email': user_.email}, - user=user_) - - output = render_to_response('authopenid/changeemail.html', { - 'form': form, - 'email': user_.email, - 'action_type': action, - 'gravatar_faq_url': reverse('faq') + '#gravatar', - 'change_email_url': reverse('user_changeemail'), - 'msg': msg - }, context_instance=RequestContext(request)) - - if action == 'validate': - set_email_validation_message(user_) - - return output - -def emailopenid_success(request, identity_url, openid_response): - logging.debug('') - openid_ = from_openid_response(openid_response) - - user_ = request.user - try: - uassoc = UserAssociation.objects.get( - openid_url__exact=identity_url - ) - except: - return emailopenid_failure(request, - _("No OpenID %s found associated in our database" % identity_url)) - - if uassoc.user.username != request.user.username: - return emailopenid_failure(request, - _("The OpenID %s isn't associated to current user logged in" % - identity_url)) - - new_email = request.session.get('new_email', '') - if new_email: - user_.email = new_email - user_.save() - del request.session['new_email'] - msg = _("Email Changed.") - - redirect = "%s?msg=%s" % (reverse('user_account_settings'), - urlquote_plus(msg)) - return HttpResponseRedirect(redirect) - - -def emailopenid_failure(request, message): - logging.debug('') - redirect_to = "%s?msg=%s" % ( - reverse('user_changeemail'), urlquote_plus(message)) - return HttpResponseRedirect(redirect_to) - -@login_required -def changeopenid(request): - """ - change openid view. Allow user to change openid - associated to its username. - - url : /changeopenid/ - - template: authopenid/changeopenid.html - """ - logging.error('change openid view - never tested it yet!!!') - - extension_args = {} - openid_url = '' - has_openid = True - msg = request.GET.get('msg', '') - - user_ = request.user - - try: - uopenid = UserAssociation.objects.get(user=user_) - openid_url = uopenid.openid_url - except: - has_openid = False - - redirect_to = get_url_host(request) + reverse('user_changeopenid') - if request.POST and has_openid: - form = ChangeopenidForm(request.POST, user=user_) - if form.is_valid(): - return ask_openid(request, form.cleaned_data['openid_url'], - redirect_to, on_failure=changeopenid_failure) - elif not request.POST and has_openid: - if 'openid.mode' in request.GET: - return complete(request, changeopenid_success, - changeopenid_failure, redirect_to) - - form = ChangeopenidForm(initial={'openid_url': openid_url }, user=user_) - return render_to_response('authopenid/changeopenid.html', { - 'form': form, - 'has_openid': has_openid, - 'msg': msg - }, context_instance=RequestContext(request)) - -def changeopenid_success(request, identity_url, openid_response): - logging.error('never tested this worflow') - openid_ = from_openid_response(openid_response) - is_exist = True - try: - uassoc = UserAssociation.objects.get(openid_url__exact=identity_url) - except: - is_exist = False - - if not is_exist: - try: - uassoc = UserAssociation.objects.get( - user__username__exact=request.user.username - ) - uassoc.openid_url = identity_url - uassoc.save() - except: - uassoc = UserAssociation(user=request.user, - openid_url=identity_url) - uassoc.save() - elif uassoc.user.username != request.user.username: - return changeopenid_failure(request, - _('This OpenID is already associated with another account.')) - - request.session['openids'] = [] - request.session['openids'].append(openid_) - - msg = _("OpenID %s is now associated with your account." % identity_url) - redirect = "%s?msg=%s" % ( - reverse('user_account_settings'), - urlquote_plus(msg)) - return HttpResponseRedirect(redirect) - - -def changeopenid_failure(request, message): - logging.error('never tested this workflow') - redirect_to = "%s?msg=%s" % ( - reverse('user_changeopenid'), - urlquote_plus(message)) - return HttpResponseRedirect(redirect_to) - -@login_required -def delete(request): - """ - delete view. Allow user to delete its account. Password/openid are required to - confirm it. He should also check the confirm checkbox. - - url : /delete - - template : authopenid/delete.html - """ - logging.error('deleting account - never tested this') - - extension_args = {} - - user_ = request.user - - redirect_to = get_url_host(request) + reverse('user_delete') - if request.POST: - form = DeleteForm(request.POST, user=user_) - if form.is_valid(): - if not form.test_openid: - user_.delete() - return signout(request) - else: - return ask_openid(request, form.cleaned_data['password'], - redirect_to, on_failure=deleteopenid_failure) - elif not request.POST and 'openid.mode' in request.GET: - return complete(request, deleteopenid_success, deleteopenid_failure, - redirect_to) - - form = DeleteForm(user=user_) - - msg = request.GET.get('msg','') - return render_to_response('authopenid/delete.html', { - 'form': form, - 'msg': msg, - }, context_instance=RequestContext(request)) - -def deleteopenid_success(request, identity_url, openid_response): - logging.error('never tested this') - openid_ = from_openid_response(openid_response) - - user_ = request.user - try: - uassoc = UserAssociation.objects.get( - openid_url__exact=identity_url - ) - except: - return deleteopenid_failure(request, - _("No OpenID %s found associated in our database" % identity_url)) - - if uassoc.user.username == user_.username: - user_.delete() - return signout(request) - else: - return deleteopenid_failure(request, - _("The OpenID %s isn't associated to current user logged in" % - identity_url)) - - msg = _("Account deleted.") - redirect = reverse('index') + u"/?msg=%s" % (urlquote_plus(msg)) - return HttpResponseRedirect(redirect) - - -def deleteopenid_failure(request, message): - logging.error('never tested this') - redirect_to = "%s?msg=%s" % (reverse('user_delete'), urlquote_plus(message)) - return HttpResponseRedirect(redirect_to) - -def external_legacy_login_info(request): - logging.debug('maybe this view does not belong in this library') - feedback_url = reverse('feedback') - return render_to_response('authopenid/external_legacy_login_info.html', - {'feedback_url':feedback_url}, - context_instance=RequestContext(request)) - -def sendpw(request): - """ - send a new password to the user. It return a mail with - a new pasword and a confirm link in. To activate the - new password, the user should click on confirm link. - - url : /sendpw/ - - templates : authopenid/sendpw_email.txt, authopenid/sendpw.html - """ - logging.debug('') - if settings.USE_EXTERNAL_LEGACY_LOGIN == True: - logging.debug('delegating to view dealing with external password recovery') - return HttpResponseRedirect(reverse('user_external_legacy_login_issues')) - - msg = request.GET.get('msg','') - logging.debug('request method is %s' % request.method) - if request.method == 'POST': - form = EmailPasswordForm(request.POST) - if form.is_valid(): - logging.debug('EmailPasswordForm is valid') - new_pw = User.objects.make_random_password() - confirm_key = UserPasswordQueue.objects.get_new_confirm_key() - try: - uqueue = UserPasswordQueue.objects.get( - user=form.user_cache - ) - except: - uqueue = UserPasswordQueue( - user=form.user_cache - ) - uqueue.new_password = new_pw - uqueue.confirm_key = confirm_key - uqueue.save() - # send email - subject = _("Request for new password") - message_template = loader.get_template( - 'authopenid/sendpw_email.txt') - key_link = settings.APP_URL + reverse('user_confirmchangepw') + '?key=' + confirm_key - logging.debug('emailing new password for %s' % form.user_cache.username) - message_context = Context({ - 'site_url': settings.APP_URL + reverse('index'), - 'key_link': key_link, - 'username': form.user_cache.username, - 'password': new_pw, - }) - message = message_template.render(message_context) - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, - [form.user_cache.email]) - msg = _("A new password and the activation link were sent to your email address.") - else: - form = EmailPasswordForm() - - logging.debug('showing reset password form') - return render_to_response('authopenid/sendpw.html', { - 'form': form, - 'msg': msg - }, context_instance=RequestContext(request)) - -def confirmchangepw(request): - """ - view to set new password when the user click on confirm link - in its mail. Basically it check if the confirm key exist, then - replace old password with new password and remove confirm - ley from the queue. Then it redirect the user to signin - page. - - url : /sendpw/confirm/?key - - """ - logging.debug('') - confirm_key = request.GET.get('key', '') - if not confirm_key: - logging.error('someone called confirm password without a key!') - return HttpResponseRedirect(reverse('index')) - - try: - uqueue = UserPasswordQueue.objects.get( - confirm_key__exact=confirm_key - ) - except: - msg = _("Could not change password. Confirmation key '%s'\ - is not registered." % confirm_key) - logging.error(msg) - redirect = "%s?msg=%s" % ( - reverse('user_sendpw'), urlquote_plus(msg)) - return HttpResponseRedirect(redirect) - - try: - user_ = User.objects.get(id=uqueue.user.id) - except: - msg = _("Can not change password. User don't exist anymore \ - in our database.") - logging.error(msg) - redirect = "%s?msg=%s" % (reverse('user_sendpw'), - urlquote_plus(msg)) - return HttpResponseRedirect(redirect) - - user_.set_password(uqueue.new_password) - user_.save() - uqueue.delete() - msg = _("Password changed for %s. You may now sign in." % - user_.username) - logging.debug(msg) - redirect = "%s?msg=%s" % (reverse('user_signin'), - urlquote_plus(msg)) - - return HttpResponseRedirect(redirect) diff --git a/fbconnect/__init__.py b/fbconnect/__init__.py deleted file mode 100755 index e69de29b..00000000 --- a/fbconnect/__init__.py +++ /dev/null diff --git a/fbconnect/fb.py b/fbconnect/fb.py deleted file mode 100755 index afcd8210..00000000 --- a/fbconnect/fb.py +++ /dev/null @@ -1,96 +0,0 @@ -from django.conf import settings -from time import time -from datetime import datetime -from urllib import urlopen, urlencode - -try: - from json import load as load_json -except: - from pjson import fread as load_json - -from models import FBAssociation -import hashlib -import logging - -REST_SERVER = 'http://api.facebook.com/restserver.php' - -def generate_sig(values): - keys = [] - - for key in sorted(values.keys()): - keys.append(key) - - signature = ''.join(['%s=%s' % (key, values[key]) for key in keys]) + settings.FB_SECRET - return hashlib.md5(signature).hexdigest() - -def check_cookies_signature(cookies): - API_KEY = settings.FB_API_KEY - - values = {} - - for key in cookies.keys(): - if (key.startswith(API_KEY + '_')): - values[key.replace(API_KEY + '_', '')] = cookies[key] - - return generate_sig(values) == cookies[API_KEY] - -def get_user_data(cookies): - request_data = { - 'method': 'Users.getInfo', - 'api_key': settings.FB_API_KEY, - 'call_id': time(), - 'v': '1.0', - 'uids': cookies[settings.FB_API_KEY + '_user'], - 'fields': 'name,first_name,last_name', - 'format': 'json', - } - - request_data['sig'] = generate_sig(request_data) - fb_response = urlopen(REST_SERVER, urlencode(request_data)) - #print(fb_response) - return load_json(fb_response)[0] - - -def delete_cookies(response): - API_KEY = settings.FB_API_KEY - - response.delete_cookie(API_KEY + '_user') - response.delete_cookie(API_KEY + '_session_key') - response.delete_cookie(API_KEY + '_expires') - response.delete_cookie(API_KEY + '_ss') - response.delete_cookie(API_KEY) - response.delete_cookie('fbsetting_' + API_KEY) - -def check_session_expiry(cookies): - return datetime.fromtimestamp(float(cookies[settings.FB_API_KEY+'_expires'])) > datetime.now() - -STATES = { - 'FIRSTTIMER': 1, - 'SESSIONEXPIRED': 2, - 'RETURNINGUSER': 3, - 'INVALIDSTATE': 4, -} - -def get_user_state(request): - API_KEY = settings.FB_API_KEY - logging.debug('') - - if API_KEY in request.COOKIES: - logging.debug('FB API key is in request cookies') - if check_cookies_signature(request.COOKIES): - logging.debug('FB cookie signature is fine') - if check_session_expiry(request.COOKIES): - logging.debug('FB session is not expired') - try: - uassoc = FBAssociation.objects.get(fbuid=request.COOKIES[API_KEY + '_user']) - logging.debug('found existing FB user association') - return (STATES['RETURNINGUSER'], uassoc.user) - except: - logging.debug('dont have FB association for this user') - return (STATES['FIRSTTIMER'], get_user_data(request.COOKIES)) - else: - logging.debug('FB session expired') - return (STATES['SESSIONEXPIRED'], None) - logging.debug('FB state is INVALID') - - return (STATES['INVALIDSTATE'], None) diff --git a/fbconnect/forms.py b/fbconnect/forms.py deleted file mode 100755 index 94f86816..00000000 --- a/fbconnect/forms.py +++ /dev/null @@ -1,8 +0,0 @@ -from django_authopenid.forms import NextUrlField, UserNameField, UserEmailField - -from django import forms - -class FBConnectRegisterForm(forms.Form): - next = NextUrlField() - username = UserNameField() - email = UserEmailField() diff --git a/fbconnect/models.py b/fbconnect/models.py deleted file mode 100755 index 2172217d..00000000 --- a/fbconnect/models.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - -class FBAssociation(models.Model): - user = models.ForeignKey(User) - fbuid = models.CharField(max_length=12, unique=True) diff --git a/fbconnect/pjson.py b/fbconnect/pjson.py deleted file mode 100755 index 273b684e..00000000 --- a/fbconnect/pjson.py +++ /dev/null @@ -1,313 +0,0 @@ -import string -import types - -## json.py implements a JSON (http://json.org) reader and writer. -## Copyright (C) 2005 Patrick D. Logan -## Contact mailto:patrickdlogan@stardecisions.com -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Lesser General Public -## License as published by the Free Software Foundation; either -## version 2.1 of the License, or (at your option) any later version. -## -## This library is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## Lesser General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -class _StringGenerator(object): - def __init__(self, string): - self.string = string - self.index = -1 - def peek(self): - i = self.index + 1 - if i < len(self.string): - return self.string[i] - else: - return None - def next(self): - self.index += 1 - if self.index < len(self.string): - return self.string[self.index] - else: - raise StopIteration - def all(self): - return self.string - -class WriteException(Exception): - pass - -class ReadException(Exception): - pass - -class JsonReader(object): - hex_digits = {'A': 10,'B': 11,'C': 12,'D': 13,'E': 14,'F':15} - escapes = {'t':'\t','n':'\n','f':'\f','r':'\r','b':'\b'} - - def read(self, s): - self._generator = _StringGenerator(s) - result = self._read() - return result - - def _read(self): - self._eatWhitespace() - peek = self._peek() - if peek is None: - raise ReadException, "Nothing to read: '%s'" % self._generator.all() - if peek == '{': - return self._readObject() - elif peek == '[': - return self._readArray() - elif peek == '"': - return self._readString() - elif peek == '-' or peek.isdigit(): - return self._readNumber() - elif peek == 't': - return self._readTrue() - elif peek == 'f': - return self._readFalse() - elif peek == 'n': - return self._readNull() - elif peek == '/': - self._readComment() - return self._read() - else: - raise ReadException, "Input is not valid JSON: '%s'" % self._generator.all() - - def _readTrue(self): - self._assertNext('t', "true") - self._assertNext('r', "true") - self._assertNext('u', "true") - self._assertNext('e', "true") - return True - - def _readFalse(self): - self._assertNext('f', "false") - self._assertNext('a', "false") - self._assertNext('l', "false") - self._assertNext('s', "false") - self._assertNext('e', "false") - return False - - def _readNull(self): - self._assertNext('n', "null") - self._assertNext('u', "null") - self._assertNext('l', "null") - self._assertNext('l', "null") - return None - - def _assertNext(self, ch, target): - if self._next() != ch: - raise ReadException, "Trying to read %s: '%s'" % (target, self._generator.all()) - - def _readNumber(self): - isfloat = False - result = self._next() - peek = self._peek() - while peek is not None and (peek.isdigit() or peek == "."): - isfloat = isfloat or peek == "." - result = result + self._next() - peek = self._peek() - try: - if isfloat: - return float(result) - else: - return int(result) - except ValueError: - raise ReadException, "Not a valid JSON number: '%s'" % result - - def _readString(self): - result = "" - assert self._next() == '"' - try: - while self._peek() != '"': - ch = self._next() - if ch == "\\": - ch = self._next() - if ch in 'brnft': - ch = self.escapes[ch] - elif ch == "u": - ch4096 = self._next() - ch256 = self._next() - ch16 = self._next() - ch1 = self._next() - n = 4096 * self._hexDigitToInt(ch4096) - n += 256 * self._hexDigitToInt(ch256) - n += 16 * self._hexDigitToInt(ch16) - n += self._hexDigitToInt(ch1) - ch = unichr(n) - elif ch not in '"/\\': - raise ReadException, "Not a valid escaped JSON character: '%s' in %s" % (ch, self._generator.all()) - result = result + ch - except StopIteration: - raise ReadException, "Not a valid JSON string: '%s'" % self._generator.all() - assert self._next() == '"' - return result - - def _hexDigitToInt(self, ch): - try: - result = self.hex_digits[ch.upper()] - except KeyError: - try: - result = int(ch) - except ValueError: - raise ReadException, "The character %s is not a hex digit." % ch - return result - - def _readComment(self): - assert self._next() == "/" - second = self._next() - if second == "/": - self._readDoubleSolidusComment() - elif second == '*': - self._readCStyleComment() - else: - raise ReadException, "Not a valid JSON comment: %s" % self._generator.all() - - def _readCStyleComment(self): - try: - done = False - while not done: - ch = self._next() - done = (ch == "*" and self._peek() == "/") - if not done and ch == "/" and self._peek() == "*": - raise ReadException, "Not a valid JSON comment: %s, '/*' cannot be embedded in the comment." % self._generator.all() - self._next() - except StopIteration: - raise ReadException, "Not a valid JSON comment: %s, expected */" % self._generator.all() - - def _readDoubleSolidusComment(self): - try: - ch = self._next() - while ch != "\r" and ch != "\n": - ch = self._next() - except StopIteration: - pass - - def _readArray(self): - result = [] - assert self._next() == '[' - done = self._peek() == ']' - while not done: - item = self._read() - result.append(item) - self._eatWhitespace() - done = self._peek() == ']' - if not done: - ch = self._next() - if ch != ",": - raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch) - assert ']' == self._next() - return result - - def _readObject(self): - result = {} - assert self._next() == '{' - done = self._peek() == '}' - while not done: - key = self._read() - if type(key) is not types.StringType: - raise ReadException, "Not a valid JSON object key (should be a string): %s" % key - self._eatWhitespace() - ch = self._next() - if ch != ":": - raise ReadException, "Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch) - self._eatWhitespace() - val = self._read() - result[key] = val - self._eatWhitespace() - done = self._peek() == '}' - if not done: - ch = self._next() - if ch != ",": - raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch) - assert self._next() == "}" - return result - - def _eatWhitespace(self): - p = self._peek() - while p is not None and p in string.whitespace or p == '/': - if p == '/': - self._readComment() - else: - self._next() - p = self._peek() - - def _peek(self): - return self._generator.peek() - - def _next(self): - return self._generator.next() - -class JsonWriter(object): - - def _append(self, s): - self._results.append(s) - - def write(self, obj, escaped_forward_slash=False): - self._escaped_forward_slash = escaped_forward_slash - self._results = [] - self._write(obj) - return "".join(self._results) - - def _write(self, obj): - ty = type(obj) - if ty is types.DictType: - n = len(obj) - self._append("{") - for k, v in obj.items(): - self._write(k) - self._append(":") - self._write(v) - n = n - 1 - if n > 0: - self._append(",") - self._append("}") - elif ty is types.ListType or ty is types.TupleType: - n = len(obj) - self._append("[") - for item in obj: - self._write(item) - n = n - 1 - if n > 0: - self._append(",") - self._append("]") - elif ty is types.StringType or ty is types.UnicodeType: - self._append('"') - obj = obj.replace('\\', r'\\') - if self._escaped_forward_slash: - obj = obj.replace('/', r'\/') - obj = obj.replace('"', r'\"') - obj = obj.replace('\b', r'\b') - obj = obj.replace('\f', r'\f') - obj = obj.replace('\n', r'\n') - obj = obj.replace('\r', r'\r') - obj = obj.replace('\t', r'\t') - self._append(obj) - self._append('"') - elif ty is types.IntType or ty is types.LongType: - self._append(str(obj)) - elif ty is types.FloatType: - self._append("%f" % obj) - elif obj is True: - self._append("true") - elif obj is False: - self._append("false") - elif obj is None: - self._append("null") - else: - raise WriteException, "Cannot write in JSON: %s" % repr(obj) - -def write(obj, escaped_forward_slash=False): - return JsonWriter().write(obj, escaped_forward_slash) - -def read(s): - return JsonReader().read(s) - -def fread(f): - return read(f.read()) diff --git a/fbconnect/tests.py b/fbconnect/tests.py deleted file mode 100755 index 2247054b..00000000 --- a/fbconnect/tests.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.test import TestCase - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} - diff --git a/fbconnect/urls.py b/fbconnect/urls.py deleted file mode 100755 index bf2d4364..00000000 --- a/fbconnect/urls.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.conf.urls.defaults import * -from django.utils.translation import ugettext as _ -from django.views.generic.simple import direct_to_template -from django.conf import settings -from views import signin, register - -urlpatterns = patterns('', - url(r'^xd_receiver$', direct_to_template, {'template': 'fbconnect/xd_receiver.html',\ - 'extra_context': {'APP_SHORT_NAME':settings.APP_SHORT_NAME}},\ - name='xd_receiver'), - - url(r'^%s$' % _('signin/'), signin, name="fb_signin"), - url(r'^%s%s$' % (_('signin/'), _('newquestion/')), signin, {'newquestion': True}, name="fb_signin_new_question"), - url(r'^%s%s$' % (_('signin/'), _('newanswer/')), signin, {'newanswer': True}, name="fb_signin_new_answer"), - - url(r'^%s$' % _('register/'), register, name="fb_user_register"), - url(r'^%s%s$' % (_('register/'), _('newquestion/')), register, {'newquestion': True}, name="fb_user_register_new_question"), - url(r'^%s%s$' % (_('register/'), _('newanswer/')), register, {'newanswer': True}, name="fb_user_register_new_answer"), -) diff --git a/fbconnect/views.py b/fbconnect/views.py deleted file mode 100755 index 1781f6bf..00000000 --- a/fbconnect/views.py +++ /dev/null @@ -1,112 +0,0 @@ -from django.shortcuts import render_to_response as render -from django.template import RequestContext -from django.http import HttpResponseRedirect -from django.utils.safestring import mark_safe -from django.core.urlresolvers import reverse -from django.contrib.auth.models import User -from django.contrib.auth import login, logout -from models import FBAssociation -from forum.forms import SimpleEmailSubscribeForm -from django.conf import settings - -import fb -import forms - -import logging - -def signin(request, newquestion = False, newanswer = False): - logging.debug('') - state, context = fb.get_user_state(request) - - if state == fb.STATES['FIRSTTIMER']: - logging.debug('FB state = FIRSTTIMER') - if newquestion: - register_url = 'fb_user_register_new_question' - elif newanswer: - register_url = 'fb_user_register_new_answer' - else: - register_url = 'fb_user_register' - return HttpResponseRedirect(reverse(register_url)) - elif state == fb.STATES['RETURNINGUSER']: - logging.debug('FB state = RETURNINGUSER') - return login_and_forward(request, context, newquestion, newanswer) - elif state == fb.STATES['SESSIONEXPIRED']: - logging.debug('FB state = SESSIONEXPIRED') - response = logout(request, next_page=reverse('index')) - fb.delete_cookies(response) - return response - - return HttpResponseRedirect(reverse('index')) - -def register(request, newquestion = False, newanswer = False): - logging.debug('') - state, context = fb.get_user_state(request) - - if state == fb.STATES['FIRSTTIMER']: - logging.debug('FB FIRSTTIMER - try to register locally') - logging.debug('request method is %s' % request.method) - if request.method == 'POST' and 'bnewaccount' in request.POST: - form1 = forms.FBConnectRegisterForm(request.POST) - email_feeds_form = SimpleEmailSubscribeForm(request.POST) - - if (form1.is_valid() and email_feeds_form.is_valid()): - tmp_pwd = User.objects.make_random_password() - user_ = User.objects.create_user(form1.cleaned_data['username'], - form1.cleaned_data['email'], tmp_pwd) - - user_.set_unusable_password() - logging.debug('created new internal user %s' % form1.cleaned_data['username']) - - uassoc = FBAssociation(user=user_, fbuid=context['uid']) - uassoc.save() - logging.debug('created new user association') - - email_feeds_form.save(user_) - - return login_and_forward(request, user_, newquestion, newanswer) - else: - logging.debug('form user input is invalid') - else: - form1 = forms.FBConnectRegisterForm(initial={ - 'next': '/', - 'username': context['name'], - 'email': '', - }) - email_feeds_form = SimpleEmailSubscribeForm() - - return render('authopenid/complete.html', { - 'form1': form1, - 'email_feeds_form': email_feeds_form, - 'provider':mark_safe('facebook'), - 'login_type':'facebook', - 'gravatar_faq_url':reverse('faq') + '#gravatar', - }, context_instance=RequestContext(request)) - else: - logging.debug('not a FIRSTTIMER --> redirect to index view') - return HttpResponseRedirect(reverse('index')) - -def login_and_forward(request, user, newquestion = False, newanswer = False): - old_session = request.session.session_key - user.backend = "django.contrib.auth.backends.ModelBackend" - logging.debug('attached auth.backends.ModelBackend to this FB user') - login(request, user) - logging.debug('user logged in!') - - from forum.models import user_logged_in - user_logged_in.send(user=user,session_key=old_session,sender=None) - logging.debug('user_logged_in signal sent') - - if (newquestion): - from forum.models import Question - question = Question.objects.filter(author=user).order_by('-added_at')[0] - logging.debug('redirecting to newly posted question') - return HttpResponseRedirect(question.get_absolute_url()) - - if (newanswer): - from forum.models import Answer - answer = Answer.objects.filter(author=user).order_by('-added_at')[0] - logging.debug('redirecting to newly posted answer') - return HttpResponseRedirect(answer.get_absolute_url()) - - logging.debug('redirecting to front page') - return HttpResponseRedirect('/') |