5

I am using django-two-factor-auth for a webapp. I cannot access the admin page.

I know I am entering the correct credentials. When I input incorrect credentials, I get an appropriate error message.

When I input the correct credentials, the page simply reloads with this URL:

http://localhost:8080/account/login/?next=/inveskore/

These are my settings related to two_factor:

LOGIN_URL = 'two_factor:login'
LOGIN_REDIRECT_URL = '/inveskore'
TWO_FACTOR_SMS_GATEWAY = 'two_factor.gateways.twilio.gateway.Twilio'

This is the associated URL path:

path('admin/', admin.site.urls),

According to this, it results from the admin user not having 2FA set.

So, how do you set 2FA for the admin user if you can't access the site?

EDIT:

I took down the 2FA login requirements for the site and then added a phone device. No luck.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Ryan Skene
  • 864
  • 1
  • 12
  • 29
  • Do you have your [Twilio credentials setup](http://django-two-factor-auth.readthedocs.io/en/stable/configuration.html#two_factor.gateways.twilio.gateway.Twilio)? – philnash Feb 04 '18 at 22:11
  • yes. i have no problem using Twilio with the one general user I have setup. – Ryan Skene Feb 06 '18 at 11:57

3 Answers3

3

I recently ran into this scenario and created this solution based on a comment there:

https://github.com/Bouke/django-two-factor-auth/issues/219#issuecomment-494382380

I subclassed AdminSiteOTPRequired and then specified it as the admin class to use

from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.views import redirect_to_login
from django.http import HttpResponseRedirect
from django.shortcuts import resolve_url
from django.urls import reverse
from django.utils.http import is_safe_url
from two_factor.admin import AdminSiteOTPRequired, AdminSiteOTPRequiredMixin


class AdminSiteOTPRequiredMixinRedirSetup(AdminSiteOTPRequired):
    def login(self, request, extra_context=None):
        redirect_to = request.POST.get(
            REDIRECT_FIELD_NAME, request.GET.get(REDIRECT_FIELD_NAME)
        )
        # For users not yet verified the AdminSiteOTPRequired.has_permission
        # will fail. So use the standard admin has_permission check:
        # (is_active and is_staff) and then check for verification.
        # Go to index if they pass, otherwise make them setup OTP device.
        if request.method == "GET" and super(
            AdminSiteOTPRequiredMixin, self
        ).has_permission(request):
            # Already logged-in and verified by OTP
            if request.user.is_verified():
                # User has permission
                index_path = reverse("admin:index", current_app=self.name)
            else:
                # User has permission but no OTP set:
                index_path = reverse("two_factor:setup", current_app=self.name)
            return HttpResponseRedirect(index_path)

        if not redirect_to or not is_safe_url(
            url=redirect_to, allowed_hosts=[request.get_host()]
        ):
            redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)

        return redirect_to_login(redirect_to)

Then in urls.py:

from django.contrib import admin
admin.site.__class__ = AdminSiteOTPRequiredMixinRedirSetup
saschwarz
  • 1,123
  • 2
  • 13
  • 26
1

I cannot comment yet but the answer above by @saschwarz worked like a charm with Django 2.2 and django-two-factor-auth. The only thing missing from his code is the additional import:

from django.http import HttpResponseRedirect

After that I was able to use this line:

admin.site.__class__ = AdminSiteOTPRequiredMixinRedirSetup

to quickly enforce two factor for admin users.

This is really missing from the docs for django-two-factor-auth... I looked at the documentation for quite a while and couldn't find a clear way to generate a qr code. It's only really demonstrated in the demo app, and not in a very modular way.

1

The solution from saschewarz didn't solve the problem in my app. So I found another one where standard admin login is shown.

django-two-factor-auth by default patch your admin urls with function 'patch_admin' from two_factor\admin.py so you always will see your standard site login for admin login.

To solve this you can comment out 2 functions in two_factor\admin.py

def patch_admin()

and

def unpatch_admin()

And comment out in two_factor\apps.py

def ready(self) 

And to use two factor authentication in admin site add this code in main urls.py (where is path to admin):

from django_otp.admin import OTPAdminSite
admin.site.__class__ = OTPAdminSite
Harry Moreno
  • 10,231
  • 7
  • 64
  • 116
schum
  • 56
  • 1
  • 3
  • 1
    I also recently implemented two factor auth to my project to find that admin login was gone and thought I messed something up so went to start over and then see the solutions on this page. I wanted to confirm this solution posted by @schum works perfectly exactly what I wanted - Thank you very much! – rob Nov 05 '21 at 20:22
  • This lets me view the admin panel login page but I can't log in. – Harry Moreno Sep 30 '22 at 19:33
  • Ah I can log in just make sure the user has `is_staff` enabled. – Harry Moreno Oct 04 '22 at 20:46