Giter VIP home page Giter VIP logo

django-two-factor-auth's Introduction

Django Two-Factor Authentication

Jazzband

Build Status

Test Coverage

PyPI

Complete Two-Factor Authentication for Django. Built on top of the one-time password framework django-otp and Django's built-in authentication framework django.contrib.auth for providing the easiest integration into most Django projects. Inspired by the user experience of Google's Two-Step Authentication, allowing users to authenticate through call, text messages (SMS), by using a token generator app like Google Authenticator or a YubiKey hardware token generator (optional).

If you run into problems, please file an issue on GitHub, or contribute to the project by forking the repository and sending some pull requests. The package is translated into English, Dutch and other languages. Please contribute your own language using Transifex.

Test drive this app through the example app. It demos most features except the Twilio integration. The example also includes django-user-sessions for providing Django sessions with a foreign key to the user. Although the package is optional, it improves account security control over django.contrib.sessions.

Compatible with supported Django and Python versions. At the moment of writing that includes 3.2, 4.0, 4.1, and 4.2 on Python 3.8, 3.9, 3.10 and 3.11. Documentation is available at readthedocs.io.

Installation

Refer to the installation instructions in the documentation.

Getting help

For general questions regarding this package, please hop over to Stack Overflow. If you think there is an issue with this package; check if the issue is already listed (either open or closed), and file an issue if it's not.

Contribute

Read the contribution guidelines.

See Also

Have a look at django-user-sessions for Django sessions with a foreign key to the user. This package is also included in the example app.

License

The project is licensed under the MIT license.

django-two-factor-auth's People

Contributors

ameriks avatar beckedorf avatar bouke avatar chipx86 avatar claudep avatar d3x avatar dekkers avatar dessibelle avatar dopry avatar eljhkrr avatar emord avatar jpaniagualaconich avatar julianwachholz avatar markush avatar mlec1 avatar moggers87 avatar moreati avatar mweesenaar avatar petrdlouhy avatar peymanslh avatar pierref avatar pre-commit-ci[bot] avatar sergei-maertens avatar shanx avatar smarthall avatar suprasummus avatar timgates42 avatar tusky avatar v1kku avatar vvojvoda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-two-factor-auth's Issues

Trouble with migrations in Django 1.7.2

After migrating from 1.0.0 -> 1.1.0 running python manage.py migrate gives us this warning:

Your models have changes that are not yet reflected in a migration, and so won't be applied.
Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.

And running python manage.py makemigrations gives us:

