Implementing a secure two-factor authentication for a login page with Django form wizard

Edwin picture Edwin · Feb 23, 2011 · Viewed 7.5k times · Source

So basically i want to achieve something similar to Google Two-factor authentication implementation. My login form consists of a 2-step form wizard:

  1. Step 1 (verifying username and password)
  2. Step 2 (authenticate security token)

The usage scenarios would be:

  1. User has a security token associated with his account: logs user in if user passes Step 1 and Step 2
  2. User doesn't have a security token: logs user in right after he passes Step 1 only

I'm subclassing django's Form Wizard now to be used as my login view. In Step 2, by default Django FormWizard will include field values from previously submitted forms as hidden fields. But as you know, password is entered in Step 1, so I don't want to include it in Step 2 for security reasons.

My first thought would be to use session to indicate if a user has passed Step 1, so I don't need to include field values from Step 1.. but I may be overlooking something here. What are the more secure solutions to this?

Also I don't quite understand the use of security-hash in FormWizard. Can someone explain?

Thanks a lot.

Answer

Karl Anderson picture Karl Anderson · Apr 23, 2011

Duo Security's duo_web project has an open source Django demo which will show you one way to do this (I am a Duo developer).

The demo setup has a @duo_auth_requried decorator similar to the builtin @login_required which checks for a session cookie indicating that the user has passed the 2nd factor authentication. The @login_required decorator verifies local authentication, the @duo_auth_required decorator verifies 2nd factor authentication, and the lack of either redirects the user to the relevant form.

The difference with your description is that we don't authenticate both in a single form or pass credentials between forms, we do them separately. Just protect a view with both decorators and you can rely on Django to assert local authentication before the 2nd factor auth is attempted.