diff --git a/COPYING b/COPYING index 2b5ff4106..3c2af0df4 100644 --- a/COPYING +++ b/COPYING @@ -663,7 +663,5 @@ if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . -External modules oath and totp-js modules are licensed under a BSD-like licence. - OpenID idp module is derived of the project django_openid_provider which is distributed under the Apache 2.0 license. diff --git a/authentic2/auth2_auth/auth2_oath/__init__.py b/authentic2/auth2_auth/auth2_oath/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/authentic2/auth2_auth/auth2_oath/backend.py b/authentic2/auth2_auth/auth2_oath/backend.py deleted file mode 100644 index 96b7103c7..000000000 --- a/authentic2/auth2_auth/auth2_oath/backend.py +++ /dev/null @@ -1,60 +0,0 @@ -import logging - -from django.db import transaction -from django.conf import settings - -from authentic2.compat import get_user_model -import authentic2.vendor.oath.hotp as hotp -from authentic2.nonce import accept_nonce -import models -logger = logging.getLogger('authentic.auth.auth2_oath') - -NONCE_TIMEOUT = getattr(settings, 'OATH_NONCE_TIMEOUT', - getattr(settings, 'NONCE_TIMEOUT', 3600)) - -class OATHTOTPBackend: - supports_object_permissions = False - supports_anonymous_user = False - - @transaction.commit_on_success() - def authenticate(self, username, oath_otp, format='dec6'): - '''Lookup the TOTP or HOTP secret for the user and try to authenticate - the proposed OTP using it. - ''' - User = get_user_model() - try: - secret = models.OATHTOTPSecret.objects.get(user__username=username) - except models.OATHTOTPSecret.DoesNotExist: - return None - try: - accepted, drift = hotp.accept_totp(secret.key, oath_otp, format=format) - except Exception, e: - logger.exception('hotp.accept_totp raised', e) - raise - - if accepted: - if not accept_nonce(oath_otp, 'OATH_OTP', NONCE_TIMEOUT): - logger.error('already used OTP %r', oath_otp) - return None - - secret.drift = drift - return User.objects.get(username=username) - else: - return None - - def get_user(self, user_id): - """ - simply return the user object. That way, we only need top look-up the - certificate once, when loggin in - """ - User = get_user_model() - try: - return User.objects.get(id=user_id) - except User.DoesNotExist: - return None - - def setup_totp(self, user): - '''Create a model containing a TOTP secret for the given user and the - current time drift which initially is zero - ''' - pass diff --git a/authentic2/auth2_auth/auth2_oath/frontend.py b/authentic2/auth2_auth/auth2_oath/frontend.py deleted file mode 100644 index 5b2c0d182..000000000 --- a/authentic2/auth2_auth/auth2_oath/frontend.py +++ /dev/null @@ -1,64 +0,0 @@ -from django.utils.translation import ugettext as _ -from django.utils.translation import gettext_noop -from django.contrib.auth.forms import AuthenticationForm -from django.contrib.auth import login, authenticate -from django.http import HttpResponseRedirect -import django.forms as forms - -import authentic2.auth2_auth.models as models -import views - -# Only difference with login/password form is the user of 'otp' intead of -# password as an argument to the authenticate() method -# So you need an OTP enabled backend to this to work -class OATHOTPHAuthenticationForm(AuthenticationForm): - def clean(self): - username = self.cleaned_data.get('username') - password = self.cleaned_data.get('password') - - if username and password: - self.user_cache = authenticate(username=username, oath_otp=password) - if self.user_cache is None: - raise forms.ValidationError(_("Please enter a correct username and one-time password. Note that both fields are case-sensitive.")) - elif not self.user_cache.is_active: - raise forms.ValidationError(_("This account is inactive.")) - - # TODO: determine whether this should move to its own method. - if self.request: - if not self.request.session.test_cookie_worked(): - raise forms.ValidationError(_("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in.")) - - return self.cleaned_data - - -class OATHOTPFrontend(object): - def enabled(self): - return True - - def name(self): - return gettext_noop('One time password') - - def id(self): - return 'oath-otp' - - def form(self): - return OATHOTPHAuthenticationForm - - def post(self, request, form, nonce, next): - # Login the user - login(request, form.get_user()) - # Keep a trace - if 'HTTPS' in request.environ.get('HTTPS','').lower() == 'on': - how = 'oath-totp-on-https' - else: - how = 'oath-totp' - if nonce: - models.AuthenticationEvent(who=form.get_user().username, how=how, - nonce=nonce).save() - return HttpResponseRedirect(next) - - def profile(self, request, next=''): - return views.totp_profile(request, next) - - def template(self): - return 'auth/login_form_oath.html' diff --git a/authentic2/auth2_auth/auth2_oath/locale/fr/LC_MESSAGES/django.po b/authentic2/auth2_auth/auth2_oath/locale/fr/LC_MESSAGES/django.po deleted file mode 100644 index 284d3458f..000000000 --- a/authentic2/auth2_auth/auth2_oath/locale/fr/LC_MESSAGES/django.po +++ /dev/null @@ -1,120 +0,0 @@ -# French translation of Authentic -# Copyright (C) 2010, 2011 Entr'ouvert -# This file is distributed under the same license as the Authentic package. -# Frederic Peters , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Authentic\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-23 17:44+0200\n" -"PO-Revision-Date: 2013-07-23 17:42+0200\n" -"Last-Translator: Mikaël Ates \n" -"Language-Team: None\n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n>1;\n" - -#: frontend.py:22 -msgid "" -"Please enter a correct username and one-time password. Note that both fields " -"are case-sensitive." -msgstr "" -"Veuillez taper un nom d'utilisateur correct et un mot de passe à usage " -"unique. Notez que les deux champs sont sensibles à la casse." - -#: frontend.py:24 -msgid "This account is inactive." -msgstr "Ce compte est inactif." - -#: frontend.py:29 -msgid "" -"Your Web browser doesn't appear to have cookies enabled. Cookies are " -"required for logging in." -msgstr "" -"Il semblerait que votre navigateur ne supporte pas les cookies. Les cookies " -"sont requis pour se connecter." - -#: frontend.py:39 -msgid "One time password" -msgstr "Mot de passe à usage unique" - -#: templates/auth/login_form_oath.html:5 -msgid "" -"\n" -"Once you have created your account, log in with an other authentication " -"method.\n" -"Then, in account management, follow the instructions to deploy the\n" -"One Time password authentication method.\n" -msgstr "" -"\n" -"Une fois votre compte créé, connectez-vous à l'aide d'une autre méthode.\n" -"Alors, dans l'interface de gestion de votre compte, suivez les instructions " -"pour déployer la\n" -"méthode d'authentification basée sur le mot de passe à usage unique.\n" - -#: templates/auth/login_form_oath.html:16 -msgid "Log in" -msgstr "S'identifier" - -#: templates/auth/login_form_oath.html:18 -msgid "Cancel" -msgstr "Annuler" - -#: templates/auth/login_form_oath.html:24 -msgid "Forgot password?" -msgstr "Mot de passe oublié ?" - -#: templates/auth/login_form_oath.html:24 -msgid "Reset it!" -msgstr "Le réinitialiser !" - -#: templates/auth/login_form_oath.html:25 -msgid "Not a member?" -msgstr "Pas un membre ?" - -#: templates/auth/login_form_oath.html:25 -msgid "Register!" -msgstr "S'inscrire !" - -#: templates/oath/totp_profile.html:5 -msgid "Time based one-time password" -msgstr "Mot de passe à usage unique basé sur le temps" - -#: templates/oath/totp_profile.html:8 -msgid "Secret" -msgstr "Secret" - -#: templates/oath/totp_profile.html:10 -msgid "Google authenticator" -msgstr "Google authenticator" - -#: templates/oath/totp_profile.html:12 -msgid "Bookmarklet" -msgstr "Marque-page générateur de mot de passe" - -#: templates/oath/totp_profile.html:13 -msgid "" -"Copy this link to your bookmarks. When clicking on it it will generate a new " -"one-time password which will allow you to login" -msgstr "" -"Copier ce lien dans vos marque-pages. Cliquez le pour générer un nouveau mot " -"de passe à usage unique pour vous connecter." - -#: templates/oath/totp_profile.html:16 -msgid "Delete this credential" -msgstr "Supprimer ce moyen d'authentification" - -#: templates/oath/totp_profile.html:19 -msgid "" -"This kind of authentication is actually not possible, because you do not " -"have any secret setup." -msgstr "" -"Ce moyen d'authentification n'est pas disponible actuellement car vous " -"n'avez pas encore généré de secret." - -#: templates/oath/totp_profile.html:23 -msgid "Generate a new credential" -msgstr "Générer un nouveau secret" diff --git a/authentic2/auth2_auth/auth2_oath/migrations/0001_initial.py b/authentic2/auth2_auth/auth2_oath/migrations/0001_initial.py deleted file mode 100644 index 9948e9bcd..000000000 --- a/authentic2/auth2_auth/auth2_oath/migrations/0001_initial.py +++ /dev/null @@ -1,39 +0,0 @@ -# encoding: utf-8 -from south.db import db -from south.v2 import SchemaMigration - - -from authentic.compat import user_model_label - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'OATHTOTPSecret' - db.create_table('auth2_oath_oathtotpsecret', ( - ('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='oath_totp_secret', unique=True, primary_key=True, to=orm[user_model_label])), - ('key', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('drift', self.gf('django.db.models.fields.IntegerField')(default=0, max_length=4)), - )) - db.send_create_signal('auth2_oath', ['OATHTOTPSecret']) - - - def backwards(self, orm): - # Deleting model 'OATHTOTPSecret' - db.delete_table('auth2_oath_oathtotpsecret') - - - models = { - user_model_label: { - 'Meta': {'object_name': user_model_label.split('.')[-1]}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - }, - 'auth2_oath.oathtotpsecret': { - 'Meta': {'object_name': 'OATHTOTPSecret'}, - 'drift': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4'}), - 'key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), - 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oath_totp_secret'", 'unique': 'True', 'primary_key': 'True', 'to': "orm['%s']" % user_model_label}) - }, - } - - complete_apps = ['auth2_oath'] diff --git a/authentic2/auth2_auth/auth2_oath/migrations/__init__.py b/authentic2/auth2_auth/auth2_oath/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/authentic2/auth2_auth/auth2_oath/models.py b/authentic2/auth2_auth/auth2_oath/models.py deleted file mode 100644 index 0d314c2a4..000000000 --- a/authentic2/auth2_auth/auth2_oath/models.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.db import models -from django.conf import settings - -class OATHTOTPSecret(models.Model): - user = models.OneToOneField(getattr(settings, 'AUTH_USER_MODEL', 'auth.User'), - primary_key= True, related_name='oath_totp_secret') - # 20 bytes string as hexadecimal - key = models.CharField(max_length=40) - drift = models.IntegerField(default=0,max_length=4) diff --git a/authentic2/auth2_auth/auth2_oath/templates/auth/login_form_oath.html b/authentic2/auth2_auth/auth2_oath/templates/auth/login_form_oath.html deleted file mode 100644 index 6fdc717b8..000000000 --- a/authentic2/auth2_auth/auth2_oath/templates/auth/login_form_oath.html +++ /dev/null @@ -1,28 +0,0 @@ -{% load i18n %} -
- -

