Add validation email before creation

This commit is contained in:
wcolmenares 2019-05-02 17:29:01 -04:00
parent c4079a1c1d
commit d07ff15f69
3 changed files with 151 additions and 53 deletions

View file

@ -0,0 +1,29 @@
{% extends "base_short.html" %}
{% load i18n staticfiles bootstrap3 %}
{% block title %}
<title> Verify your email. </title>
{% endblock %}
{% block content %}
<div class="auth-container">
<div class="auth-bg"></div>
<div class="auth-center">
<div class="auth-content">
<div class="auth-box">
<h1 class="section-heading allcaps">{% trans " Check your email " %}</h1>
<p class="text-center">{% trans "In order to complete the sign up process, please check your email and follow the activation instructions." %}</p>
<form action="{% url 'index' %}" method="get" class="form" novalidated>
<div class="text-center">
<button type="submit" class="btn choice-btn btn-block">
{% trans "Back to indexpage" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -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/<str:user>/<str:token>/', ResetRequest.as_view()),
path('activate/<str:user>/<str:pwd>/<str:firstname>/<str:lastname>/<str:email>/<str:token>/', ActivateAccount.as_view()),
path('reset/', ResetRequest.as_view(), name="reset"),
path('', Index.as_view(), name="login_index"),
]

View file

@ -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,21 +133,16 @@ class Register(View):
pwd = r'%s' % password1
try:
ldap_manager = LdapManager()
ldap_manager.create_user(
username, pwd, firstname, lastname, email
)
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
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 = '{}, Welcome to datacenterlight'.format(firstname)
body = 'The username {} was successfully created.\n'.format(username)
subject = 'Activate your ungleich account'.format(firstname)
body = 'You can activate your ungleich account account by clicking <a href="{link}">here</a>.' \
' 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,
@ -114,12 +150,13 @@ class Register(View):
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, 'error.html', { 'urlname': urlname,
'service': service,
'error': e } )
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 <a href="{link}">here</a> 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)