From c4079a1c1d7d89fbeb036c6cda3259d24cdecd19 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 2 May 2019 04:10:06 -0400 Subject: [PATCH 01/17] request the username in login instead of the email --- dal/forms.py | 14 +++++++------- dal/views.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dal/forms.py b/dal/forms.py index d4bc028..0968601 100644 --- a/dal/forms.py +++ b/dal/forms.py @@ -4,18 +4,18 @@ from django.utils.translation import ugettext_lazy as _ class LoginForm(forms.Form): - email = forms.CharField(widget=forms.TextInput()) + username = forms.CharField(widget=forms.TextInput()) password = forms.CharField(widget=forms.PasswordInput()) class Meta: - fields = ['email', 'password'] + fields = ['username', 'password'] def clean(self): - email = self.cleaned_data.get('email') + username = self.cleaned_data.get('username') password = self.cleaned_data.get('password') if self.errors: return self.cleaned_data - is_auth = authenticate(username=email, password=password) + is_auth = authenticate(username=username, password=password) if not is_auth: raise forms.ValidationError( _("Your username and/or password were incorrect.") @@ -26,6 +26,6 @@ class LoginForm(forms.Form): # ) return self.cleaned_data - def clean_email(self): - email = self.cleaned_data.get('email') - return email + def clean_username(self): + username = self.cleaned_data.get('username') + return username diff --git a/dal/views.py b/dal/views.py index eb5e5de..3f04ca2 100644 --- a/dal/views.py +++ b/dal/views.py @@ -37,9 +37,9 @@ class Index(FormView): success_url = 'useroptions.html' def form_valid(self, form): - email = form.cleaned_data.get('email') + username = form.cleaned_data.get('username') password = form.cleaned_data.get('password') - user = authenticate(username=email, password=password) + user = authenticate(username=username, password=password) if user is not None: login(self.request, user) return render(self.request, 'useroptions.html', { 'user': user } ) From d07ff15f69da1ced383ce96f22568f988e217af0 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 2 May 2019 17:29:01 -0400 Subject: [PATCH 02/17] Add validation email before creation --- dal/templates/confirm_email.html | 29 ++++++ dal/urls.py | 4 +- dal/views.py | 171 +++++++++++++++++++++---------- 3 files changed, 151 insertions(+), 53 deletions(-) create mode 100644 dal/templates/confirm_email.html diff --git a/dal/templates/confirm_email.html b/dal/templates/confirm_email.html new file mode 100644 index 0000000..729af28 --- /dev/null +++ b/dal/templates/confirm_email.html @@ -0,0 +1,29 @@ +{% extends "base_short.html" %} +{% load i18n staticfiles bootstrap3 %} + +{% block title %} + Verify your email. +{% endblock %} + + + +{% block content %} +
+
+
+
+
+

{% trans " Check your email " %}

+

{% trans "In order to complete the sign up process, please check your email and follow the activation instructions." %}

+
+
+ +
+
+
+
+
+
+{% endblock %} diff --git a/dal/urls.py b/dal/urls.py index 1dab47a..394a8ba 100644 --- a/dal/urls.py +++ b/dal/urls.py @@ -13,7 +13,8 @@ from .views import ( Index, LogOut, ResetRequest, - UserCreateAPI + UserCreateAPI, + ActivateAccount ) urlpatterns = [ @@ -26,6 +27,7 @@ urlpatterns = [ path('index/', Index.as_view(), name="index"), path('logout/', LogOut.as_view(), name="logout"), path('reset///', ResetRequest.as_view()), + path('activate///////', ActivateAccount.as_view()), path('reset/', ResetRequest.as_view(), name="reset"), path('', Index.as_view(), name="login_index"), ] \ No newline at end of file diff --git a/dal/views.py b/dal/views.py index 3f04ca2..568207a 100644 --- a/dal/views.py +++ b/dal/views.py @@ -31,6 +31,47 @@ from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin +def activate_account_link(base_url, user, pwd, firstname, lastname, email, epochutc): + tokengen = PasswordResetTokenGenerator() + pseudouser = PseudoUser() + token = tokengen.make_token(pseudouser) + buser = bytes(user, 'utf-8') + bpwd = bytes(pwd, 'utf-8') + bfirstname = bytes(firstname, 'utf-8') + blasttname = bytes(lastname, 'utf-8') + bemail = bytes(email, 'utf-8') + userpart = b64encode(buser) + pwdpart = b64encode(bpwd) + fnpart = b64encode(bfirstname) + lnpart = b64encode(blasttname) + mailpart = b64encode(bemail) + # create entry into the database + newdbentry = ResetToken(user=user, token=token, creation=epochutc) + newdbentry.save() + # set up the link + link = "{base_url}/activate/{user}/{pwd}/{fn}/{ln}/{mail}/(token)/".format( + base_url=base_url, user=userpart.decode('utf-8'), + pwd=pwdpart.decode('utf-8'), + fn=fnpart.decode('utf-8'), + ln=lnpart.decode('utf-8'), + mail=mailpart.decode('utf-8'), + token=token + ) + return link + + +def clean_db(): + """Revoves outdated tokens""" + # cutoff time is set to 24h hours + # using utcnow() to have no headache with timezones + cutoff = int(datetime.utcnow().timestamp()) - (24*60*60) + # Get all tokens older than 24 hours + oldtokens = ResetToken.objects.all().filter(creation__lt=cutoff) + for token in oldtokens: + # delete all tokens older than 24 hours + token.delete() + return True + class Index(FormView): template_name = "landing.html" form_class = LoginForm @@ -92,34 +133,30 @@ class Register(View): pwd = r'%s' % password1 try: - ldap_manager = LdapManager() - ldap_manager.create_user( - username, pwd, firstname, lastname, email + creationtime = int(datetime.utcnow().timestamp()) + base_url = "{0}://{1}".format(self.request.scheme, + self.request.get_host()) + link = activate_account_link(base_url, username, pwd, firstname, lastname, email, creationtime) + email_from = settings.EMAIL_FROM_ADDRESS + to = ['%s <%s>' % (username, email)] + subject = 'Activate your ungleich account'.format(firstname) + body = 'You can activate your ungleich account account by clicking here.' \ + ' You can also copy and paste the following link into the address bar of your browser and follow' \ + ' the link in order to activate your account.\n\n{link}'.format(link=link) + # Build the email + mail = EmailMessage( + subject=subject, + body=body, + from_email=email_from, + to=to ) + mail.send() + except Exception as e: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': e } ) - # Finally, we send the send user credentials via email - creationtime = int(datetime.utcnow().timestamp()) - # Construct the data for the email - email_from = settings.EMAIL_FROM_ADDRESS - to = ['%s <%s>' % (username, email)] - subject = '{}, Welcome to datacenterlight'.format(firstname) - body = 'The username {} was successfully created.\n'.format(username) - # Build the email - mail = EmailMessage( - subject=subject, - body=body, - from_email=email_from, - to=to - ) - try: - mail.send() - except Exception as e: - print(e) - pass - return render(request, 'usercreated.html', { 'user': username } ) + return render(request, 'confirm_email.html') class ChangeData(LoginRequiredMixin, View): login_url = reverse_lazy('login_index') @@ -297,7 +334,7 @@ class ResetRequest(View): # Cleans up outdated tokens # If we expect quite a bit of old tokens, maybe somewhere else is better, # but for now we don't really expect many unused tokens - self.clean_db() + clean_db() # If user and token are not supplied by django, it was called from somewhere else, so it's # invalid if user == None or token == None: @@ -336,10 +373,10 @@ class ResetRequest(View): if password1 == "" or not password1 or password2 == "" or not password2: return render(request, 'error.html', { 'service': service, 'error': 'Please supply a password and confirm it.' } ) if password1 != password2: - return render(request, 'error.html', { 'service': service, 'error': 'The supplied passwords do not match.' } ) + return render(request, 'error.html', {'service': service, 'error': 'The supplied passwords do not match.'}) if len(password1) < 8: - return render(request, 'error.html', { 'service': service, 'error': 'The password is too short, please use a longer one. At least 8 characters.' } ) - # everything checks out, now change the password + return render(request, 'error.html', {'service': service, + 'error': 'The password is too short, please use a longer one. At least 8 characters.'}) ldap_manager = LdapManager() result = ldap_manager.change_password( @@ -353,17 +390,7 @@ class ResetRequest(View): else: return render(request, 'error.html', { 'service': service, 'error': result } ) - # Cleans up outdated tokens - def clean_db(self): - # cutoff time is set to 24h hours - # using utcnow() to have no headache with timezones - cutoff = int(datetime.utcnow().timestamp()) - (24*60*60) - # Get all tokens older than 24 hours - oldtokens = ResetToken.objects.all().filter(creation__lt=cutoff) - for token in oldtokens: - # delete all tokens older than 24 hours - token.delete() - return True + # The logged in user can change the password here @@ -488,6 +515,47 @@ class PseudoUser(): pk = ''.join(choice(string.ascii_letters + string.digits) for _ in range(20)) password = ''.join(choice(string.ascii_letters + string.digits) for _ in range(30)) + +class ActivateAccount(View): + + def get(self, request, user=None, pwd=None, firstname=None, lastname=None, email=None, token=None): + clean_db() + if token is None: + return HttpResponse('Invalid URL', status=404) + elem_list = [user, pwd, firstname, lastname, email] + clean_list = [] + for value in elem_list: + try: + value_temp = bytes(value, 'utf-8') + value_decode = b64decode(value_temp) + value_clean = value_decode.decode('utf-8') + clean_list.append(value_clean) + except Exception as e: + return HttpResponse('Invalid URL', status=404) + checks_out = False + dbentries = ResetToken.objects.all().filter(user=clean_list[0]) + for entry in dbentries: + if entry.token == token: + # found the token, now delete it since it's used + checks_out = True + entry.delete() + # No token was found + if not checks_out: + return HttpResponse('Invalid URL.', status=404) + # Token was found, create user + try: + ldap_manager = LdapManager() + ldap_manager.create_user( + clean_list[0], clean_list[1], clean_list[2], clean_list[3], clean_list[4] + ) + #Send welcome email + except Exception as e: + return render(request, 'error.html', {'urlname': 'register', + 'service': 'register an user', + 'error': e}) + return render(request, 'usercreated.html', { 'user': clean_list[0] } ) + + class UserCreateAPI(APIView): def post(self, request): @@ -508,25 +576,24 @@ class UserCreateAPI(APIView): pwd = r'%s' % User.objects.make_random_password() - try: - ldap_manager = LdapManager() - ldap_manager.create_user( - username, pwd, firstname, lastname, email - ) - except Exception as e: - return Response('While trying to create the user, an error was encountered: %s' % e, 400) - - # send user credentials via email + base_url = "{0}://{1}".format(self.request.scheme, + self.request.get_host()) creationtime = int(datetime.utcnow().timestamp()) + link = activate_account_link(base_url, username, pwd, firstname, lastname, email. creationtime) + # Construct the data for the email email_from = settings.EMAIL_FROM_ADDRESS to = ['%s <%s>' % (username, email)] - subject = 'Your datacenterlight credentials' - body = 'Your user was successfully created.\n' + subject = 'Ungleich account creation.' + body = 'A request has been sent to our servers to register you as a ungleich user.\n' + body += 'In order to complete the registration process you must ' \ + 'click here or copy & paste the following link into the address bar of ' \ + 'your browser.\n{link}\n'.format(link=link) body += 'Your credentials are:\n' body += 'Username: %s\n\n' % username body += 'Password: %s\n\n' % pwd - body += 'We strongly recommend you to after log in change your password.\n' + body += 'We strongly recommend after the activation to log in and change your password.\n' + body += 'This link will remain active for 24 hours.\n' # Build the email mail = EmailMessage( subject=subject, @@ -537,5 +604,5 @@ class UserCreateAPI(APIView): try: mail.send() except: - return Response('User was created, but failed to send the email', 201) - return Response('User successfully created', 200) + return Response('Failed to send the email', 201) + return Response('Email with activation link successfully sent', 200) From 86a082c29fa9304742c27b87b6fcaf589db031ec Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 2 May 2019 17:36:31 -0400 Subject: [PATCH 03/17] Fix typho email verification --- dal/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dal/views.py b/dal/views.py index 568207a..f2d8b62 100644 --- a/dal/views.py +++ b/dal/views.py @@ -49,7 +49,7 @@ def activate_account_link(base_url, user, pwd, firstname, lastname, email, epoch newdbentry = ResetToken(user=user, token=token, creation=epochutc) newdbentry.save() # set up the link - link = "{base_url}/activate/{user}/{pwd}/{fn}/{ln}/{mail}/(token)/".format( + link = "{base_url}/activate/{user}/{pwd}/{fn}/{ln}/{mail}/{token}/".format( base_url=base_url, user=userpart.decode('utf-8'), pwd=pwdpart.decode('utf-8'), fn=fnpart.decode('utf-8'), From 503e31cc69d87a2fccc18ca0ffb61326538ee205 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 2 May 2019 21:24:54 -0400 Subject: [PATCH 04/17] fix user ldap creation from bytes to string --- dal/ungleich_ldap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py index 3ff81f5..1dedbc9 100644 --- a/dal/ungleich_ldap.py +++ b/dal/ungleich_ldap.py @@ -91,7 +91,7 @@ class LdapManager: logger.debug("{uid} does not exist. Using it".format(uid=uidNumber)) self._set_max_uid(uidNumber) try: - uid = user.encode("utf-8") + uid = user # user.encode("utf-8") conn.add("uid={uid},{customer_dn}".format( uid=uid, customer_dn=settings.LDAP_CUSTOMER_DN ), From 200699486ad03849eb5fc7a804ad04f26670b965 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 5 May 2019 16:44:02 -0400 Subject: [PATCH 05/17] rest interface for retrieve-create users seed --- dal/urls.py | 4 +++- dal/views.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/dal/urls.py b/dal/urls.py index 394a8ba..6142eab 100644 --- a/dal/urls.py +++ b/dal/urls.py @@ -14,7 +14,8 @@ from .views import ( LogOut, ResetRequest, UserCreateAPI, - ActivateAccount + ActivateAccount, + SeedRetrieveCreate ) urlpatterns = [ @@ -29,5 +30,6 @@ urlpatterns = [ path('reset///', ResetRequest.as_view()), path('activate///////', ActivateAccount.as_view()), path('reset/', ResetRequest.as_view(), name="reset"), + path('otp/', SeedRetrieveCreate.as_view(), name="seed"), path('', Index.as_view(), name="login_index"), ] \ No newline at end of file diff --git a/dal/views.py b/dal/views.py index f2d8b62..9a66a9f 100644 --- a/dal/views.py +++ b/dal/views.py @@ -14,6 +14,8 @@ from rest_framework.response import Response from .models import ResetToken from .forms import LoginForm from .ungleich_ldap import LdapManager +from decouple import config, Csv +from pyotp import TOTP import logging @@ -26,6 +28,8 @@ from datetime import datetime from random import choice, randint import string +import requests +import json from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin @@ -606,3 +610,43 @@ class UserCreateAPI(APIView): except: return Response('Failed to send the email', 201) return Response('Email with activation link successfully sent', 200) + + +class SeedRetrieveCreate(APIView): + def post(self, request): + try: + username = request.data['username'] + password = request.data['password'] + realm = request.data['realm'] + except KeyError: + return Response('You need to specify username, password, and realm values', 400) + # authenticate the user against ldap + user = authenticate(username=username, password=password) + if user is not None: + req = requests.get(config('OTPSERVER'), data=json.dumps( + { + 'auth_token': TOTP(config('ADMIN_SEED')).now, + 'auth_name': config('ADMIN_NAME'), + 'auth_realm': 'ungleich-admin'}), headers={'Content-Type': 'application/json'}) + response_data = json.loads(req) + for elem in response_data: + if elem['name'] == username and elem['realm'] == realm: + return Response('Your {} seed is {}'.format(realm, elem['seed']), 200) + # If doesn't find a match then check if the realm is allowed and create the user + allowed_realms = config('ALLOWED_REALMS', cast=Csv()) + if realm not in allowed_realms: + return Response('Not allowed to perform this action.', 403) + else: + req = requests.post(config('OTPSERVER'), data=json.dumps( + { + 'auth_token': TOTP(config('ADMIN_SEED')).now, + 'auth_name': config('ADMIN_NAME'), + 'auth_realm': 'ungleich-admin', + 'name': username, + 'realm': realm + }), headers={'Content-Type': 'application/json'}) + if req.status_code == 201: + msg = json.loads(req.text) + return Response(msg, 201) + else: + return Response(json.loads(req.text)) From 4cfff85d7ef50eb793de02b515753d2f262c3003 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 5 May 2019 16:44:27 -0400 Subject: [PATCH 06/17] update requirements --- requirements.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ba3e644..cd37ada 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,7 @@ django-bootstrap3 django-filter==2.1.0 python-decouple ldap3 -djangorestframework \ No newline at end of file +djangorestframework +python-decouple==3.1 +pyotp==2.2.7 +requests \ No newline at end of file From 6795a4c35c992ab1e38c64e18e0cbde9a547ee0d Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 5 May 2019 17:13:58 -0400 Subject: [PATCH 07/17] remove double requirement package --- requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index cd37ada..0eb76fb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,5 @@ django-filter==2.1.0 python-decouple ldap3 djangorestframework -python-decouple==3.1 -pyotp==2.2.7 +pyotp requests \ No newline at end of file From 54aa8f474e53f793e854b3c96f062160b175e084 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 5 May 2019 17:16:14 -0400 Subject: [PATCH 08/17] added rest framework conf --- dal/settings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dal/settings.py b/dal/settings.py index a302eac..e39373f 100644 --- a/dal/settings.py +++ b/dal/settings.py @@ -65,6 +65,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'bootstrap3', 'dal', + 'rest_framework' ] MIDDLEWARE = [ @@ -208,3 +209,10 @@ if config('ENABLE_DEBUG_LOG', default=False, cast=bool): set_library_log_detail_level, OFF, BASIC, NETWORK, EXTENDED ) set_library_log_detail_level(BASIC) + + +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': ( + 'rest_framework.renderers.JSONRenderer', + ) +} From 9711dc1eccb6223d37fd883ad9cd9fee4b99177f Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 5 May 2019 18:12:43 -0400 Subject: [PATCH 09/17] fix show message error when not valid credentials --- dal/views.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/dal/views.py b/dal/views.py index 9a66a9f..7e74e3f 100644 --- a/dal/views.py +++ b/dal/views.py @@ -18,7 +18,6 @@ from decouple import config, Csv from pyotp import TOTP import logging - logger = logging.getLogger(__name__) # Imports for the extra stuff not in django @@ -623,12 +622,18 @@ class SeedRetrieveCreate(APIView): # authenticate the user against ldap user = authenticate(username=username, password=password) if user is not None: - req = requests.get(config('OTPSERVER'), data=json.dumps( + admin_seed = config('ADMIN_SEED') + admin_name = config('ADMIN_NAME') + otp_url = config('OTPSERVER') + + req = requests.get(otp_url, data=json.dumps( { - 'auth_token': TOTP(config('ADMIN_SEED')).now, - 'auth_name': config('ADMIN_NAME'), + 'auth_token': TOTP(admin_seed).now(), + 'auth_name': admin_name, 'auth_realm': 'ungleich-admin'}), headers={'Content-Type': 'application/json'}) - response_data = json.loads(req) + + response_data = json.loads(req.text) + for elem in response_data: if elem['name'] == username and elem['realm'] == realm: return Response('Your {} seed is {}'.format(realm, elem['seed']), 200) @@ -637,10 +642,10 @@ class SeedRetrieveCreate(APIView): if realm not in allowed_realms: return Response('Not allowed to perform this action.', 403) else: - req = requests.post(config('OTPSERVER'), data=json.dumps( + req = requests.post(otp_url, data=json.dumps( { - 'auth_token': TOTP(config('ADMIN_SEED')).now, - 'auth_name': config('ADMIN_NAME'), + 'auth_token': TOTP(admin_seed).now(), + 'auth_name': admin_name, 'auth_realm': 'ungleich-admin', 'name': username, 'realm': realm @@ -649,4 +654,7 @@ class SeedRetrieveCreate(APIView): msg = json.loads(req.text) return Response(msg, 201) else: - return Response(json.loads(req.text)) + return Response(json.loads(req.text), req.status_code) + + else: + return Response('Invalid Credentials', 400) \ No newline at end of file From 9576ae9064993929d156f86a35179706747fd641 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Mon, 6 May 2019 11:42:58 -0400 Subject: [PATCH 10/17] Same messages in creation/deletion preventing scape chars errors in password --- dal/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dal/views.py b/dal/views.py index 7e74e3f..6d76360 100644 --- a/dal/views.py +++ b/dal/views.py @@ -615,11 +615,13 @@ class SeedRetrieveCreate(APIView): def post(self, request): try: username = request.data['username'] - password = request.data['password'] + password = request.data[r'password'] realm = request.data['realm'] + print(password) except KeyError: return Response('You need to specify username, password, and realm values', 400) # authenticate the user against ldap + user = authenticate(username=username, password=password) if user is not None: admin_seed = config('ADMIN_SEED') @@ -636,7 +638,7 @@ class SeedRetrieveCreate(APIView): for elem in response_data: if elem['name'] == username and elem['realm'] == realm: - return Response('Your {} seed is {}'.format(realm, elem['seed']), 200) + return Response(elem, 200) # If doesn't find a match then check if the realm is allowed and create the user allowed_realms = config('ALLOWED_REALMS', cast=Csv()) if realm not in allowed_realms: From 321d8548da494d3af46393130fd30f19bbeb069a Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 26 May 2019 16:13:58 -0400 Subject: [PATCH 11/17] url for seed list --- dal/urls.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dal/urls.py b/dal/urls.py index 6142eab..4c86376 100644 --- a/dal/urls.py +++ b/dal/urls.py @@ -15,6 +15,7 @@ from .views import ( ResetRequest, UserCreateAPI, ActivateAccount, + Seeds, SeedRetrieveCreate ) @@ -22,6 +23,7 @@ urlpatterns = [ path('register/', Register.as_view(), name="register"), path('create/', UserCreateAPI.as_view(), name="create"), path('changedata/', ChangeData.as_view(), name="change_data"), + path('seeds/', Seeds.as_view(), name="user_seeds"), path('resetpassword/', ResetPassword.as_view(), name="reset_password"), path('changepassword/', ChangePassword.as_view(), name="change_password"), path('deleteaccount/', DeleteAccount.as_view(), name="account_delete"), From d37144c541206d0838ca0bb41abdd8a463ca12be Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 26 May 2019 16:15:07 -0400 Subject: [PATCH 12/17] seed listing view and template --- dal/templates/seed_list.html | 35 ++++++++++++++++++++++++++++ dal/views.py | 44 +++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 dal/templates/seed_list.html diff --git a/dal/templates/seed_list.html b/dal/templates/seed_list.html new file mode 100644 index 0000000..6699db0 --- /dev/null +++ b/dal/templates/seed_list.html @@ -0,0 +1,35 @@ +{% extends "base_short.html" %} +{% load i18n staticfiles bootstrap3 %} + +{% block title %} + Options for {{user}} +{% endblock %} + + +{% block content %} +
+
+
+
+
+

{% trans "Seeds of," %} {{user}}



+ + + {% for i in seed %} + + + + + {% endfor %} + +
{{ i.realm }}{{ i.seed }}
+
+
+ +
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/dal/views.py b/dal/views.py index 6d76360..359b47a 100644 --- a/dal/views.py +++ b/dal/views.py @@ -34,6 +34,13 @@ from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin +admin_seed = config('ADMIN_SEED') +admin_name = config('ADMIN_NAME') +admin_realm = config('ADMIN_REALM') +user_realm = config('USER_REALM') +otp_url = config('OTPSERVER') + + def activate_account_link(base_url, user, pwd, firstname, lastname, email, epochutc): tokengen = PasswordResetTokenGenerator() pseudouser = PseudoUser() @@ -551,6 +558,17 @@ class ActivateAccount(View): ldap_manager.create_user( clean_list[0], clean_list[1], clean_list[2], clean_list[3], clean_list[4] ) + req = requests.post(otp_url, data=json.dumps( + { + 'auth_token': TOTP(admin_seed).now(), + 'auth_name': admin_name, + 'auth_realm': admin_realm, + 'name': clean_list[0], + 'realm': user_realm + }), headers={'Content-Type': 'application/json'}) + if req.status_code != 201: + logger.error("User {} failed to create its otp seed".format(clean_list[0])) + #Send welcome email except Exception as e: return render(request, 'error.html', {'urlname': 'register', @@ -624,15 +642,12 @@ class SeedRetrieveCreate(APIView): user = authenticate(username=username, password=password) if user is not None: - admin_seed = config('ADMIN_SEED') - admin_name = config('ADMIN_NAME') - otp_url = config('OTPSERVER') req = requests.get(otp_url, data=json.dumps( { 'auth_token': TOTP(admin_seed).now(), 'auth_name': admin_name, - 'auth_realm': 'ungleich-admin'}), headers={'Content-Type': 'application/json'}) + 'auth_realm': admin_realm}), headers={'Content-Type': 'application/json'}) response_data = json.loads(req.text) @@ -648,7 +663,7 @@ class SeedRetrieveCreate(APIView): { 'auth_token': TOTP(admin_seed).now(), 'auth_name': admin_name, - 'auth_realm': 'ungleich-admin', + 'auth_realm': admin_realm, 'name': username, 'realm': realm }), headers={'Content-Type': 'application/json'}) @@ -659,4 +674,21 @@ class SeedRetrieveCreate(APIView): return Response(json.loads(req.text), req.status_code) else: - return Response('Invalid Credentials', 400) \ No newline at end of file + return Response('Invalid Credentials', 400) + + +class Seeds(LoginRequiredMixin, View): + login_url = reverse_lazy('login_index') + def get(self, request): + seedlist = [] + response = requests.get( + otp_url, + headers={'Content-Type': 'application/json'}, + data=json.dumps( + {'auth_name': admin_name, 'auth_realm': admin_realm, 'auth_token': TOTP(admin_seed).now()})) + response_data = json.loads(response.text) + for i in range(len(response_data)): + if response_data[i]['name'] == 'wcolmenares': #request.user: + value = {'realm': response_data[i]['realm'], 'seed': response_data[i]['seed']} + seedlist.append(value) + return render(request, 'seed_list.html', {'seed': seedlist}) From 36d10deaab2694bc3afec80dbc2376ab5385d546 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 26 May 2019 16:50:56 -0400 Subject: [PATCH 13/17] Added buttons for back to index and show seeds --- dal/templates/changepassword.html | 2 ++ dal/templates/changeuserdata.html | 6 ++++++ dal/templates/deleteaccount.html | 1 + dal/templates/seed_list.html | 8 +++++--- dal/templates/useroptions.html | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dal/templates/changepassword.html b/dal/templates/changepassword.html index e9a5abf..c6f61e6 100644 --- a/dal/templates/changepassword.html +++ b/dal/templates/changepassword.html @@ -35,6 +35,8 @@ +
+ Back to Index
diff --git a/dal/templates/changeuserdata.html b/dal/templates/changeuserdata.html index f8a76d7..8878ca2 100644 --- a/dal/templates/changeuserdata.html +++ b/dal/templates/changeuserdata.html @@ -34,7 +34,13 @@ {% trans "Change User Data" %} +
+ + + diff --git a/dal/templates/deleteaccount.html b/dal/templates/deleteaccount.html index 1828827..3c74052 100644 --- a/dal/templates/deleteaccount.html +++ b/dal/templates/deleteaccount.html @@ -27,6 +27,7 @@
+ Back to Index
diff --git a/dal/templates/seed_list.html b/dal/templates/seed_list.html index 6699db0..9d13640 100644 --- a/dal/templates/seed_list.html +++ b/dal/templates/seed_list.html @@ -25,9 +25,11 @@

- +
+ +
diff --git a/dal/templates/useroptions.html b/dal/templates/useroptions.html index 1e9c568..d5bae62 100644 --- a/dal/templates/useroptions.html +++ b/dal/templates/useroptions.html @@ -16,6 +16,7 @@
{% trans "Change your userdata" %}
Change your password
+ Show seeds
{% trans "Logout" %}


From ce5f88b1348920f0fddc2af34d807ffe221b74ed Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sun, 26 May 2019 16:59:52 -0400 Subject: [PATCH 14/17] fix hardwritten test --- dal/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dal/views.py b/dal/views.py index 359b47a..0717334 100644 --- a/dal/views.py +++ b/dal/views.py @@ -688,7 +688,7 @@ class Seeds(LoginRequiredMixin, View): {'auth_name': admin_name, 'auth_realm': admin_realm, 'auth_token': TOTP(admin_seed).now()})) response_data = json.loads(response.text) for i in range(len(response_data)): - if response_data[i]['name'] == 'wcolmenares': #request.user: + if response_data[i]['name'] == request.user.username: value = {'realm': response_data[i]['realm'], 'seed': response_data[i]['seed']} seedlist.append(value) return render(request, 'seed_list.html', {'seed': seedlist}) From f6b723b76a3b6133f6731a68a468ecb76b24b878 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 30 May 2019 05:04:11 -0400 Subject: [PATCH 15/17] fix typho in creation link --- dal/views.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dal/views.py b/dal/views.py index 0717334..d1e563a 100644 --- a/dal/views.py +++ b/dal/views.py @@ -600,7 +600,7 @@ class UserCreateAPI(APIView): base_url = "{0}://{1}".format(self.request.scheme, self.request.get_host()) creationtime = int(datetime.utcnow().timestamp()) - link = activate_account_link(base_url, username, pwd, firstname, lastname, email. creationtime) + link = activate_account_link(base_url, username, pwd, firstname, lastname, email, creationtime) # Construct the data for the email email_from = settings.EMAIL_FROM_ADDRESS @@ -624,9 +624,10 @@ class UserCreateAPI(APIView): ) try: mail.send() - except: - return Response('Failed to send the email', 201) - return Response('Email with activation link successfully sent', 200) + except Exception as e: + return response('Failed to send the email, please try again', 400) + return Response('An email with activation link has been sent in order to complete your registration.\n\ + \nPlease check your inbox.', 200) class SeedRetrieveCreate(APIView): From e1b4aac2227bc60517f82c8a7cc2f4b7aaf3c361 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 30 May 2019 05:07:06 -0400 Subject: [PATCH 16/17] fix typho response -> Response --- dal/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dal/views.py b/dal/views.py index d1e563a..bf33dbd 100644 --- a/dal/views.py +++ b/dal/views.py @@ -625,7 +625,7 @@ class UserCreateAPI(APIView): try: mail.send() except Exception as e: - return response('Failed to send the email, please try again', 400) + return Response('Failed to send the email, please try again', 400) return Response('An email with activation link has been sent in order to complete your registration.\n\ \nPlease check your inbox.', 200) From 8a8cc5d20e58a8d1f11518c73dffc455d0b3e820 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Thu, 30 May 2019 05:17:20 -0400 Subject: [PATCH 17/17] better response messsage --- dal/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dal/views.py b/dal/views.py index bf33dbd..5e245f5 100644 --- a/dal/views.py +++ b/dal/views.py @@ -626,8 +626,7 @@ class UserCreateAPI(APIView): mail.send() except Exception as e: return Response('Failed to send the email, please try again', 400) - return Response('An email with activation link has been sent in order to complete your registration.\n\ - \nPlease check your inbox.', 200) + return Response('An email with activation link has been sent in order to complete your registration. Please check your inbox.', 200) class SeedRetrieveCreate(APIView):