-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #82 from rcpch:fix-otp-local-dev
Bypass 2FA Token in local development
- Loading branch information
Showing
8 changed files
with
177 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,34 @@ | ||
{% load i18n %} | ||
|
||
<div class="flex flex-col justify-center items-center"> | ||
|
||
<button type="submit" class="bg-rcpch_light_blue text-white font-semibold hover:text-white py-2.5 px-3 mt-5 border border-rcpch_light_blue hover:bg-rcpch_strong_blue hover:border-rcpch_strong_blue"> | ||
{% trans "Next" %} | ||
</button> | ||
|
||
|
||
<button type="submit" | ||
class="bg-rcpch_light_blue text-white font-semibold hover:text-white py-2.5 px-3 mt-5 border border-rcpch_light_blue hover:bg-rcpch_strong_blue hover:border-rcpch_strong_blue"> | ||
{% trans "Next" %} | ||
</button> | ||
|
||
{% if wizard.steps.prev %} | ||
<!-- <div> --> | ||
<button | ||
name="wizard_goto_step" | ||
type="submit" | ||
value="{{ wizard.steps.prev }}" | ||
class="justify-center items-center bg-rcpch_light_blue text-white font-semibold hover:text-white py-2.5 px-3 mt-5 border border-rcpch_light_blue hover:bg-rcpch_strong_blue hover:border-rcpch_strong_blue" | ||
> | ||
Back | ||
</button> | ||
</div> | ||
{% endif %} | ||
<!-- </div> --> | ||
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}" | ||
class="justify-center items-center bg-rcpch_light_blue text-white font-semibold hover:text-white py-2.5 px-3 mt-5 border border-rcpch_light_blue hover:bg-rcpch_strong_blue hover:border-rcpch_strong_blue"> | ||
Back | ||
</button> | ||
</div> | ||
{% endif %} | ||
|
||
<!--IF NO PREV BUTTON -> MUST BE AT FIRST SIGNIN PAGE --> | ||
{% if not wizard.steps.prev %} | ||
<div class="flex flex-col justify-center items-center"> | ||
<a href="{% url 'password_reset' %}" class="bg-rcpch_light_blue text-white font-semibold hover:text-white py-2.5 px-3 mt-5 border border-rcpch_light_blue hover:bg-rcpch_strong_blue hover:border-rcpch_strong_blue">Reset Password</a> | ||
<a href="{% url 'password_reset' %}" | ||
class="bg-rcpch_light_blue text-white font-semibold hover:text-white py-2.5 px-3 mt-5 border border-rcpch_light_blue hover:bg-rcpch_strong_blue hover:border-rcpch_strong_blue">Reset | ||
Password</a> | ||
<div class="mt-5"> | ||
<div class="mt-2 bg-gray-100 border border-gray-200 text-sm text-gray-800 rounded-lg p-4 dark:bg-white/10 dark:border-white/20 dark:text-white font-montserrat" role="alert"> | ||
<span class="font-bold">NOTE</span> For users of the old platform, you will require a new username and password to access this new platform. Please contact your Lead Clinician or <a href="mailto:[email protected]">[email protected]</a> for assistance. | ||
<div | ||
class="mt-2 bg-gray-100 border border-gray-200 text-sm text-gray-800 rounded-lg p-4 dark:bg-white/10 dark:border-white/20 dark:text-white font-montserrat" | ||
role="alert"> | ||
<span class="font-bold">NOTE</span> For users of the old platform, you will require a new username and password to | ||
access this new platform. Please contact your Lead Clinician or <a | ||
href="mailto:[email protected]">[email protected]</a> for assistance. | ||
</div> | ||
</div> | ||
</div> | ||
{% endif %} | ||
{% endif %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# python imports | ||
import logging | ||
|
||
from django.conf import settings | ||
from django.core.exceptions import PermissionDenied | ||
from django.contrib.auth.decorators import login_required | ||
|
||
# Logging setup | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def login_and_otp_required(): | ||
""" | ||
Must have verified via 2FA | ||
""" | ||
|
||
def decorator(view): | ||
# First use login_required on decorator | ||
login_required(view) | ||
|
||
def wrapper(request, *args, **kwargs): | ||
# Then, ensure 2fa verified | ||
user = request.user | ||
|
||
# Bypass 2fa if local dev, with warning message | ||
if settings.DEBUG: | ||
logger.warning( | ||
"User %s has bypassed 2FA for %s as settings.DEBUG is %s", | ||
user, | ||
view, | ||
settings.DEBUG, | ||
) | ||
return view(request, *args, **kwargs) | ||
|
||
# Prevent unverified users | ||
if not user.is_verified(): | ||
user_list = user.__dict__ | ||
epilepsy12_user = user_list["_wrapped"] | ||
logger.info( | ||
"User %s is unverified. Tried accessing %s", | ||
epilepsy12_user, | ||
view.__qualname__, | ||
) | ||
raise PermissionDenied("Unverified user") | ||
|
||
return view(request, *args, **kwargs) | ||
|
||
return wrapper | ||
|
||
return decorator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,26 @@ | ||
from django.shortcuts import get_object_or_404, redirect, render | ||
from django.urls import reverse | ||
from django.contrib.auth.decorators import login_required | ||
from django_otp.decorators import otp_required | ||
from django.contrib import messages | ||
|
||
from ..general_functions import csv_upload | ||
from ..forms.upload import UploadFileForm | ||
from ..models import Patient, Visit | ||
from .decorators import login_and_otp_required | ||
|
||
|
||
@login_required | ||
@login_and_otp_required() | ||
def home(request): | ||
if request.user.is_verified(): | ||
file_uploaded = False | ||
if request.method == "POST": | ||
form = UploadFileForm(request.POST, request.FILES) | ||
file = request.FILES["csv_upload"] | ||
file_uploaded = csv_upload(csv_file=file) | ||
if file_uploaded["status"]==500: | ||
messages.error(request=request,message=f"{file_uploaded["errors"]}") | ||
return redirect('home') | ||
else: | ||
form = UploadFileForm() | ||
context = {"file_uploaded": file_uploaded, "form": form} | ||
template = "home.html" | ||
return render(request=request, template_name=template, context=context) | ||
|
||
file_uploaded = False | ||
if request.method == "POST": | ||
form = UploadFileForm(request.POST, request.FILES) | ||
file = request.FILES["csv_upload"] | ||
file_uploaded = csv_upload(csv_file=file) | ||
if file_uploaded["status"]==500: | ||
messages.error(request=request,message=f"{file_uploaded["errors"]}") | ||
return redirect('home') | ||
else: | ||
return redirect(reverse("two_factor:profile")) | ||
form = UploadFileForm() | ||
context = {"file_uploaded": file_uploaded, "form": form} | ||
template = "home.html" | ||
return render(request=request, template_name=template, context=context) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"""Defines custom mixins used throughout our Class Based Views""" | ||
|
||
import logging | ||
|
||
from django.conf import settings | ||
from django.core.exceptions import PermissionDenied | ||
from django.contrib.auth.mixins import AccessMixin | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class LoginAndOTPRequiredMixin(AccessMixin): | ||
""" | ||
Mixin that ensures the user is logged in and has verified via OTP. | ||
Bypassed in local development is user.is_superuser AND settings.DEBUG==True. | ||
""" | ||
|
||
def dispatch(self, request, *args, **kwargs): | ||
|
||
# Check if the user is authenticated | ||
if not request.user.is_authenticated: | ||
return self.handle_no_permission() | ||
|
||
# Check if the user is superuser and bypass 2FA in debug mode | ||
if settings.DEBUG and request.user.is_superuser: | ||
logger.warning( | ||
"User %s has bypassed 2FA for %s as settings.DEBUG is %s and user is superuser", | ||
request.user, | ||
self.__class__.__name__, | ||
settings.DEBUG, | ||
) | ||
return super().dispatch(request, *args, **kwargs) | ||
|
||
# Check if the user is verified | ||
if not request.user.is_verified(): | ||
logger.info( | ||
"User %s is unverified. Tried accessing %s", | ||
request.user, | ||
self.__class__.__name__, | ||
) | ||
raise PermissionDenied() | ||
|
||
return super().dispatch(request, *args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.