From 8a4fda127db7c4630f1a44330616f75f5760ae5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Grou=C3=A8s?= <valentin.groues@uni.lu> Date: Mon, 10 Jul 2017 09:20:38 +0200 Subject: [PATCH] add token verification via sms --- readme.md | 7 ++++++ requirements.txt | 1 + smash/smash/local_settings.py.template | 4 +++ smash/web/nexmo_gateway.py | 34 ++++++++++++++++++++++++++ smash/web/views/__init__.py | 4 +-- smash/web/views/auth.py | 9 ++++--- 6 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 smash/web/nexmo_gateway.py diff --git a/readme.md b/readme.md index ccf5b24c..22d11dd3 100644 --- a/readme.md +++ b/readme.md @@ -187,6 +187,13 @@ SHELL=/bin/bash ## Operations +### Disable two steps authentication for a specific user + + +``` +./manage.py two_factor_disable ${USERNAME} +``` + ### Public holidays to import public holidays run: diff --git a/requirements.txt b/requirements.txt index 42af6653..e7d3b4c1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ python-docx==0.8.6 django-cleanup==0.4.2 django_cron==0.5.0 django-two-factor-auth==1.6.1 +nexmo==2.0.0-alpha1 \ No newline at end of file diff --git a/smash/smash/local_settings.py.template b/smash/smash/local_settings.py.template index a2411b28..bb8abb8c 100644 --- a/smash/smash/local_settings.py.template +++ b/smash/smash/local_settings.py.template @@ -39,3 +39,7 @@ STATIC_ROOT = '/tmp/static' # Warning! `/tmp` directory can be flushed in any m MEDIA_ROOT = '/tmp/media' # Warning! `/tmp` directory can be flushed in any moment; use a persistent one, e.g. ~/tmp/media STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' + +NEXMO_API_KEY = 'API_KEY' +NEXMO_API_SECRET = 'API_SECRET' +NEXMO_DEFAULT_FROM = 'Scheduling' # the sender of the message (phone number or text) diff --git a/smash/web/nexmo_gateway.py b/smash/web/nexmo_gateway.py new file mode 100644 index 00000000..0515c732 --- /dev/null +++ b/smash/web/nexmo_gateway.py @@ -0,0 +1,34 @@ +import nexmo +from django.conf import settings + + +class Nexmo: + """ + Gateway for sending text messages and making phone calls using Nexmo_. + + All you need is your Nexmo Account API and Secret, as shown in your Nexmo + account dashboard. + + ``NEXMO_API_KEY`` + Should be set to your account's API Key. + + ``NEXMO_API_SECRET`` + Should be set to your account's secret. + + ``NEXMO_DEFAULT_FROM`` + Should be set to a phone number or name. + + .. _Nexmo: http://www.nexmo.com/ + """ + + def __init__(self): + self.client = nexmo.Client(key=getattr(settings, 'NEXMO_API_KEY'), secret=getattr(settings, 'NEXMO_API_SECRET')) + self.default_from = getattr(settings, 'NEXMO_DEFAULT_FROM') + + def make_call(self, device, token): + pass + + def send_sms(self, device, token): + body = 'Your authentication token is %s' % token + phone_number = device.number.as_e164 + self.client.send_message({'to': phone_number, 'from': self.default_from, 'text': body}) diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py index 4322cb37..49fc1dce 100644 --- a/smash/web/views/__init__.py +++ b/smash/web/views/__init__.py @@ -1,5 +1,5 @@ # coding=utf-8 - +from django.conf import settings from django.contrib.auth.decorators import login_required from django.shortcuts import redirect, render from django.views.generic.base import ContextMixin @@ -16,7 +16,7 @@ handler400 = 'web.views.e400_bad_request' def index(request): if request.user.is_authenticated(): return redirect('web.views.appointments') - return redirect('web.views.login') + return redirect(getattr(settings, "LOGIN_URL")) def e404_page_not_found(request, context=None): diff --git a/smash/web/views/auth.py b/smash/web/views/auth.py index 2e095773..1a293f4a 100644 --- a/smash/web/views/auth.py +++ b/smash/web/views/auth.py @@ -1,8 +1,11 @@ # coding=utf-8 +from django.conf import settings from django.shortcuts import redirect, render from ..auth import do_login, do_logout +login_url = getattr(settings, "LOGIN_URL") + def login(request): context = { @@ -22,9 +25,9 @@ def login(request): # FIXME: risk of phishing attacks # see https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet else: - return redirect('web.views.appointments') + return redirect(login_url) else: - response = redirect('web.views.login') + response = redirect(login_url) response['Location'] += "?error={}".format(message) return response return render(request, "login.html", context) @@ -32,6 +35,6 @@ def login(request): def logout(request): state, message = do_logout(request) - response = redirect('web.views.login') + response = redirect(login_url) response['Location'] += "?error={}".format(message) return response -- GitLab