Add validation email before creation
This commit is contained in:
parent
c4079a1c1d
commit
d07ff15f69
3 changed files with 151 additions and 53 deletions
29
dal/templates/confirm_email.html
Normal file
29
dal/templates/confirm_email.html
Normal 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 %}
|
|
@ -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"),
|
||||
]
|
157
dal/views.py
157
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,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)
|
||||
|
|
Loading…
Reference in a new issue