-{% blocktrans %} -Once you have created your account, log in with an other authentication method. -Then, in account management, follow the instructions to deploy the -One Time password authentication method. -{% endblocktrans %} -

- -
-
-{% csrf_token %} -{{ form.as_p }} - -{% if cancel %} - -{% endif %} -
-
- - - -
diff --git a/authentic2/auth2_auth/auth2_oath/templates/oath/totp_profile.html b/authentic2/auth2_auth/auth2_oath/templates/oath/totp_profile.html deleted file mode 100644 index b6c33235c..000000000 --- a/authentic2/auth2_auth/auth2_oath/templates/oath/totp_profile.html +++ /dev/null @@ -1,32 +0,0 @@ -{% load i18n %} - - - -

{% trans "Time based one-time password" %}

-
- {% if key %} -

{% trans "Secret" %}: {{ key }}

- {% if google_authenticator %} -

{% trans "Google authenticator" %}:

{{ google_authenticator|safe }}

- {% endif %} -

{% trans "Bookmarklet" %} -

{% trans "Copy this link to your bookmarks. When clicking on it it will generate a new one-time password which will allow you to login" %}

-

- {% csrf_token %} - -

- {% else %} -

{% trans "This kind of authentication is actually not possible, because you do not have any secret setup." %}

- {% endif %} -

