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