GithubHelp home page GithubHelp logo

gavinwahl / django-u2f Goto Github PK

View Code? Open in Web Editor NEW
166.0 15.0 32.0 146 KB

FIDO U2F security token support for Django

License: BSD 2-Clause "Simplified" License

Python 85.63% JavaScript 5.17% HTML 8.92% Shell 0.29%

django-u2f's Introduction

Django U2F

Build Status

django-u2f provides support for FIDO U2F security tokens in Django. The functionality is similar to the Security Key two-factor authentication that Google recently announced, and uses the same tokens.

django-u2f isn't yet production ready, but is a working proof of concept. There are many TODOs sprinkled around the code that should be fixed before relying on it.

Installation

$ pip install django-u2f

Add django_u2f to INSTALLED_APPS and include django_u2f.urls somewhere in your url patterns. Set LOGIN_URL = 'u2f:login'. Make sure that Django's built in login view does not not have a urlpattern, because it will authenticate users without their second factor. django-u2f provides its own login view to handle that.

Demo

To see a demo, use the test project included in the repo and perform the following steps (using virtualenv is optional):

git clone https://github.com/gavinwahl/django-u2f
cd django-u2f
virtualenv -p python3 venv
source venv/bin/activate
pip install -e .
cd testproj
pip install -r requirements.txt
python manage.py migrate
python manage.py createsuperuser

# finally create a self-signed certificate and start the webserver
./mkcert.sh
python manage.py runserver_plus --cert localhost

For now the only supported browser is Chrome, version 41 or higher. U2F also requires that the page is served over a secure connection.

Start by going to https://localhost:8000/u2f/login. Since you haven't added any security keys yet, you will be logged in with just a username and password. Once logged in, click 'Add another key' on the key management page and follow the instructions. Now your account is protected by two factor authentication, and when you log in again your U2F token will be required.

You can administrate the keys attached to your account on the key management page as well, at the URL https://localhost:8000/u2f/keys.

Using U2F keys on linux

Some distros don't come with udev rules to make USB HID /dev/ nodes accessible to normal users. If your key doesn't light up and start flashing when you expect it to, this might be what is happening. See Yubico/libu2f-host#2 and https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules for some discussion of the rule to make it accessible. If you just want a quick temporary fix, you can run sudo chmod 666 /dev/hidraw* every time after you plug in your key (The files disappear after unplugging).

Helpful links

django-u2f's People

Contributors

acatton avatar bgaudino avatar bheupers avatar brianjp93 avatar frennkie avatar gavinwahl avatar juliancbrown avatar moreati avatar rechner 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

django-u2f's Issues

Custom URL paths with Django-U2F

I prefer to have more control over URL hierarchy. For example, I would prefer that the u2f:login view be served via /login/ instead of /u2f/login/, with the rest of the U2F-related URLs available underneath /settings/security/. I also would like the ability to customize the URL slugs of some of the U2F views. In an effort to accomplish this, I currently use:

u2f_urls = [
    url(r'^multi-factor/', u2f_views.two_factor_settings,
        name='two-factor-settings'),
    url(r'^add-key/', u2f_views.add_key, name='add-u2f-key'),
    url(r'^verify-factor/', u2f_views.verify_second_factor,
        name='verify-second-factor'),
    url(r'^keys/', u2f_views.keys, name='u2f-keys'),
    url(r'^backup-codes/', u2f_views.backup_codes, name='backup-codes'),
    url(r'^add-totp-device/', u2f_views.add_totp, name='add-totp'),
    url(r'^totp-devices/', u2f_views.totp_devices, name='totp-devices'),
]