-
- diff --git a/authentic2/auth2_auth/auth2_oath/urls.py b/authentic2/auth2_auth/auth2_oath/urls.py deleted file mode 100644 index 2a564b58f..000000000 --- a/authentic2/auth2_auth/auth2_oath/urls.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.conf.urls import patterns -import views - -urlpatterns = patterns('', - (r'^new_totp_secret$', views.new_totp_secret), - (r'^delete_totp_secret$', views.delete_totp_secret)) diff --git a/authentic2/auth2_auth/auth2_oath/views.py b/authentic2/auth2_auth/auth2_oath/views.py deleted file mode 100644 index 082fd103c..000000000 --- a/authentic2/auth2_auth/auth2_oath/views.py +++ /dev/null @@ -1,58 +0,0 @@ -import urllib -import random -import base64 - -from django.http import HttpResponseBadRequest, HttpResponseRedirect -from django.template import RequestContext -from django.template.loader import render_to_string - -import models -import authentic2.vendor.totp_js.totp_bookmarklet as totp_bookmarklet - -_hexachars = '0123456789abcdef' - -def new_totp_secret(request, next_url='/'): - if request.user is None or not hasattr(request.user, '_meta') \ - or request.method != 'POST': - return HttpResponseBadRequest() - key = ''.join([random.choice(_hexachars) for x in range(40)]) - secret, _ = models.OATHTOTPSecret.objects.get_or_create(user=request.user) - secret.key = key - secret.save() - next_url = request.REQUEST.get('next', next_url) - return HttpResponseRedirect(next_url) - -def delete_totp_secret(request, next_url='/'): - if request.user is None or not hasattr(request.user, '_meta') \ - or request.method != 'POST': - return HttpResponseBadRequest() - try: - models.OATHTOTPSecret.objects.filter(user=request.user).delete() - except models.OATHTOTPSecret.DoesNotExist: - pass - next_url = request.REQUEST.get('next', next_url) - return HttpResponseRedirect(next_url) - -def totp_profile(request, next_url='', template_name='oath/totp_profile.html'): - if request.user is None or not hasattr(request.user, '_meta'): - return '' - if next_url: - next_url = '?next=%s' % urllib.quote(next_url) - google_authenticator, key, bookmarklet = '', '', '' - try: - secret = models.OATHTOTPSecret.objects.get(user=request.user) - key = secret.key - bookmarklet = totp_bookmarklet.otp_doc(secret.key) - google_authenticator = 'otpauth://totp/%(user)s@localhost?secret=%(b32_secret)s' % \ - { 'user': request.user.username, - 'domain': request.get_host(), - 'b32_secret': base64.b32encode(key.decode('hex')) } - except models.OATHTOTPSecret.DoesNotExist: - pass - return render_to_string(template_name, - { 'key': key, - 'bookmarklet': bookmarklet, - 'google_authenticator': google_authenticator, - 'next': next_url, - 'base': '/oath'}, - RequestContext(request)) diff --git a/authentic2/idp/saml/saml2_endpoints.py b/authentic2/idp/saml/saml2_endpoints.py index a750605f9..093b62ea1 100644 --- a/authentic2/idp/saml/saml2_endpoints.py +++ b/authentic2/idp/saml/saml2_endpoints.py @@ -260,9 +260,6 @@ def build_assertion(request, login, nid_format='transient', attributes=None): elif backend == \ 'authentic2.authsaml2.backends.AuthSAML2TransientBackend': authn_context = lasso.SAML2_AUTHN_CONTEXT_UNSPECIFIED - elif backend == \ - 'authentic2.auth2_auth.auth2_oath.backend.OATHTOTPBackend': - authn_context = lasso.SAML2_AUTHN_CONTEXT_TIME_SYNC_TOKEN else: backend = load_backend(backend) if hasattr(backend, 'get_saml2_authn_context'): diff --git a/authentic2/settings.py b/authentic2/settings.py index c580fa37b..13e10efdb 100644 --- a/authentic2/settings.py +++ b/authentic2/settings.py @@ -317,7 +317,6 @@ ADMIN_TOOLS_MENU = 'authentic2.menu.CustomMenu' AUTH_SAML2 = 'AUTH_SAML2' in os.environ AUTH_OPENID = 'AUTH_OPENID' in os.environ AUTH_SSL = 'AUTH_SSL' in os.environ -AUTH_OATH = 'AUTH_OATH' in os.environ IDP_SAML2 = 'IDP_SAML2' in os.environ IDP_OPENID = 'IDP_OPENID' in os.environ IDP_CAS = 'IDP_CAS' in os.environ @@ -354,11 +353,6 @@ if AUTH_SSL: AUTH_FRONTENDS += ('authentic2.auth2_auth.auth2_ssl.frontend.SSLFrontend',) INSTALLED_APPS += ('authentic2.auth2_auth.auth2_ssl',) -if AUTH_OATH: - INSTALLED_APPS += ('authentic2.auth2_auth.auth2_oath',) - AUTHENTICATION_BACKENDS += ('authentic2.auth2_auth.auth2_oath.backend.OATHTOTPBackend',) - AUTH_FRONTENDS += ('authentic2.auth2_auth.auth2_oath.frontend.OATHOTPFrontend',) - if IDP_SAML2: IDP_BACKENDS += ('authentic2.idp.saml.backend.SamlBackend',) diff --git a/authentic2/urls.py b/authentic2/urls.py index aebcbd0cb..45ee94d03 100644 --- a/authentic2/urls.py +++ b/authentic2/urls.py @@ -41,10 +41,6 @@ if getattr(settings, 'IDP_OPENID', False): urlpatterns += patterns('', (r'^openid/', include('authentic2.idp.idp_openid.urls'))) -if 'authentic2.auth2_auth.auth2_oath' in settings.INSTALLED_APPS: - urlpatterns += patterns('', - (r'^oath/', include('authentic2.auth2_auth.auth2_oath.urls'))) - try: if settings.DISCO_SERVICE: urlpatterns += patterns('', diff --git a/authentic2/vendor/oath/TODO b/authentic2/vendor/oath/TODO deleted file mode 100644 index 2e2b1c6b7..000000000 --- a/authentic2/vendor/oath/TODO +++ /dev/null @@ -1,3 +0,0 @@ -- implement accept_hotp -- add truncation functions for hashing algorithm with a larger output like SHA2 - variant. diff --git a/authentic2/vendor/oath/__init__.py b/authentic2/vendor/oath/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/authentic2/vendor/oath/hotp.py b/authentic2/vendor/oath/hotp.py deleted file mode 100644 index d0bdde062..000000000 --- a/authentic2/vendor/oath/hotp.py +++ /dev/null @@ -1,133 +0,0 @@ -import hashlib -import hmac -import binascii -import time -import datetime -import calendar - -''' -Python implementation of HOTP and TOTP algorithms from the OATH project. - -Copyright 2010, Benjamin Dauvergne - -* All rights reserved. -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution.''' - -def __truncated_value(h): - bytes = map(ord, h) - offset = bytes[19] & 0xf - v = (bytes[offset] & 0x7f) << 24 | (bytes[offset+1] & 0xff) << 16 | \ - (bytes[offset+2] & 0xff) << 8 | (bytes[offset+3] & 0xff) - return v - -def dec(h,p): - v = str(__truncated_value(h)) - return v[len(v)-p:] - -def __hotp(key, counter, hash=hashlib.sha1): - hex_counter = hex(long(counter))[2:-1] - hex_counter = '0' * (16 - len(hex_counter)) + hex_counter - bin_counter = binascii.unhexlify(hex_counter) - bin_key = binascii.unhexlify(key) - - return hmac.new(bin_key, bin_counter, hash).digest() - -def hotp(key,counter,format='dec6',hash=hashlib.sha1): - '''Compute a HOTP value as prescribed by RFC4226 - - See http://tools.ietf.org/html/rfc4226 - ''' - bin_hotp = __hotp(key, counter, hash) - - if format == 'hex40': - return binascii.hexlify(bin_hotp[0:5]) - elif format == 'dec6': - return dec(bin_hotp, 6) - elif format == 'dec7': - return dec(bin_hotp, 7) - elif format == 'dec8': - return dec(bin_hotp, 8) - else: - raise ValueError('unknown format') - -def totp(key, format='dec8', period=30, t=None, hash=hashlib.sha1): - '''Compute a TOTP value as prescribed by OATH specifications. - - See http://tools.ietf.org/html/draft-mraihi-totp-timebased-06 - ''' - if t is None: - t = time.time() - else: - if isinstance(t, datetime.datetime): - t = calendar.timegm(t.utctimetuple()) - else: - t = int(t) - T = int(t/period) - return hotp(key, T, format=format, hash=hash) - -def accept_totp(key, response, period=30, format='dec8', hash=hashlib.sha1, - forward_drift=1, backward_drift=1, drift=0, t=None): - '''Validate a TOTP value inside a window of - [drift-bacward_drift:drift+forward_drift] of time steps. - Where drift is the drift obtained during the last call to accept_totp. - - Return a pair (v,d) where v is a boolean giving the result, and d the - needed drift to validate the value. The drift value should be saved for - user with later call to accept_totp in order to accept a slowly - accumulating drift with a token clock. - ''' - t = t or time.time() - for i in range(-backward_drift,forward_drift+1): - d = (drift+i) * period - if totp(key, format=format, period=period, hash=hash, t=t+d) == response: - return True, drift+i - return False, 0 - -if __name__ == '__main__': - # Test vectors extracted from RFC 4226 - secret = '3132333435363738393031323334353637383930' - tvector = [ - (0, 'cc93cf18508d94934c64b65d8ba7667fb7cde4b0'), - (1, '75a48a19d4cbe100644e8ac1397eea747a2d33ab'), - (2, '0bacb7fa082fef30782211938bc1c5e70416ff44'), - (3, '66c28227d03a2d5529262ff016a1e6ef76557ece'), - (4, 'a904c900a64b35909874b33e61c5938a8e15ed1c'), - (5, 'a37e783d7b7233c083d4f62926c7a25f238d0316'), - (6, 'bc9cd28561042c83f219324d3c607256c03272ae'), - (7, 'a4fb960c0bc06e1eabb804e5b397cdc4b45596fa'), - (8, '1b3c89f65e6c9e883012052823443f048b4332db'), - (9, '1637409809a679dc698207310c8c7fc07290d9e5'), ] - for counter, value in tvector: - assert(binascii.hexlify(__hotp(secret, counter)) == value) - tvector2 = [ - (0, '4c93cf18', '1284755224', '755224',), - (1, '41397eea', '1094287082', '287082',), - (2, '82fef30', '137359152', '359152',), - (3, '66ef7655', '1726969429', '969429',), - (4, '61c5938a', '1640338314', '338314',), - (5, '33c083d4', '868254676', '254676',), - (6, '7256c032', '1918287922', '287922',), - (7, '4e5b397', '82162583', '162583',), - (8, '2823443f', '673399871', '399871',), - (9, '2679dc69', '645520489', '520489',),] - for counter, hexa, deci, trunc in tvector2: - h = __hotp(secret, counter) - v = __truncated_value(h) - assert(hex(v)[2:] == hexa) - assert(str(v) == deci) - assert(dec(h,6) == trunc) - secret = binascii.hexlify('12345678901234567890') - tvector3 = [ - (59, hashlib.sha1, '94287082'), - (1111111109, hashlib.sha1, '07081804') ] - for timestamp, hash, value in tvector3: - assert (totp(secret,t=datetime.datetime.utcfromtimestamp(timestamp),hash=hash) == value) - assert(accept_totp(secret, '94287082', t=65) == (True, -1)) - assert(accept_totp(secret, '94287082', t=65, drift=-1) == (True, -1)) diff --git a/authentic2/vendor/totp_js/README.rst b/authentic2/vendor/totp_js/README.rst deleted file mode 100644 index 99721322e..000000000 --- a/authentic2/vendor/totp_js/README.rst +++ /dev/null @@ -1,8 +0,0 @@ -Simple data document generator containing a TOTP soft token -=========================================================== - -To use it from your python application just do: - - import totp_bookmarklet - - html_fragment = 'OTP Bookmarklet' % totp_bookmarklet.otp_doc('my_secret') diff --git a/authentic2/vendor/totp_js/__init__.py b/authentic2/vendor/totp_js/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/authentic2/vendor/totp_js/js/crypto.js b/authentic2/vendor/totp_js/js/crypto.js deleted file mode 100644 index f0c2e5655..000000000 --- a/authentic2/vendor/totp_js/js/crypto.js +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Crypto-JS v2.0.X - * http://code.google.com/p/crypto-js/ - * Copyright (c) 2009, Jeff Mott. All rights reserved. - * http://code.google.com/p/crypto-js/wiki/License - */ -if(typeof Crypto=="undefined"||!Crypto.util){(function(){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var d=window.Crypto={};var a=d.util={rotl:function(h,g){return(h<>>(32-g))},rotr:function(h,g){return(h<<(32-g))|(h>>>g)},endian:function(h){if(h.constructor==Number){return a.rotl(h,8)&16711935|a.rotl(h,24)&4278255360}for(var g=0;g0;h--){g.push(Math.floor(Math.random()*256))}return g},bytesToWords:function(h){for(var k=[],j=0,g=0;j>>5]|=h[j]<<(24-g%32)}return k},wordsToBytes:function(i){for(var h=[],g=0;g>>5]>>>(24-g%32))&255)}return h},bytesToHex:function(g){for(var j=[],h=0;h>>4).toString(16));j.push((g[h]&15).toString(16))}return j.join("")},hexToBytes:function(h){for(var g=[],i=0;i>>6*(3-k))&63))}else{g.push("=")}}}return g.join("")},base64ToBytes:function(h){if(typeof atob=="function"){return e.stringToBytes(atob(h))}h=h.replace(/[^A-Z0-9+\/]/ig,"");for(var g=[],j=0,k=0;j>>(6-k*2)))}return g}};d.mode={};var b=d.charenc={};var f=b.UTF8={stringToBytes:function(g){return e.stringToBytes(unescape(encodeURIComponent(g)))},bytesToString:function(g){return decodeURIComponent(escape(e.bytesToString(g)))}};var e=b.Binary={stringToBytes:function(j){for(var g=[],h=0;h>5]|=128<<(24-x%32);v[((x+64>>>9)<<4)+15]=x;for(var z=0;z>>31)}var s=((r<<5)|(r>>>27))+g+(p[y]>>>0)+(y<20?(q&k|~q&h)+1518500249:y<40?(q^k^h)+1859775393:y<60?(q&k|q&h|k&h)-1894007588:(q^k^h)-899497514);g=h;h=k;k=(q<<30)|(q>>>2);q=r;r=s}r+=E;q+=D;k+=C;h+=B;g+=A}return[r,q,k,h,g]};c._blocksize=16})();(function(){var e=Crypto,a=e.util,b=e.charenc,d=b.UTF8,c=b.Binary;e.HMAC=function(l,m,k,h){if(m.constructor==String){m=d.stringToBytes(m)}if(k.constructor==String){k=d.stringToBytes(k)}if(k.length>l._blocksize*4){k=l(k,{asBytes:true})}var g=k.slice(0),n=k.slice(0);for(var j=0;j>>16)^(i[3]<<16);r[1]=i[2]^(i[7]>>>16)^(i[5]<<16);r[2]=i[4]^(i[1]>>>16)^(i[7]<<16);r[3]=i[6]^(i[3]>>>16)^(i[1]<<16);for(var o=0;o<4;o++){r[o]=((r[o]<<8)|(r[o]>>>24))&16711935|((r[o]<<24)|(r[o]>>>8))&4278255360}for(var c=120;c>=0;c-=8){r[c/8]=(r[c>>>5]>>>(24-c%32))&255}}l[q]^=r[q%16]}},_keysetup:function(b){i[0]=b[0];i[2]=b[1];i[4]=b[2];i[6]=b[3];i[1]=(b[3]<<16)|(b[2]>>>16);i[3]=(b[0]<<16)|(b[3]>>>16);i[5]=(b[1]<<16)|(b[0]>>>16);i[7]=(b[2]<<16)|(b[1]>>>16);g[0]=f.rotl(b[2],16);g[2]=f.rotl(b[3],16);g[4]=f.rotl(b[0],16);g[6]=f.rotl(b[1],16);g[1]=(b[0]&4294901760)|(b[1]&65535);g[3]=(b[1]&4294901760)|(b[2]&65535);g[5]=(b[2]&4294901760)|(b[3]&65535);g[7]=(b[3]&4294901760)|(b[0]&65535);h=0;for(var c=0;c<4;c++){k._nextstate()}for(var c=0;c<8;c++){g[c]^=i[(c+4)&7]}},_ivsetup:function(b){var o=f.endian(b[0]),m=f.endian(b[1]),n=(o>>>16)|(m&4294901760),l=(m<<16)|(o&65535);g[0]^=o;g[1]^=n;g[2]^=m;g[3]^=l;g[4]^=o;g[5]^=n;g[6]^=m;g[7]^=l;for(var c=0;c<4;c++){k._nextstate()}},_nextstate:function(){for(var c=[],l=0;l<8;l++){c[l]=g[l]}g[0]=(g[0]+1295307597+h)>>>0;g[1]=(g[1]+3545052371+((g[0]>>>0)<(c[0]>>>0)?1:0))>>>0;g[2]=(g[2]+886263092+((g[1]>>>0)<(c[1]>>>0)?1:0))>>>0;g[3]=(g[3]+1295307597+((g[2]>>>0)<(c[2]>>>0)?1:0))>>>0;g[4]=(g[4]+3545052371+((g[3]>>>0)<(c[3]>>>0)?1:0))>>>0;g[5]=(g[5]+886263092+((g[4]>>>0)<(c[4]>>>0)?1:0))>>>0;g[6]=(g[6]+1295307597+((g[5]>>>0)<(c[5]>>>0)?1:0))>>>0;g[7]=(g[7]+3545052371+((g[6]>>>0)<(c[6]>>>0)?1:0))>>>0;h=(g[7]>>>0)<(c[7]>>>0)?1:0;for(var m=[],l=0;l<8;l++){var o=(i[l]+g[l])>>>0;var q=o&65535,n=o>>>16;var b=((((q*q)>>>17)+q*n)>>>15)+n*n,p=(((o&4294901760)*o)>>>0)+(((o&65535)*o)>>>0)>>>0;m[l]=b^p}i[0]=m[0]+((m[7]<<16)|(m[7]>>>16))+((m[6]<<16)|(m[6]>>>16));i[1]=m[1]+((m[0]<<8)|(m[0]>>>24))+m[7];i[2]=m[2]+((m[1]<<16)|(m[1]>>>16))+((m[0]<<16)|(m[0]>>>16));i[3]=m[3]+((m[2]<<8)|(m[2]>>>24))+m[1];i[4]=m[4]+((m[3]<<16)|(m[3]>>>16))+((m[2]<<16)|(m[2]>>>16));i[5]=m[5]+((m[4]<<8)|(m[4]>>>24))+m[3];i[6]=m[6]+((m[5]<<16)|(m[5]>>>16))+((m[4]<<16)|(m[4]>>>16));i[7]=m[7]+((m[6]<<8)|(m[6]>>>24))+m[5]}}})(); \ No newline at end of file diff --git a/authentic2/vendor/totp_js/js/hotp.js b/authentic2/vendor/totp_js/js/hotp.js deleted file mode 100644 index 6d0251e8f..000000000 --- a/authentic2/vendor/totp_js/js/hotp.js +++ /dev/null @@ -1,110 +0,0 @@ -/* - A simple Javascript HOTP implementation (HMAC-Based One-Time Password Algorithm) as described in RFC 4226. - - The library is relying on crypto-js (http://code.google.com/p/crypto-js/) for the javascript HMAC-SHA1 implementation. - - The library can be used to create software token (don't forget to protect the key of the token...). - - If you want to use the library, you'll need to load the crypto-js (sha1 and hmac) and hotp.js. - - Calling the library is easy, you just have to set the hex key of the token, the counter plus the output format. - - otp = hotp("3132333435363738393031323334353637383930","4","dec6"); - - Current output formats are : hex40 (format used by ootp, a free software library) and dec6 (the 6 decimal digit as described in the RFC 4226). - - A demo page with the test vector of the RFC 4226 : http://www.foo.be/hotp/example.html* - - http://www.gitorious.org/hotp-js/ - - Copyright (C) 2009 Alexandre Dulaunoy - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -*/ - -function hotp(key, counter, format) { - - function hotp_hexkeytobytestream(s) { - // s is the key to be converted in bytes - var b = new Array(); - var last = s.length; - for (var i = 0; i < last; i = i + 2) { - var x = s[i] + s[i + 1]; - x.toUpperCase(); - x = "0x" + x; - x = parseInt(x); - b[i] = String.fromCharCode(x); - } - var ret = new String(); - ret = b.join(''); - return ret; - - } - function hotp_movingfactortohex(count) { - // count is the moving factor in OTP to be converted in bytes - v = decimaltohex(count, 16); - var decb = new Array(); - lhex = Crypto.util.hexToBytes(v); - for (var i = 0; i < lhex.length; i++) { - decb[i] = String.fromCharCode(lhex[i]); - } - var retval = new String(); - retval = decb.join(''); - return retval; - } - - function decimaltohex(d, padding) { - // d is the decimal value - // padding is the padding to apply (O pad) - var hex = Number(d).toString(16); - padding = typeof(padding) === "undefined" || padding === null ? padding = 2 : padding; - while (hex.length < padding) { - hex = "0" + hex; - } - return hex; - } - - function truncatedvalue(h, p) { - // h is the hash value - // p is precision - offset = h[19] & 0xf; - v = (h[offset] & 0x7f) << 24 | (h[offset + 1] & 0xff) << 16 | (h[offset + 2] & 0xff) << 8 | (h[offset + 3] & 0xff); - v = "" + v; - v = v.substr(v.length - p, p); - return v; - } - - var hmacBytes = Crypto.HMAC(Crypto.SHA1, Crypto.charenc.Binary.stringToBytes((hotp_movingfactortohex(counter))), Crypto.charenc.Binary.stringToBytes(hotp_hexkeytobytestream(key))); - - if (format == "hex40") { - return hmacBytes.substring(0, 10); - } else if (format == "dec6") { - return truncatedvalue(Crypto.util.hexToBytes(hmacBytes), 6); - } else if (format == "dec7") { - return truncatedvalue(Crypto.util.hexToBytes(hmacBytes), 7); - } else if (format == "dec8") { - return truncatedvalue(Crypto.util.hexToBytes(hmacBytes), 8); - } - else { - return "unknown format"; - } - -} - -function totp(key,format) { - var T = parseInt(new Date().getTime()/30000); - return hotp(key,T,format); -} - diff --git a/authentic2/vendor/totp_js/js/my-otp.js b/authentic2/vendor/totp_js/js/my-otp.js deleted file mode 100644 index a6f2c9807..000000000 --- a/authentic2/vendor/totp_js/js/my-otp.js +++ /dev/null @@ -1,5 +0,0 @@ -function otp() { - var key = 'FAFA'; - alert('Code: ' + totp(key, 'MODE')); -}; -otp(); diff --git a/authentic2/vendor/totp_js/totp_bookmarklet.py b/authentic2/vendor/totp_js/totp_bookmarklet.py deleted file mode 100644 index d4c5715a0..000000000 --- a/authentic2/vendor/totp_js/totp_bookmarklet.py +++ /dev/null @@ -1,30 +0,0 @@ -import binascii -import base64 -import os.path - -def __content(f): - return open(os.path.join(os.path.dirname(__file__), f)).read() - -crypto_js = __content('js/crypto.js') -hotp_js = __content('js/hotp.js') -myotp_js = __content('js/my-otp.js') - - -def dataize(document, type='text/html'): - return 'data:%s;base64,%s' % (type, base64.b64encode(document)) - -def otp_doc(key,mode='dec6'): - '''Convert an hexadecimal key to a document able to produce TOTP keys using - the dec6 mode - ''' - doc = '''' - - - -''' % (crypto_js + ';' + hotp_js + ';' + \ - myotp_js.replace('FAFA',key).replace('MODE',mode)) - return dataize(doc) - -if __name__ == '__main__': - import sys - print '''OTP Password''' % otp_doc(sys.argv[1])