is_verified() changing from True to False during HTTP redirect

155 views
Skip to first unread message

Karl Goetz

unread,
Feb 8, 2018, 3:37:58 AM2/8/18
to django-otp
Hi,
I have a view (several actually but all displaying the same behaviour) sitting behind @otp_required(if_configured=True) as provided by django_otp. When I attempt to visit these pages with an authenticated but not yet verified user they redirect me to the page for performing second factor where I can enter my details and successfully authenticate.

My log shows the authentication succeeding, then I log that request.user.is_verified() is True and the device the user authenticates against.

What happens then is that I try and HttpResponseRedirect the user back to the page they were trying to visit when asked captured by otp_required . This is where the problem starts, as I'm immediately sent back to my second factor login page. The log indicates  request.user.is_verified() is *no longer* True, but how I could lose that status I'm not sure.

I have the following OTP apps in my installed apps:
    'django_otp',
    'django_otp.plugins.otp_totp',
    'django_otp.plugins.otp_hotp',
    'django_otp.plugins.otp_static',

and loaded django_otp.middleware.OTPMiddleware to my middleware.


Any pointers as to where I can look for this mystery permissions downgrade?

thanks,
Karl.

Peter Sagerson

unread,
Feb 8, 2018, 1:17:28 PM2/8/18
to djang...@googlegroups.com
I would probably start by checking the user's session and making sure the device was persisted. Look at OTPMiddleware to see what's going on--it's pretty straightforward.


--
You received this message because you are subscribed to the Google Groups "django-otp" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-otp+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Karl Goetz

unread,
Feb 11, 2018, 12:14:41 AM2/11/18
to djang...@googlegroups.com, Peter Sagerson
On 9/2/18 05:17, Peter Sagerson wrote:
> I would probably start by checking the user's session and making sure
> the device was persisted. Look at OTPMiddleware to see what's going
> on--it's pretty straightforward.

Thanks for the suggestions!

I didn't have a chance to look at this last week but hope to look in the
coming week - I will report back if I determine what the issue was.

kk


>> On Feb 8, 2018, at 12:37 AM, Karl Goetz <goetz...@gmail.com
signature.asc

Karl Goetz

unread,
Feb 28, 2018, 9:40:09 PM2/28/18
to djang...@googlegroups.com

Hi,
I only just had a chance to come back to this, and while I have more
information unfortunately I don't have more progress.

I'm hoping you can suggest something after reading the details below, if
not I will have to trace the request through the other middlewhere and
see what happens.

On 9/2/18 05:17, Peter Sagerson wrote:
> I would probably start by checking the user's session and making sure
> the device was persisted. Look at OTPMiddleware to see what's going
> on--it's pretty straightforward.


The users device doesn't appear to persist. The logs below show (i hope)
roughly what goes on (i hacked in log statements to the decorator):

When I try and view a protected page for the first time I'm captured and
sent to the login page (as expected)

> 2018-03-01 13:27:38 DEBUG django_otp.decorators: in test()
> 2018-03-01 13:27:38 DEBUG django_otp.decorators: user device None
> 2018-03-01 13:27:38 DEBUG django_otp.decorators: user.is_verified False
> 2018-03-01 13:27:38 DEBUG django_otp.decorators: if_configured True
> 2018-03-01 13:27:38 DEBUG django_otp.decorators: _user_is_authenticated(user) True
> 2018-03-01 13:27:38 DEBUG django_otp.decorators: user_has_device True
> 2018-03-01 13:27:39 DEBUG otp_vip.views: In multi_factor view
> 2018-03-01 13:27:39 DEBUG otp_vip.views: using template otp_vip/validate_vip.html
> 2018-03-01 13:27:39 DEBUG otp_vip.views: is user verified False
> 2018-03-01 13:27:39 DEBUG otp_vip.views: user otp dev None> 2018-03-01 13:27:41 DEBUG otp_vip.views: creating some empty forms


I take my OTP and enter it in the form, printing my POST data as I go.
You can see the verification succeed and the device being recorded
against the user.

> 2018-03-01 13:28:21 DEBUG otp_vip.views: In multi_factor view
> 2018-03-01 13:28:21 DEBUG otp_vip.views: using template otp_vip/validate_vip.html
> 2018-03-01 13:28:21 DEBUG otp_vip.views: is user verified False
> 2018-03-01 13:28:21 DEBUG otp_vip.views: user otp dev None
> 2018-03-01 13:28:21 DEBUG otp_vip.views: <QueryDict: {u'csrfmiddlewaretoken': [u'csrf data'], u'otp_token': [u'638741'], u'otp_device': [u'otp_vip.viptokencredential/33']}>
> 2018-03-01 13:28:21 DEBUG otp_vip.views: attempting to log in via pin
> 2018-03-01 13:28:21 DEBUG otp_vip.credential_models: recording token to db
> 2018-03-01 13:28:21 DEBUG otp_vip.credential_models: Calling validate_token_data with user ka...@kgoetz.id.au and token 638741
> 2018-03-01 13:28:21 DEBUG otp_vip.utils: Initialising ValidateTokenData with user ka...@kgoetz.id.au and code 638741
> 2018-03-01 13:28:22 DEBUG otp_vip.utils: Checking request return code
> 2018-03-01 13:28:22 DEBUG otp_vip.utils: Authentication succeeded at 2018-03-01 13:28:22.035024
> 2018-03-01 13:28:22 DEBUG otp_vip.views: second factor token worked
> 2018-03-01 13:28:22 DEBUG otp_vip.views: is user verified True
> 2018-03-01 13:28:22 DEBUG otp_vip.views: user otp dev VIP access for Mac (v2) (Push enabled False) (kg2652)

