Example #1
0
    def authenticate(self, fb_uid=None, fb_object=None, request=None):
        """ If we receive a facebook uid then the cookie has already been validated. """
        if fb_uid:
            user, created = User.objects.get_or_create(username=fb_uid)

            if request and created:
                request.session['new_facebook_user'] = True

            try:
                if user.fb_profile:
                    exists = True
            except:
                exists = False

            # Consider replacing this synchronous data request (out to Facebook
            # and back) with an asynchronous request, using Celery or similar tool
            if FACEBOOK_PREPOPULATE_USER_DATA and (created or not exists) and fb_object:
                fb_user = fb_object.graph.get_object(u'me')
                user.first_name = fb_user['first_name']
                user.last_name  = fb_user['last_name']

                if 'email' in FACEBOOK_EXTENDED_PERMISSIONS and 'email' in fb_user:
                    user.email = fb_user['email']
                    
                user.save()

                profile = FacebookProfile.fromFacebookObject(fb_user, user)

            if FACEBOOK_PREPOPULATE_USER_DATA and fb_object and \
               user.fb_profile.last_update < datetime.now() - timedelta(1):
                user.fb_profile.update(fb_object.graph.get_object(u'me'))

            return user
        return None
Example #2
0
    def authenticate(self, fb_uid=None, fb_object=None, request=None):
        """ If we receive a facebook uid then the cookie has already been validated. """
        if fb_uid:
            user, created = User.objects.get_or_create(username=fb_uid)

            if request and created:
                request.session['new_facebook_user'] = True

            try:
                if user.fb_profile:
                    exists = True
            except:
                exists = False

            # Consider replacing this synchronous data request (out to Facebook
            # and back) with an asynchronous request, using Celery or similar tool
            if FACEBOOK_PREPOPULATE_USER_DATA and (created or
                                                   not exists) and fb_object:
                fb_user = fb_object.graph.get_object(u'me')
                user.first_name = fb_user['first_name']
                user.last_name = fb_user['last_name']

                if 'email' in FACEBOOK_EXTENDED_PERMISSIONS and 'email' in fb_user:
                    user.email = fb_user['email']

                user.save()

                profile = FacebookProfile.fromFacebookObject(fb_user, user)

            if FACEBOOK_PREPOPULATE_USER_DATA and fb_object and \
               user.fb_profile.last_update < datetime.now() - timedelta(1):
                user.fb_profile.update(fb_object.graph.get_object(u'me'))

            return user
        return None
def login_return(request):
    """
    OAuth callback.
    """
    
    ##################
    # 1) Validations #
    ##################
    
    # Check for required parameter.
    code = request.GET.get('code', None)
    if not code:
        messages.add_message(request, messages.ERROR, _('Facebook login error #1'))
        return HttpResponseRedirect(reverse('yaccounts:index'))
    
    ###########################
    # 2) Request access token #
    ###########################
        
    request_access_token_url = access_token_url + '?client_id=' + app_id \
                                 + '&redirect_uri=' + settings.HOST_URL + reverse('yaccounts:facebook_return') \
                                 + '&client_secret=' + app_secret \
                                 + '&code=' + code
    response = cgi.parse_qs(urllib.urlopen(request_access_token_url).read())
    try:
        access_token = response['access_token'][-1]
    except KeyError:
        messages.add_message(request, messages.ERROR, _('Facebook login error #2'))
        return HttpResponseRedirect(reverse('yaccounts:index'))
    
    # Verify credentials.
    # Validate user access token. If we can fetch it's information, the token is good!
    try:
        fb_api = facebook.GraphAPI(access_token=access_token)
        userinfo = UserInfo(fb_api.get_object('me'))
    except:
        messages.add_message(request, messages.ERROR, _('Facebook login error #3'))
        return HttpResponseRedirect(reverse('yaccounts:index'))
    
    #########################################################
    # 3) Authenticate user with given Facebook credentials. #
    #########################################################
    user = authenticate(facebook_userinfo=userinfo, facebook_access_token=access_token)
    
    ##
    # a) Facebook profile is linked with existing user account.
    if user:
        
        # Additional information on the request that should be logged.
        metadata = { 'user_agent': request.META['HTTP_USER_AGENT'] }
        
        # If user is active, login account and redirect to next page (if provided, else account profile)
        if user.is_active:
            
            # Create user login session.
            login(request, user)
            
            # Log authentication.
            AuthenticationLog.new(email=user.email,
                                  valid_credentials=True,
                                  credentials_type='facebook',
                                  account_status='active',
                                  success=True,
                                  ip_address=request.META['REMOTE_ADDR'],
                                  metadata=json.dumps(metadata))
            
            # Redirect to either page referenced as next or accounts index.
            return HttpResponseRedirect(request.session.get('login_next', reverse('yaccounts:index')))
        
        # User account is inactive.
        else:
            
            # Log authentication.
            AuthenticationLog.new(email=user.email,
                                  valid_credentials=True,
                                  credentials_type='facebook',
                                  account_status='disabled',
                                  success=False,
                                  ip_address=request.META['REMOTE_ADDR'],
                                  metadata=json.dumps(metadata))
            
            # Message.
            messages.warning(request, _("Your account is disabled."))
            
            # Return.
            return HttpResponseRedirect(reverse('yaccounts:login'))
        
    ##
    # b) Unknown Facebook profile.
    else:
        
        # i) If there is an account logged in, (attempt to) link the Facebook profile with it.
        if request.user.is_authenticated():
            try:
                FacebookProfile.new(user=request.user, userinfo=userinfo, access_token=access_token)
                messages.success(request, _("Facebook account connected successfully."))
            except IntegrityError:
                messages.error(request, _("You already have a Facebook profile linked to your account."))
            return HttpResponseRedirect(reverse('yaccounts:index'))
        
        # ii) Create new account.
        else:
            # Place Facebook info in a session variable in order for it to be accessed in the registration page.
            request.session['facebook_create'] = {
                    'facebook_user_id': userinfo.id,
                    'name': userinfo.name,
                    'profile_image_url': FacebookProfile.get_profile_image_url(userinfo.id),
                    'access_token': access_token,
                    'expires': (datetime.datetime.now() + datetime.timedelta(seconds=5*60)).strftime('%s') # Convert to epoch to be JSON serializable.
            }
            return HttpResponseRedirect(reverse('yaccounts:facebook_create'))
