From 2f4df934f0bef28859a87a3e232273990e3e8508 Mon Sep 17 00:00:00 2001 From: Michael Collins <15347726+michaeljcollinsuk@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:06:07 +0000 Subject: [PATCH] Add auth.py views file --- controlpanel/frontend/views/__init__.py | 59 ++-------------------- controlpanel/frontend/views/auth.py | 66 +++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 55 deletions(-) create mode 100644 controlpanel/frontend/views/auth.py diff --git a/controlpanel/frontend/views/__init__.py b/controlpanel/frontend/views/__init__.py index 330a45d12..33b591a0a 100644 --- a/controlpanel/frontend/views/__init__.py +++ b/controlpanel/frontend/views/__init__.py @@ -1,17 +1,12 @@ # Third-party -import base64 -import hashlib - -from authlib.common.security import generate_token -from authlib.integrations.django_client import OAuthError -from django.contrib import messages from django.http import HttpResponseRedirect from django.urls import reverse -from django.views.generic.base import TemplateView, View +from django.views.generic.base import TemplateView from mozilla_django_oidc.views import OIDCLogoutView # First-party/Local from controlpanel.frontend.views.accessibility import Accessibility +from controlpanel.frontend.views.auth import EntraIdAuthView, FrontPageView # isort: off from controlpanel.frontend.views.app import ( @@ -75,17 +70,17 @@ ReleaseList, ) from controlpanel.frontend.views.reset import ResetHome +from controlpanel.frontend.views.task import TaskList from controlpanel.frontend.views.tool import RestartTool, ToolList from controlpanel.frontend.views.user import ( + EnableBedrockUser, ResetMFA, SetSuperadmin, - EnableBedrockUser, UserDelete, UserDetail, UserList, ) from controlpanel.oidc import OIDCLoginRequiredMixin, oauth -from controlpanel.frontend.views.task import TaskList class IndexView(OIDCLoginRequiredMixin, TemplateView): @@ -107,52 +102,6 @@ def get(self, request): return HttpResponseRedirect(reverse("list-tools")) -class FrontPageView(TemplateView): - template_name = "frontpage.html" - # TODO bypass when user has already authenticated with UserPassesTestMixin - - def _get_code_challenge(self): - code_verifier = generate_token(64) - digest = hashlib.sha256(code_verifier.encode()).digest() - return base64.urlsafe_b64encode(digest).rstrip(b"=").decode() - - def post(self, request): - code_challenge = self._get_code_challenge() - redirect_uri = request.build_absolute_uri(reverse("entraid-auth")) - return oauth.azure.authorize_redirect( - request, redirect_uri, code_challenge=code_challenge, - ) - - -class EntraIdAuthView(View): - - def _authorize_token(self): - try: - token = oauth.azure.authorize_access_token(self.request) - except OAuthError: - # TODO log the error - token = None - return token - - def get(self, request, *args, **kwargs): - token = self._authorize_token() - if not token: - messages.error(self.request, "Something went wrong, please try again soon") - return HttpResponseRedirect(reverse("index")) - - self.update_user(token=token) - return HttpResponseRedirect(reverse("index")) - - def update_user(self, token): - email = token["userinfo"]["email"] - self.request.user.justice_email = email - self.request.user.save() - messages.success( - request=self.request, - message=f"Successfully authenticated with your email {email}" - ) - - class LogoutView(OIDCLogoutView): def get(self, request): return super().post(request) diff --git a/controlpanel/frontend/views/auth.py b/controlpanel/frontend/views/auth.py new file mode 100644 index 000000000..3795b3b83 --- /dev/null +++ b/controlpanel/frontend/views/auth.py @@ -0,0 +1,66 @@ +# Standard library +import base64 +import hashlib + +# Third-party +import sentry_sdk +from authlib.common.security import generate_token +from authlib.integrations.django_client import OAuthError +from django.contrib import messages +from django.http import HttpResponseRedirect +from django.urls import reverse +from django.views import View +from django.views.generic import TemplateView + +# First-party/Local +from controlpanel.oidc import oauth + + +class FrontPageView(TemplateView): + http_method_names = ["get", "post"] + template_name = "frontpage.html" + # TODO bypass when user has already authenticated with UserPassesTestMixin + + def _get_code_challenge(self): + code_verifier = generate_token(64) + digest = hashlib.sha256(code_verifier.encode()).digest() + return base64.urlsafe_b64encode(digest).rstrip(b"=").decode() + + def post(self, request): + code_challenge = self._get_code_challenge() + redirect_uri = request.build_absolute_uri(reverse("entraid-auth")) + return oauth.azure.authorize_redirect( + request, + redirect_uri, + code_challenge=code_challenge, + ) + + +class EntraIdAuthView(View): + http_method_names = ["get"] + + def _authorize_token(self): + try: + token = oauth.azure.authorize_access_token(self.request) + except OAuthError as error: + sentry_sdk.capture_exception(error) + token = None + return token + + def get(self, request, *args, **kwargs): + token = self._authorize_token() + if not token: + messages.error(self.request, "Something went wrong, please try again soon") + return HttpResponseRedirect(reverse("index")) + + self.update_user(token=token) + return HttpResponseRedirect(reverse("index")) + + def update_user(self, token): + email = token["userinfo"]["email"] + self.request.user.justice_email = email + self.request.user.save() + messages.success( + request=self.request, + message=f"Successfully authenticated with your email {email}", + )