diff --git a/.gitignore b/.gitignore index c217378..5e6c943 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ .env .vscode/ .Pipfile.lock +*client_secret.json* diff --git a/backend/users/backend.py b/backend/users/backend.py index 0b16017..0a6383c 100644 --- a/backend/users/backend.py +++ b/backend/users/backend.py @@ -1,17 +1,38 @@ +from django.conf import settings from django.contrib.auth.backends import ModelBackend +from google.auth.transport import requests +from google.oauth2 import id_token +from google_auth_oauthlib.flow import Flow +from .mail import send_validation_mail from .models import User class OAuthAuthenticationBackend(ModelBackend): """ - Authentication backend to allow authenticating users against a - Microsoft ADFS server with an authorization code. + Authentication backend to allow user use Google to login. """ def authenticate(self, request, username=None, password=None, **kwargs): - if kwargs.get('id_info'): - user = self.get_google_oauth_user(kwargs.get('id_info')) + state = kwargs.get('oauth_state') + flow = Flow.from_client_secrets_file( + f'{settings.ROOT_DIR}/backend/client_secret.json', + scopes=None, + redirect_uri=request.build_absolute_uri('/users/google-callback/'), + ) + + # Use the authorization response to get tokens + flow.fetch_token(authorization_response=request.build_absolute_uri(), state=state) + + # Use the id_token to get user information + token = flow.credentials.id_token + request_google_oauth = requests.Request() + id_info = id_token.verify_oauth2_token( + token, + request_google_oauth, + ) + + user = self.get_google_oauth_user(id_info) return user def get_google_oauth_user(self, id_info): @@ -24,5 +45,6 @@ def get_google_oauth_user(self, id_info): user = User.objects.get(email=data['email']) except User.DoesNotExist: user = User.objects.create(**data) + send_validation_mail(email=data['email']) return user diff --git a/backend/users/mail.py b/backend/users/mail.py index f34bd11..14b0f21 100644 --- a/backend/users/mail.py +++ b/backend/users/mail.py @@ -30,4 +30,5 @@ def send_validation_mail(email: str): recipient_list, html_message=f'{message}
{url}{token}', ) + print(f'Email sent successfully to {recipient_list} !') return ({'title': 'Success', 'detail': 'Validation email sent.'},) diff --git a/backend/users/views.py b/backend/users/views.py index e653407..b065c47 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -5,8 +5,6 @@ from django.shortcuts import redirect from django.utils import timezone from django.utils.http import url_has_allowed_host_and_scheme -from google.auth.transport import requests -from google.oauth2 import id_token from google_auth_oauthlib.flow import Flow from rest_framework import generics, permissions, status from rest_framework.decorators import action @@ -26,11 +24,20 @@ class OAuthViewset(GenericViewSet): @action(detail=False, methods=['get'], url_path='google-login') def google_login(self, request): # Set up the Google OAuth2.0 flow - flow = Flow.from_client_secrets_file( - f'{settings.ROOT_DIR}/backend/client_secret.json', - scopes=['openid', 'profile', 'email'], - redirect_uri=request.build_absolute_uri('/users/google-callback/'), - ) + try: + flow = Flow.from_client_secrets_file( + f'{settings.ROOT_DIR}/backend/client_secret.json', + scopes=['openid', 'profile', 'email'], + redirect_uri=request.build_absolute_uri('/users/google-callback/'), + ) + except FileNotFoundError: + return Response( + { + 'title': 'Error', + 'Detail': 'Google login is currently disabled due' + + 'to missing client secrets on the host server.', + }, + ) authorization_url, state = flow.authorization_url(prompt='consent') # Store the state so the callback can verify the response. @@ -42,25 +49,7 @@ def google_callback(self, request): # pragma: no cover # Get the state from the session to verify the response. state = request.session.get('oauth_state') - flow = Flow.from_client_secrets_file( - f'{settings.ROOT_DIR}/backend/client_secret.json', - scopes=None, - redirect_uri=request.build_absolute_uri('/users/google-callback/'), - ) - - # Use the authorization response to get tokens - flow.fetch_token(authorization_response=request.build_absolute_uri(), state=state) - - # Use the id_token to get user information - token = flow.credentials.id_token - request_google_oauth = requests.Request() - id_info = id_token.verify_oauth2_token( - token, - request_google_oauth, - ) - - user = authenticate(request=request, id_info=id_info) - + user = authenticate(request=request, oauth_state=state) if user: if user.is_active: login(request, user)