def create_account(request):
    """
    Create new account with Facebook credentials.
    """
    
    #
    # Lets validate if we should be here.
    #
    
    # If user is authenticated, then this place shouldn't be reached.
    # Facebook profile, if valid, should be linked with the logged in account and not create a new account.
    if request.user.is_authenticated():
        return HttpResponseRedirect(reverse('yaccounts:index'))
    
    # In order to create account with Facebook profile, its details should have been stored in session.
    facebook_create = request.session.get('facebook_create', None)
    if not facebook_create:
        messages.error(request, _('Facebook login error #4'))
        return HttpResponseRedirect(reverse('yaccounts:login'))
    
    # If time window for registration of new account with this Facebook profile has expired,
    # delete it from session and restart Facebook login process.
    if datetime.datetime.now() > datetime.datetime.fromtimestamp(float(facebook_create['expires'])):
        del request.session['facebook_create']
        return HttpResponseRedirect(reverse('yaccounts:facebook_login'))
    
    #
    # Proceed with account creation.
    #
    email = ''
    
    # A form was received.
    if request.method == 'POST':
        
        proceed = True
        
        # Fetch mandatory params.
        try:
            email = request.POST['email']
        except KeyError:
            proceed = False
            messages.error(request, _("Please provide an e-mail address."))
            
        # Validate email address.
        try:
            validate_email(email)
        except ValidationError:
            proceed = False
            messages.error(request, _("Please provide a valid email address."))
            
        # Check if Facebook profile is already connected to another account.
        try:
            FacebookProfile.objects.get(facebook_user_id=facebook_create['facebook_user_id'])
            proceed = False
            messages.error(request, _("Facebook profile already connected to another account."))
        except ObjectDoesNotExist:
            pass
        
        # Check if account exists with given email address.
        try:
            get_user_model().objects.get(email=email)
            proceed = False
            messages.error(request, _("Email already registered."))
        except ObjectDoesNotExist:
            pass
        
        #
        # Everything checks! \o/
        #
        if proceed:
            
            # 1) Create user with random password.
            try:
                random_password = generate_key(email + str(datetime.datetime.now()) + str(facebook_create['facebook_user_id']))
                random_password += datetime.datetime.now().strftime('%s')
                user = get_user_model().new(name=facebook_create['name'], email=email, password=random_password, credentials_type='facebook')
            except:
                logger.error('Error creating user via Facebook! #5 ' + str(facebook_create), exc_info=1)
                messages.error(request, _('Facebook login error #5'))
            
            # 2) Create Facebook profile and associate it with the new user.
            try:
                userinfo = UserInfo(userinfo={ 'id': facebook_create['facebook_user_id'], 'name': facebook_create['name'] })
                FacebookProfile.new(user=user, userinfo=userinfo, access_token=facebook_create['access_token'])
                # Redirect to login page with message.
                messages.success(request, _("An email was sent in order to confirm your account."))
                return HttpResponseRedirect(reverse('yaccounts:login'))
            except:
                user.delete() # Delete newly created user (as it would be inaccessible since the Facebook Profile wasn't created!)
                logger.error('Error creating user via Facebook! #6 ' + str(facebook_create), exc_info=1)
                messages.error(request, _('Facebook login error #6'))
    
    # Render page.
    return render_to_response('yaccounts/create_social.html',
                              { 'avatar': facebook_create['profile_image_url'],
                               'username': facebook_create['name'],
                               'email': email,
                               'post_url': reverse('yaccounts:facebook_create') },
                              context_instance=RequestContext(request))