Migrations for 'two_factor':
  0002_auto_20150109_1536.py:
    - Alter field key on phonedevice

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/core/management/__init__.pyc in execute_from_command_line(argv)
    383     """
    384     utility = ManagementUtility(argv)
--> 385     utility.execute()

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/core/management/__init__.pyc in execute(self)
    375             sys.stdout.write(self.main_help_text() + '\n')
    376         else:
--> 377             self.fetch_command(subcommand).run_from_argv(self.argv)
    378 
    379 

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/core/management/base.pyc in run_from_argv(self, argv)
    286         handle_default_options(options)
    287         try:
--> 288             self.execute(*args, **options.__dict__)
    289         except Exception as e:
    290             if options.traceback or not isinstance(e, CommandError):

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/core/management/base.pyc in execute(self, *args, **options)
    336                     not options.get('skip_checks')):
    337                 self.check()
--> 338             output = self.handle(*args, **options)
    339             if output:
    340                 if self.output_transaction:

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/core/management/commands/makemigrations.pyc in handle(self, *app_labels, **options)
    122             return
    123 
--> 124         self.write_migration_files(changes)
    125 
    126     def write_migration_files(self, changes):

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/core/management/commands/makemigrations.pyc in write_migration_files(self, changes)
    150                         # We just do this once per app
    151                         directory_created[app_label] = True
--> 152                     migration_string = writer.as_string()
    153                     with open(writer.path, "wb") as fh:
    154                         fh.write(migration_string)

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/db/migrations/writer.pyc in as_string(self)
    129         operations = []
    130         for operation in self.migration.operations:
--> 131             operation_string, operati�on_imports = OperationWriter(operation).serialize()
    132             imports.update(operation_imports)
    133             operations.append(operation_string)

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/db/migrations/writer.pyc in serialize(self)
     86                     self.feed('],')
     87             else:
---> 88                 arg_string, arg_imports = MigrationWriter.serialize(arg_value)
     89                 self.feed('%s=%s,' % (arg_name, arg_string))
     90                 imports.update(arg_imports)

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/db/migrations/writer.pyc in serialize(cls, value)
    331         elif isinstance(value, models.Field):
    332             attr_name, path, args, kwargs = value.deconstruct()
--> 333             return cls.serialize_deconstructed(path, args, kwargs)
    334         # Classes
    335         elif isinstance(value, type):

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/db/migrations/writer.pyc in serialize_deconstructed(cls, path, args, kwargs)
    237             imports.update(arg_imports)
    238         for kw, arg in kwargs.items():
--> 239             arg_string, arg_imports = cls.serialize(arg)
    240             imports.update(arg_imports)
    241             strings.append("%s=%s" % (kw, arg_string))

/Users/kyle/.virtualenv/lib/python2.7/site-packages/django/db/migrations/writer.pyc in serialize(cls, value)
    358             # Further error checking
    359             if value.__name__ == '<lambda>':
--> 360                 raise ValueError("Cannot serialize function: lambda")
    361             if value.__module__ is None:
    362                 raise ValueError("Cannot serialize function %r: No module" % value)

ValueError: Cannot serialize function: lambda

Reverting back to 1.0.0 makes these errors go away.

Django 1.7.2
Python 2.7.8

Warn user when backup device used

Since more backup devices increase the attack surface of login (although enhance usability), would it make sense to provide a fake (optionally real) email warning to the registered user when a backup device is used, instead of the main device?

Todo version 0.3

Wishlist:

  • #19 Mixin class for requiring OTP
  • #21 When requiring OTP, tell users to enable it (instead of redirecting to login view)
  • #18 - Optionally enforce OTP for admin views
  • #23 Investigate how to integrate with social logins (openid/oauth)
  • #22 Views documentation
  • #20 Include back button on backup tokens views
  • Allow a few days for translators to update translations

Manual auto-login

I saw that in 5515a77 you enabled auto-login after setting up a device.

How do we use this in a registration form? The usual way with authenticate() and login() doesn't seem to be working. ;)

YubiKey is requested when entering backup token

On my account, I've selected YubiKey as the primary OTP source. I've also created backup tokens. Now when I login and select 'use backup token', the form is still asking for a YubiKey. Now I could probably enter my backup tokens, but it doesn't seem right.

Cannot generate QR code for unicode characters

Hello, I found this,I need some help to get it work:

UnicodeEncodeError at /account/two_factor/qrcode
'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)
Request Method: GET
Request URL:    http://test.example.com/account/two_factor/qrcode
Django Version: 1.4.13
Exception Type: UnicodeEncodeError
Exception Value:    
'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)
Exception Location: /usr/local/lib/python2.7/dist-packages/two_factor/views/core.py in get, line 504
Python Executable:  /usr/bin/python
Python Version: 2.7.3
Python Path:    
['/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-linux2',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages',
 '/data/blog']
Server time:    星期二, 15 七月 2014 18:26:08 +0800
Unicode error hint

The string that could not be encoded/decoded was: 测试网站....

Django-CMS installation/integration

I have followed the steps to install django-two-factor-auth on django-cms, no errors or issues during the installation process.

the only difference is that urls.py of django-cms supports multilingual which urlpatterns has the below

urlpatterns = i18n_patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^', include('cms.urls')),
    url(r'', include('two_factor.urls', 'two_factor')),
)

then i tried to move it to the commented part of urlpatterns on top:

urlpatterns = patterns('',
    url(r'', include('two_factor.urls', 'two_factor')),
    # Examples:
    # url(r'^$', 'projectname.views.home', name='home'),
    # url(r'^projectname/', include('projectname.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
)

without luck

on your herokuapp demo it shows in the url /accounts/ do i need pinax's django-user-accounts to be able to have the page for users to setup django-two-factor-auth?

Admin not secure when using admindocs

If user try to access admin/doc then even with two-factor is enabled it is redirected towards the old login page and on passing valid credentials it opens the dashboard.

ValueError: u'token' is not in list in two_factor.views.utils in process_step

Stacktrace (most recent call last):

  File "django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "django/views/generic/base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
  File "django/utils/decorators.py", line 29, in _wrapper
    return bound_func(*args, **kwargs)
  File "django/views/decorators/debug.py", line 75, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
  File "django/utils/decorators.py", line 25, in bound_func
    return func(self, *args2, **kwargs2)
  File "django/utils/decorators.py", line 29, in _wrapper
    return bound_func(*args, **kwargs)
  File "django/views/decorators/cache.py", line 52, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "django/utils/decorators.py", line 25, in bound_func
    return func(self, *args2, **kwargs2)
  File "django/contrib/formtools/wizard/views.py", line 236, in dispatch
    response = super(WizardView, self).dispatch(request, *args, **kwargs)
  File "django/views/generic/base.py", line 87, in dispatch
    return handler(request, *args, **kwargs)
  File "two_factor/views/core.py", line 91, in post
    return super(LoginView, self).post(*args, **kwargs)
  File "django/contrib/formtools/wizard/views.py", line 291, in post
    self.storage.set_step_data(self.steps.current, self.process_step(form))
  File "two_factor/views/utils.py", line 96, in process_step
    key = keys.index(step) + 1

Not sure why this is happening, and it happens randomly. Seems like it might we a session issue?

Defaulting country code if one isn't provided

Is it possible to have some sort of configuration variable to enable automatically defaulting to a particular country code if one isn't provided? For my site, the vast majority of the users are in the US and have US mobile numbers so it's confusing to require +1 at the beginning. Right now I added the following code to PhoneNumberForm in forms.py but obviously this isn't ideal:

def clean_number(self):
    data = self.cleaned_data.get('number', '')
    if not data:
        raise forms.ValidationError("You must enter a phone number")
    if len(data) == 10 and (data[0:1] != "+" or data[0:2] != "00"):
        # Assume US number and prepend +1.
        data = "+1" + data
    return data

during integration

trying to integrate this into a django/mezzanine app, but when I "login", I'm getting

ProgrammingError at /account/login/
relation "otp_static_staticdevice" does not exist
LINE 1: ...name", "otp_static_staticdevice"."confirmed" FROM "otp_stati...
                                                             ^
Request Method: POST
Request URL:    http://127.0.0.1:8000/account/login/
Django Version: 1.6.1
Exception Type: ProgrammingError
Exception Value:    
relation "otp_static_staticdevice" does not exist
LINE 1: ...name", "otp_static_staticdevice"."confirmed" FROM "otp_stati...
                                                             ^

and this is getting thrown for both existing users and with ones I've just registered successfully. Any ideas? I have run migrations.

Remember OTP token for hours

I want to implement remember otp for few hours 10 hrs. Means on first attempt admin gives userid/password an then give the OTP and for next 10 hrs when admin try to login again then it asks for userid/password only and skip the OTP till the 10 hrs.

Whats the best place to implement this in codebase.

User sometimes sent to login page when attempting to generate backup tokens

If a user has only just set up two-factor authentication and then attempts to generate backup tokens or any other view protected by the otp_required decorator, they are sent to the login page (where they need to enter their username and password). This can be replicated on the example app.

I find this a bit jarring as I'm already logged in and propose two changes:

  1. LoginView should detect that the user has logged in and skip the username/password step
  2. Setting up two factor auth should count as having logged in with an OTP device, e.g. request.user.is_verified() should return True

Having either (or even both) of these would solve this issue.

Changing the LoginView is hopefully quite trivial, but I would like to hear people's opinions on the 2nd change before I attempt doing anything for it.

Back-up tokens cannot be used for login

The example app demonstrates the generation and viewing of backup codes through a backup static device. There does not appear to be a way to use these backup tokens to log in though.

Support for custom user model, and especially USERNAME_FIELD

How feasible would it be to support a custom user model? At least one thing that would have to be updated is that all references to user.username, for example:

https://github.com/Bouke/django-two-factor-auth/blob/d113b80c220bcf62b25d252d5980f02420c8c270/two_factor/views/core.py#L444

would have to be updated to use the USERNAME_FIELD (https://docs.djangoproject.com/en/dev/topics/auth/customizing/#django.contrib.auth.models.CustomUser.USERNAME_FIELD) setting on the user model (for cases where, for example, USERNAME_FIELD=email and there is no "username" attribute).

Twilio libraries are required

The Twilio python libraries are required for the application to work, however they are not included in the install requirements.

Only allow call+sms authentication for certain users

As outbound text messages and calls are not free, it would be nice to specify which users can use these methods for authenticating. Authentication through the iPhone app is free, so that does not need to be limited.

Google Authenticator does not work with example app.

Steps:

  1. Go to http://example-two-factor-auth.herokuapp.com/
  2. Follow steps under "next steps", and choose "Token generator" in step 3.
  3. Use "Google Authenticator" app with the ZXing barcode scanner to scan the QR code.

Results:
An error stating "Please enter a valid token." when I try entering the code (eg. 707923) shown in my Google Authenticator app.

Notes:
Test account info:
username: vectortest
password: a

In Google Authenticator, I see "[email protected]" as the account id.

TWO_FACTOR_PATCH_ADMIN with false asks for OTP

Following are the steps.
First TWO_FACTOR_PATCH_ADMIN = True and enable this on admin account.
Now Set this flag to False.

Now i have following issues.

1.I can access standard admin/login but patched admin/account/login is also accessible.
2. And if i login from patched admin/account/login then it asks for the OTP.

I think if TWO_FACTOR_PATCH_ADMIN = False then the the package functionality should be disabled. For the moment i make the urls disable depending upon the settings value.

Advise to add backup devices after setup

Once the initial two-factor setup is completed; the user is redirected to the profile page. However for account recovery, it would be better that the user adds a backup device. This could be a phone number, for call / sms token delivery, or it could be a set of backup tokens. If the user chooses to (a) not add a backup device or (b) cancels adding the backup device, two-factor should still be enabled; not to be dependent on the addition of a backup device.

LOGIN_URL issue

We are using single setting file for django project (frontend + admin with two factor enabled) and both are using LOGIN_URL. Now we want to enable two factor for our site. two factor app expects same variable (LOGIN_URL) in settings but we might need different value for two factor.

How we can achieve this ??

We might thinking to change the LOGIN_URL in two-factor code with
TWO_FACTOR_LOGIN_URL or do u have any other idea to achieve this ?

adding more SMS gateways

I was wondering where to start for adding more international SMS gateways such as clickatell or others that uses simple web api/url for sending SMSs?

AttributeError: 'bool' object has no attribute 'otp_device'

There appears to be a bug in views.core.LoginView.get_user() when the form for whatever reason is invalid it sets user_cache to False. This causes AttributeError by otp_device.

Probably should break out line 154 so that it wont have the potential to return a boolean for user_cache.

Management command for enabling two-factor for a user

Just a quick thought: aren't the management commands a bit ambigous? disable and status might very well refer to pretty much anything on a Django install. I'd argue that a better naming would be something like:

./manage.py two_factor_status <username>
./manage.py two_factor_disable <username>

On a side note, an enable command would be useful as well, as a way of enforcing two factor auth for all users from day one. Would that even be possible (given that an admin would supply phone numbers, hand out codes etc.)? I'd be happy to submit at PR if that's the case.

Allow other Twilio voice language

Supported languages:

For voice set to man or woman, select English with an American accent (en), English with a British accent (en-gb), Spanish (es), French (fr), Italian (it), and German (de). The default is English with an American accent (en).

Template missing

Get this error:

raise TemplateDoesNotExist(name)

TemplateDoesNotExist: base.html

On the lastest version.

cannot import name six

after pip install i'm running manage.py syncdb and getting this error:
raise ImproperlyConfigured('ImportError %s: %s' % (app, e.args[0]))
django.core.exceptions.ImproperlyConfigured: ImportError django_otp: cannot import name six

django 1.4
python 2.7.3

Token not valid issue on iphone3gs

/account/two_factor/setup/
During setup iphone scans and generate the token but it is not verified by the form keep giving me error.Please enter a valid token.

But for andriod phone this is working fine

New SMS integration

Hello @Bouke ,
I'm traveling to DjangoCon[1] Europe next week and thought of working on new SMS gateway integration for django-two-factor-auth after working on the translation.

Can you please let me know from where I need to start (keeping in mind i haven't worked on code for almost a decade since i have my own team 😄)

Best Regards
Bashar
P.S: are you coming to DjangoCon?
[1] http://2014.djangocon.eu/

Yubikey support

Hi! I just want to thank you for your work on this! It's pretty amazing. I was wondering if Yubikey support would be added at any point, since django-otp also supports Yubikeys?

Double login on first autentification

Here is a usecase to reproduce. It can be reproduced on demo app on heroku or on any other installation of django two factor.

  1. Register a new user.
  2. Login with new user
  3. Enable two factor auth.
  4. Enter phone number
  5. Enter code that should be send to phone number
  6. So far all good.
  7. Now go to profile page
  8. Click add new phone number button
    And here comes a problem. Two factor asks to login to do that. But the user already logged in. This shouldn't happen.
    If i logout from site completely and then login and try to add new phone number - works as expected, no login screens. So this only happen on new users who enabled two factor, and wanted to add a new phone.

Selectively force two-factor for users

For securing accounts of admin users it would be nice to force them to enable two-factor authentication. Two-factor should be optional for normal users.

Release RC1

Now that beta 1 has been released, RC1 should be released if no blockers are found.

iPhone/iPad fails to read qr code with spaces in "alias"

If you have a space in the get_current_site(self.request).name, the QR code fails to read on an iPhone or iPad. Android will read the QR code because it uses a more lenient url handler. urlencoding the alias should fix the problem.

Twilio gateway might be vulnerable to voicemail hack

See also this blogpost which uses the victim's voicemail service to access OTP tokens. When the call goes to voicemail, the tokens can be access through a vulnerable voicemail service (e.g. requiring no PIN). Then the attacker will have access to the tokens and is able to login. When requiring interaction (e.g. pressing a button), this type of attack can be disarmed. Major services like Google and Yahoo are still vulnerable to this type of attack.

Could we please get a new release?

I'm currently waiting to merge two factor authentication into the RatticWeb project. I don't really want to be pointing at an unreleased version of this project when my next version goes out. Is it possible to get 0.5.0 released?

Seed column too short?

My system is generating 20 character seeds, but the DB column is VACHAR(16) so it's getting truncated. I've manually fixed this, but perhaps the project need a new migration.

Ubuntu 10.04
Python 2.6.5
Django 1.5.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.