In this view I've tried returning an HttpRepsonse('with html in it') and
an HttpResponseRedirect('/to-protectedpage'), both fail in the same way.

The example above is an HttpResponse - a redirect simply goes
immediately in to the next block where the protected page is viewed and
the user captured again due to a missing device/unverified state and
we're back where we started.

> 2018-03-01 13:28:39 DEBUG django_otp.decorators: in test()
> 2018-03-01 13:28:39 DEBUG django_otp.decorators: user device None
> 2018-03-01 13:28:39 DEBUG django_otp.decorators: user.is_verified False
> 2018-03-01 13:28:39 DEBUG django_otp.decorators: if_configured True
> 2018-03-01 13:28:39 DEBUG django_otp.decorators: _user_is_authenticated(user) True
> 2018-03-01 13:28:39 DEBUG django_otp.decorators: user_has_device True
> 2018-03-01 13:28:39 DEBUG otp_vip.views: In multi_factor view
> 2018-03-01 13:28:39 DEBUG otp_vip.views: using template otp_vip/validate_vip.html
> 2018-03-01 13:28:39 DEBUG otp_vip.views: is user verified False
> 2018-03-01 13:28:39 DEBUG otp_vip.views: user otp dev None> 2018-03-01 13:28:41 DEBUG otp_vip.views: creating some empty forms


To check if it was due to middleware ordering, I changed from the
previous configuration to one where OTPMiddleware was immediately after
AuthenticationMiddleware, this doesn't appear to have altered the
systems behaviour.

('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.common.CommonMiddleware',
'dj_pagination.middleware.PaginationMiddleware',
'tendenci.apps.profiles.middleware.ForceLogoutProfileMiddleware',
'tendenci.apps.profiles.middleware.ProfileMiddleware',
'tendenci.apps.base.middleware.Http403Middleware',
'tendenci.apps.redirects.middleware.RedirectMiddleware',
'tendenci.apps.mobile.middleware.MobileMiddleware',
'tendenci.apps.theme.middleware.RequestMiddleware',
'tendenci.apps.base.middleware.MissingAppMiddleware',
'tendenci.apps.memberships.middleware.ExceededMaxTypesMiddleware',
'tendenci.apps.forums.middleware.PybbMiddleware',
'tendenci.apps.profiles.middleware.ProfileLanguageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'htmlmin.middleware.HtmlMinifyMiddleware',
'htmlmin.middleware.MarkRequestMiddleware',
'django_otp.middleware.OTPMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware')


('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.common.CommonMiddleware',
'dj_pagination.middleware.PaginationMiddleware',
'tendenci.apps.profiles.middleware.ForceLogoutProfileMiddleware',
'tendenci.apps.profiles.middleware.ProfileMiddleware',
'tendenci.apps.base.middleware.Http403Middleware',
'tendenci.apps.redirects.middleware.RedirectMiddleware',
'tendenci.apps.mobile.middleware.MobileMiddleware',
'tendenci.apps.theme.middleware.RequestMiddleware',
'tendenci.apps.base.middleware.MissingAppMiddleware',
'tendenci.apps.memberships.middleware.ExceededMaxTypesMiddleware',
'tendenci.apps.forums.middleware.PybbMiddleware',
'tendenci.apps.profiles.middleware.ProfileLanguageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'htmlmin.middleware.HtmlMinifyMiddleware',
'htmlmin.middleware.MarkRequestMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware')


kk

signature.asc

Peter Sagerson

unread,
Mar 2, 2018, 4:06:37 PM3/2/18
to djang...@googlegroups.com
My best guess is that you've customized the login process sufficiently that you're not getting the auto-magic persistence behavior. Most of the documented integration techniques rely on django.contrib.auth.views.login, which sends the user_logged_in signal, which in turn is handled in django_otp/__init__.py. If you're using a custom view for verification, you'll need to do a little extra work.[1]

Thanks,
Peter




Karl Goetz

unread,
Mar 4, 2018, 5:08:32 AM3/4/18
to djang...@googlegroups.com, Peter Sagerson
On 3/3/18 08:06, Peter Sagerson wrote:
> My best guess is that you've customized the login process sufficiently
> that you're not getting the auto-magic persistence behavior. Most of the
> documented integration techniques rely on
> django.contrib.auth.views.login, which sends the user_logged_in signal,
> which in turn is handled in django_otp/__init__.py. If you're using a
> custom view for verification, you'll need to do a little extra work.[1]
>
> Thanks,
> Peter
>
>
> [1] https://django-otp-official.readthedocs.io/en/latest/auth.html#django_otp.login.

Amazing, that was exactly it.
After adding login/_handle_auth_login to the relevant view all the magic
fell in to place.
I'm not sure how that bit slipped through, but its great to see it
working now.

Thanks!
kk

>
>
>> On Feb 28, 2018, at 6:40 PM, Karl Goetz <ka...@kgoetz.id.au
signature.asc
Reply all
Reply to author
Forward
0 new messages