Skip to content

Commit

Permalink
bug(social_auth): Handle duplicate users
Browse files Browse the repository at this point in the history
- generate unique username identifiers for google, facebook and twitter.
- ensure that users from different social networks with same username can login

[Finishes  #160346412]
  • Loading branch information
reiosantos authored and Innocent Asiimwe committed Sep 11, 2018
1 parent 2c7b120 commit 3085acd
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 17 deletions.
14 changes: 3 additions & 11 deletions authors/apps/social_auth/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.contrib.auth import authenticate
from rest_framework import serializers
from rest_framework.permissions import AllowAny

from authors.apps.authentication.models import User
Expand All @@ -17,19 +16,12 @@ def create_user_and_return_token(user_id, email, name):
'username': name, 'email': email, 'password': 'nopassword'}

# create a new facebook user
try:
User.objects.create_user(**user)
except: # noqa: E722
msg = 'User with email {0} already exists.'.format(email)
raise serializers.ValidationError(
msg
)
User.objects.create_user(**user)

User.objects.filter(email=email).update(social_id=user_id)

auth = authenticate(email=email, password="nopassword")
return {
auth.token
}
return auth.token
else:
# if user already exists and is authenticated by google also,
# return the user an authentication token
Expand Down
22 changes: 20 additions & 2 deletions authors/apps/social_auth/google.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import os

from google.auth.exceptions import RefreshError
from google.auth.transport import requests
from google.oauth2 import id_token
from google.oauth2.credentials import Credentials


class GoogleAuth:

@staticmethod
def validate(auth_token):
def validate(auth_token, refresh_token=None, access_token=None):
try:
token_uri = "https://accounts.google.com/o/oauth2/token"
key = os.environ.get("GOOGLE_API_KEY", None)
secret = os.environ.get("GOOGLE_API_SECRET", None)

credentials = Credentials(access_token, refresh_token=refresh_token, id_token=auth_token,
token_uri=token_uri, client_id=key, client_secret=secret)
# and now we refresh the token
# but not if we know that its not a valid token.
request = requests.Request()
try:
credentials.refresh(request)
except RefreshError:
pass

auth_token = credentials.id_token

# Specify the CLIENT_ID of the app that accesses the backend:
id_info = id_token.verify_oauth2_token(auth_token, requests.Request(),
os.environ.get("GOOGLE_OAUTH2_KEY", None))
os.environ.get("GOOGLE_API_KEY", None))

# ID token is valid. Get the user's Google Account ID from the decoded token.
return id_info
Expand Down
7 changes: 4 additions & 3 deletions authors/apps/social_auth/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
from authors.apps.social_auth.common import create_user_and_return_token


# noinspection PyMethodMayBeStatic
# noinspection PyMethodMayBeStatic,SpellCheckingInspection
class GoogleSocialAuthViewSerializer(serializers.Serializer):
""" Handles all social auth related tasks from google """

# get google authentication token from and do validations
auth_token = serializers.CharField()
refresh_token = serializers.CharField(write_only=True, required=False, default=None)

def validate_auth_token(self, auth_token) -> object:

# create an instance of the google social auth lib and validate token
user_info = google.GoogleAuth.validate(auth_token)
user_info = google.GoogleAuth.validate(auth_token, refresh_token=self.initial_data.get('refresh_token'))

try:
user_info['sub']
Expand All @@ -33,7 +34,7 @@ def validate_auth_token(self, auth_token) -> object:
return create_user_and_return_token(user_id=user_id, email=email, name=name)


# noinspection PyMethodMayBeStatic
# noinspection PyMethodMayBeStatic,SpellCheckingInspection
class FacebookSocialAuthViewSerializer(serializers.Serializer):
""" Handles all social auth related tasks from google """

Expand Down
30 changes: 29 additions & 1 deletion authors/apps/social_auth/tests/test_social_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def setUp(self):

self.google_debug_token = {
"user": {
"auth_token": os.getenv('GOOGLE_DEBUG_TOKEN')
"auth_token": os.getenv('GOOGLE_DEBUG_TOKEN'),
"refresh_token": os.getenv('GOOGLE_DEBUG_REFRESH_TOKEN')
}
}

Expand Down Expand Up @@ -77,3 +78,30 @@ def test_signup_with_expired_facebook_token(self):
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['errors']['auth_token'], [
'The token is either invalid or expired. Please login again.'])

def test_signup_with_valid_google_token(self):
""" test if a user can signup with correct google token """

response = self.test_client.post(
"/api/social/auth/google/", data=json.dumps(
self.google_debug_token), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertIn('auth_token', response.json())

# user already exists
response = self.test_client.post(
"/api/social/auth/google/", data=json.dumps(
self.google_debug_token), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertIn('auth_token', response.json())

def test_signup_with_valid_facebook_token(self):
""" test if a user can signup with correct fb token """

response = self.test_client.post(
"/api/social/auth/facebook/", data=json.dumps(
self.facebook_debug_token), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json())
self.assertIn('auth_token', response.json())

0 comments on commit 3085acd

Please sign in to comment.