django-two-factor-auth icon indicating copy to clipboard operation
django-two-factor-auth copied to clipboard

Enforcing two-factor not working after logout

Open tchimih opened this issue 4 years ago • 6 comments

Expected Behavior

When trying to enforce a view with two-factor authentication, the method is_verified() should work even after the user logged out.

Current Behavior

When the user activate the two-factor, the is_verified() returns true. However, when he logout and login again with two factor (sms; yubikey or otp) theis_verified retruns false.

Context

Settings file

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'qsessions',
    'django_otp',
    'django_otp.plugins.otp_static',
    'django_otp.plugins.otp_totp',
    'two_factor',
    'otp_yubikey',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'authentication',
    'app',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'qsessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django_otp.middleware.OTPMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Your Environment

  • Browser and version: Chrome
  • Python version: 3.6
  • Django version: 3.0.4
  • Dango otp: 0.8.1
  • django-otp-yubikey: 0.5.2
  • django-two-factor-auth version: 1.7.0

tchimih avatar Apr 22 '20 15:04 tchimih

That is expected behaviour as Django clears out the user session on logout. If you're wanting users to be able to skip 2FA the next time they log in, then that's already covered by #56 and there's a PR #352 with a proposed fix.

moggers87 avatar Apr 22 '20 16:04 moggers87

I don't quite understand. The is_verified() returns false even after a successful login with 2FA, is that an expected behavior ?

Here are the steps:

  • User log in with simple credential,
  • User enables two_factor and the is_verified() returns True,
  • User logout and login with 2FA (yubkiey, ...)
  • is_verfied() returns false even when the user has logged in using the 2FA.

How can check if the user has logged in with 2FA ?

tchimih avatar Apr 22 '20 17:04 tchimih

Oh, so you've logged in again? That is a bug then.

moggers87 avatar Apr 22 '20 21:04 moggers87

Yeah, I've logged in again and it retruns false. Here is a snippet of my code:

def home(request):
    if not request.user.is_authenticated:
        return redirect("/account/login")
    if not request.user.is_verified():
        return redirect('/account/two_factor')
   ...

Can I maybe read the django-otp models in order to check whether the user has a otp device ? could be a temporary solution.

tchimih avatar Apr 23 '20 07:04 tchimih

Finally got around to looking at this bug and I'm unable to reproduce. I followed these steps:

  1. logged in
  2. enabled 2fa
  3. logged out
  4. logged back in again with 2fa

After that I could still access two-factor protected views. Does this happen with token devices too? I'm wondering if this is just an issue with Phone/SMS as I think you're missing the ThreadLocal middleware. See the docs for additional configuration required for Twilio: https://django-two-factor-auth.readthedocs.io/en/stable/configuration.html#twilio-gateway

moggers87 avatar May 21 '20 15:05 moggers87

Also I notice you're using django-two-factor-auth 1.7.0 with Django 3.0, which not supported. I doubt it's the cause of this issue, but I strongly recommend upgrading to the latest version of django-two-factor-auth (1.10.0 is the oldest release to support Django 3.0 fyi)

moggers87 avatar May 21 '20 15:05 moggers87