Example #5
0
    def authenticate(self, fb_uid=None, fb_object=None):
        """ If we receive a facebook uid then the cookie has already been validated. """
        if fb_uid:
            user, created = User.objects.get_or_create(username=fb_uid)

            # Consider replacing this synchronous data request (out to Facebook
            # and back) with an asynchronous request, using Celery or similar tool
            if FACEBOOK_PREPOPULATE_USER_DATA and created and fb_object:
                fb_user = fb_object.graph.get_object(u'me')
                user.first_name = fb_user['first_name']
                user.last_name  = fb_user['last_name']

                if 'email' in FACEBOOK_EXTENDED_PERMISSIONS and 'email' in fb_user:
                    user.email = fb_user['email']
                    
                user.save()

                profile = FacebookProfile()

                profile.user = user

                if 'birthday' in fb_user:
                    match = re.search('(\d+)/(\d+)/(\d+)', fb_user['birthday'])
                    if match:
                        profile.birthday = "%s-%s-%s" % (match.group(3), match.group(1), match.group(2))

                profile.uid = fb_user['id']
                profile.name = fb_user['name']
                profile.first_name = fb_user['first_name']
                profile.last_name = fb_user['last_name']

                if 'middle_name' in fb_user:
                    profile.middle_name = fb_user['middle_name']


                if 'link' in fb_user:
                    profile.link = fb_user['link']

                if 'hometown' in fb_user:
                    profile.hometown = fb_user['hometown']['name']

                if 'bio' in fb_user:
                    profile.bio = fb_user['bio']

                if 'gender' in fb_user:
                    profile.gender = fb_user['gender'][0].upper()

                profile.modified = fb_user['updated_time'].replace('T', ' ').replace('+', '.')

                profile.save()

            return user
        return None
    def authenticate(self, token=None, request=None):
        """ Reads in a Facebook code and asks Facebook
            if it's valid and what user it points to. """
        keystone = KeystoneBackend()
        self.keystone = keystone
        args = {
            'client_id': settings.FACEBOOK_APP_ID,
            'client_secret': settings.FACEBOOK_APP_SECRET,
            'redirect_uri': request.build_absolute_uri(
                reverse('horizon.facebook.views.authentication_callback')),
            'code': token,
        }
        # Get a legit access token
        target = urllib.urlopen(
                'https://graph.facebook.com/oauth/access_token?'
                + urllib.urlencode(args)).read()
        response = cgi.parse_qs(target)
        if 'access_token' not in response:
            messages.error(
                request, _("Token Expired, please login again."))
            return None
        access_token = response['access_token'][-1]

        # Read the user's profile information
        fb_profile = urllib.urlopen(
                'https://graph.facebook.com/me?access_token=%s' % access_token)
        fb_profile = json.load(fb_profile)
        tenant_id = None
        password = ""
        try:
            # Try and find existing user
            fb_user = FacebookProfile.objects.get(facebook_id=fb_profile['id'])
            user = fb_user.user
            # Update access_token
            fb_user.access_token = access_token
            password = fb_user.password
            tenant_id = fb_user.tenant_id
            fb_user.save()
        except FacebookProfile.DoesNotExist:
            # No existing user
            try:
                facebook_id = fb_profile['id']
                username = "******" % facebook_id
                try:
                    user = User.objects.create_user(username, fb_profile['email'])
                except IntegrityError:
                    # Username already exists, make it unique
                    existing_user = User.objects.get(username=username)
                    existing_user.delete()
                    user = User.objects.create_user(username, fb_profile['email'])
                user.save()

                password = "".join([random.choice(
                                        string.ascii_lowercase + string.digits)
                                   for i in range(8)])
                # Create the FacebookProfile
                fb_user = FacebookProfile(user=user, facebook_id=fb_profile['id'],
                                          access_token=access_token,
                                          password=password)
                tenant_name = "facebook%s" % fb_profile['id']
                if not self.keystone_user_exists(username):
                    tenant = self.add_keystone_user(settings, tenant_name, password, fb_profile)
                else:
                    tenant = self.get_keystone_tenant(settings, tenant_name)
                fb_user.tenant_id = tenant.id
                tenant_id = fb_user.tenant_id
                fb_user.save()
            except Exception, e:
                messages.error(request, e)
                fb_user.delete()