urlpatterns = [
    url(r'^login/', u2f_views.login, name='login'),
    url(r'^logout/$', auth_views.LogoutView.as_view(
        next_page=reverse_lazy('login')),
        name='logout'),

    url(r'^settings/security/', include(u2f_urls, namespace='u2f')),
    [...]

Question 1: Is there a better way to handle this?

Question 2... In certain rare cases, there will be an unauthenticated request for the verify-second-factor view, which is handled by this bit of code, which yields a NoReverseMatch error because the u2f:login route doesn't exist in my setup above.

I suppose I could add a duplicate login entry in the top stanza so that u2f:login exists, but then I've got redundant login routes at /login/ and /settings/security/login/.

My understanding of Django URL route namespaces is admittedly quite limited, but I can't quite think of the best way to handle this. Might you have any suggestions?

No module django_u2f

Installs via pip:

17:59:15 [aaron@ender:~/code] develop* 1 ± pip install git+https://github.com/gavinwahl/django-u2f.git
Downloading/unpacking git+https://github.com/gavinwahl/django-u2f.git
  Cloning https://github.com/gavinwahl/django-u2f.git to /tmp/pip-yjKj6u-build
  Running setup.py (path:/tmp/pip-yjKj6u-build/setup.py) egg_info for package from git+https://github.com/gavinwahl/django-u2f.git

Downloading/unpacking django-argonauts (from django-u2f==0.0.0)
  Downloading django-argonauts-1.1.4.tar.gz
  Running setup.py (path:/home/aaron/.virtualenvs/code/build/django-argonauts/setup.py) egg_info for package django-argonauts

Requirement already satisfied (use --upgrade to upgrade): django>=1.8 in /home/aaron/.virtualenvs/code/lib/python2.7/site-packages (from django-u2f==0.0.0)
Downloading/unpacking qrcode (from django-u2f==0.0.0)
  Downloading qrcode-5.1.tar.gz
  Running setup.py (path:/home/aaron/.virtualenvs/code/build/qrcode/setup.py) egg_info for package qrcode

Requirement already satisfied (use --upgrade to upgrade): six in /home/aaron/.virtualenvs/code/lib/python2.7/site-packages (from django-u2f==0.0.0)
Installing collected packages: django-argonauts, qrcode, django-u2f
  Running setup.py install for django-argonauts

  Running setup.py install for qrcode

    Installing qr script to /home/aaron/.virtualenvs/bin
  Running setup.py install for django-u2f

Successfully installed django-argonauts qrcode django-u2f
Cleaning up...
18:00:26 [aaron@ender:~/code] develop(+3/-0)* 1 ± 

Try to run the devserver:

18:00:45 [aaron@ender:~/code] develop(+3/-0)* 1 ± python manage.py runserver 0.0.0.0:8000
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/aaron/.virtualenvs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/aaron/.virtualenvs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 312, in execute
    django.setup()
  File "/home/aaron/.virtualenvs/local/lib/python2.7/site-packages/django/__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/aaron/.virtualenvs/local/lib/python2.7/site-packages/django/apps/registry.py", line 85, in populate
    app_config = AppConfig.create(entry)
  File "/home/aaron/.virtualenvs/local/lib/python2.7/site-packages/django/apps/config.py", line 86, in create
    module = import_module(entry)
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
ImportError: No module named django_u2f
18:02:25 [aaron@ender:~/code] develop(+3/-0)* 1 ±

Looking in site-packages directory:

18:04:07 [aaron@ender:~/.virtualenvs/lib/python2.7/site-packages] [] $ find | grep -i u2f
./django_u2f-0.0.0-py2.7.egg-info
./django_u2f-0.0.0-py2.7.egg-info/dependency_links.txt
./django_u2f-0.0.0-py2.7.egg-info/requires.txt
./django_u2f-0.0.0-py2.7.egg-info/SOURCES.txt
./django_u2f-0.0.0-py2.7.egg-info/PKG-INFO
./django_u2f-0.0.0-py2.7.egg-info/top_level.txt
./django_u2f-0.0.0-py2.7.egg-info/installed-files.txt
18:04:10 [aaron@ender:~/.virtualenvs/lib/python2.7/site-packages] [] $ 

There is no django_u2f module folder.

{"errorCode":2}

The /add-key/ page displays the text:

To add a security key to your account, insert (and tap) it.

Error with U2F

With a textbox below it containing the text:
{"errorCode":2}

My key works for signing in to Google, Github, etc...so I don't think it's a key problem.

I don't get any errors in the Django console or the Chrome console.

Admin login doesn't check for a key

The admin uses it's own login view, which delegates to django.contrib.auth.views.login, which doesn't require a key to log in. In the current implementation, this allows you to bypass two-factor auth by just using the admin login view instead of django-u2f's.

The only solution I can't think of is to replace (monkey-patch) auth.views.login with django_u2f.views.login.

There's also a similar bug when someone accidentally registers a non-u2f login view urlpattern accidentally. If the monkey patching happens before urls are loaded, we can prevent this mistake too.

Issues with templating

TemplateDoesNotExist at /u2f/keys/
base.html
Request Method: GET
Request URL: https://localhost:8000/u2f/keys/
Django Version: 1.9.6
Exception Type: TemplateDoesNotExist
Exception Value:
base.html
Exception Location: /home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/site-packages/django/template/engine.py in find_template, line 169
Python Executable: /home/niemand/Development/Django/u2f_django_nzpug/venv/bin/python
Python Version: 3.5.1
Python Path:
['/home/niemand/Development/Django/u2f_django_nzpug',
'/home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python35.zip',
'/home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5',
'/home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/plat-linux',
'/home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/lib-dynload',
'/usr/lib64/python3.5',
'/usr/lib/python3.5',
'/usr/lib/python3.5/plat-linux',
'/home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/site-packages']
Server time: Thu, 12 May 2016 04:40:41 +0000
Template-loader postmortem

Django tried loading these templates, in this order:

Using engine django:
django.template.loaders.app_directories.Loader: /home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/site-packages/django/contrib/admin/templates/base.html (Source does not exist)
django.template.loaders.app_directories.Loader: /home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/site-packages/django/contrib/auth/templates/base.html (Source does not exist)
django.template.loaders.app_directories.Loader: /home/niemand/Development/Django/u2f_django_nzpug/venv/lib/python3.5/site-packages/django_u2f/templates/base.html (Source does not exist)

ErrorCode 2 on Firefox when trying to register

Hi.

When trying this app, I used my main browser, Firefox, which normally works with u2f (on Github, for example). I created a self-signed certificate, and served the testproject on HTTPS, as described on the readme.

On a logged-in account, the https://localhost:8000/u2f/add-key/ page immediately shows an error in the input field: {"errorCode":2} (which means that the appId is incorrect, but the code shows "appId": "https://localhost:8000").
On Chromium (where my keys work as expected), the register request works fine, the page waits for me to plug my key, and when I press the button, the token is written on the field, and the form is submitted.

I tried to simulate a non-local environment, with a fake host in /etc/hosts and a listen port of 443. Still no success (chromium works, but not firefox).

I can’t figure yet what is wrong for Firefox. Do you have any idea?

Thanks.

Error when adding U2F key via Firefox

Many thanks, Gavin, for all your work on django-u2f. I was very pleasantly surprised to see the inclusion of the demo project, which by the way functioned perfectly right out of the box. Bravo!

With full realization that the ReadMe mentions Chrome/Chromium as the only supported browser, I could not help but try Firefox with the U2F add-on (source). When I tapped the U2F device to finalize adding the key, I got an error: ValueError: Missing required fields: version (full traceback follows below).

Interestingly, if I use Chromium to add the U2F key, I can subsequently use Firefox and the U2F add-on to log in successfully.

That said, it would be nice to be able to use Firefox to add U2F keys as well. Do you have any idea what might be behind the error, and perhaps what might be done to fix it?

← Tap triangle to toggle traceback display Traceback (most recent call last): File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 63, in __call__ return self.application(environ, start_response) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/wsgi.py", line 157, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in get_response response = self._middleware_chain(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__ response = self.get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner response = response_for_exception(request, exc) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception return debug.technical_500_response(request, *exc_info) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response six.reraise(exc_type, exc_value, tb) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/six.py", line 686, in reraise raise value File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner response = get_response(request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response response = self.process_exception_by_middleware(e, request) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view return view_func(request, *args, **kwargs) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view return self.dispatch(request, *args, **kwargs) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_u2f/views.py", line 90, in dispatch return super(AddKeyView, self).dispatch(request, *args, **kwargs) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch return handler(request, *args, **kwargs) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django/views/generic/edit.py", line 183, in post return self.form_valid(form) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/django_u2f/views.py", line 115, in form_valid device, attestation_cert = u2f.complete_registration(request, response) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/u2flib_server/u2f.py", line 45, in complete_registration return U2fRegisterRequest.wrap(request).complete(response, valid_facets) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/u2flib_server/model.py", line 416, in complete resp = RegisterResponse.wrap(response) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/u2flib_server/model.py", line 261, in wrap return data if isinstance(data, cls) else cls(data) File "/virtualenvs/u2fdemo/lib/python3.6/site-packages/u2flib_server/model.py", line 246, in __init__ raise ValueError('Missing required fields: %s' % ', '.join(missing)) ValueError: Missing required fields: version

Enhance templates

We want templates that could be used in a real environment without too many shame, for a start

Improve error management in forms

Any exception (for example, a JSONDecodeError) while decoding the responses from the client leads to an error page instead of showing the form again with a readable error

ImportError: cannot import name u2f_v2

I tried to install django-u2f followed all the procedure then when i ran the command
python manage.py syncdb

the error i am getting it

from django_u2f import views as u2f_views
File "/home/r3dt3am/Desktop/projects/U2F/venv/local/lib/python2.7/site-packages/django_u2f/views.py", line 24, in <module>
from u2flib_server import u2f_v2 as u2f
ImportError: cannot import name u2f_v2

TemplateDoesNotExist: u2f/login.html

Hi you.

I run server with the follow command:
......django-u2f/testproj$ sudo python manage.py runserver_plus --cert localhost

When I try to access "https://localhost:8000/u2f/login/" I meet an error as below:

127.0.0.1 - - [14/Jan/2017 17:00:42] "GET /u2f/login/ HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/django/contrib/staticfiles/handlers.py", line 63, in call
return self.application(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/wsgi.py", line 170, in call
response = self.get_response(request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 124, in get_response
response = self._middleware_chain(request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 41, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 86, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 128, in handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
File "/usr/local/lib/python2.7/dist-packages/django_extensions/management/technical_response.py", line 6, in null_technical_500_response
six.reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 39, in inner
response = get_response(request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 217, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 215, in _get_response
response = response.render()
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py", line 109, in render
self.content = self.rendered_content
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py", line 84, in rendered_content
template = self.resolve_template(self.template_name)
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py", line 68, in resolve_template
return get_template(template, using=self.using)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py", line 25, in get_template
raise TemplateDoesNotExist(template_name, chain=chain)
TemplateDoesNotExist: u2f/login.html

Attestation signature verification failed (testproj)

I set up the demo project, and after logging in I tried to add a key, but got the error "Attestation signature verification failed!" (from u2flib_server).

To try to figure out what was going wrong, I tried doing the process manually: I started up u2f_server.py from python-u2flib-server (as described in their README) and used curl to hit the enroll endpoint and get a challenge. I used the JS API (from the Chrome extension) to send the challenge to my key and get the response data, which I submitted to u2f_server.py using curl again...and it worked. (My key is also working in Gmail and Yubico's demo.)

I stepped through u2f.complete_register for both the successful (manual) request as well as the unsuccessful one from the test project, and didn't spot a problem... Do you know what might be going wrong?

DeprecationWarning for verifier (upstream issue)

I just ran the Demo and noticed a DeprecationWarning:

/home/user/django-u2f/venv/lib/python3.5/site-packages/u2flib_server/model.py:210: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead.
  verifier = pubkey.verifier(self.signature, ec.ECDSA(hashes.SHA256()))

Ensure i18n is ready

I’ve seen error messages that weren’t encapsulated in the gettext_lazy() function. We should make sure that every string echoed by Django-U2F is ready to be translated, and provide a second language support. I’m willing to work on french translations

Integration with django-two-factor-auth and/or django-otp

Gavin, I've made a hacky proof of concept for U2F with django-two-factor-auth moreati/django-two-factor-auth@a44ac23. It doesn't use django-u2f, but it's based heavily on it.

I think the proper route to integration is a django-otp plugin that implements U2F. For the next step the options I see are:

  1. Create django-otp-u2f a fork of django-u2f, that is seperate to django-u2f
  2. Turn django-u2f into a django-otp plugin. This would:
    • Replace django-u2f's model with a django-otp Device subclass (with migration scripts for the django_u2f.models, if possible/desirable)
    • Replace django-u2f's LOGIN_URL integration with that from django-otp (or possibly django-two-factor-auth)
    • Migrate/replace django-u2f's forms to integrate with django-otp and django-two-factor-auth
  3. Keep existing django-Add extra models/forms/views to django-u2f that in

Do you have a preference? Based on simplicity/maintenance mine is the 2nd, but I don't have an existing install base or users.

Are you aware of anybody using django-u2f in anger?

Any other thoughts? Queries?

Backup codes shouldn't be sufficient to enable MFA

Backup codes by themselves are not a good option for multi-factor authentication, and yet at present it is too easy for users to generate backup codes and, in the process, enable backup-code-only MFA.

I can think of two changes that would help mitigate this:

  1. Change the default templates such that backup code generation links are not displayed until either U2F or TOTP is enabled.

  2. Remove backup codes from the requires_two_factor function.

While (1) above may be sufficient to avoid the problem in most cases, I'm having a difficult time understanding why someone would want backup-code-only MFA, which is why I proposed (2) as well. That said, perhaps I'm missing something — if so, please enlighten me. ☺️

@gavinwahl: What do you think?

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.