2019-01-26 13:02:37 +00:00
# Imports from django
2018-10-09 17:49:47 +00:00
from django . shortcuts import render
2019-02-19 22:16:05 +00:00
from django . views . generic import View , FormView
2018-10-14 17:21:17 +00:00
from django . contrib . auth import authenticate , login , logout
2019-04-23 05:19:45 +00:00
from django . contrib . auth . models import User
2019-02-24 19:16:10 +00:00
from django . http import HttpResponse
2018-10-14 15:48:11 +00:00
from django . core . validators import validate_email , ValidationError
2018-10-09 17:49:47 +00:00
from django . urls import reverse_lazy
2018-10-15 15:52:15 +00:00
from django . contrib . auth . tokens import PasswordResetTokenGenerator
2018-10-16 18:25:50 +00:00
from django . core . mail import EmailMessage
2019-02-24 19:14:49 +00:00
from django . views . decorators . cache import cache_control
2019-04-23 05:19:45 +00:00
from rest_framework . views import APIView
from rest_framework . response import Response
2018-10-16 18:25:50 +00:00
from . models import ResetToken
2019-02-19 22:16:05 +00:00
from . forms import LoginForm
2019-02-23 20:29:33 +00:00
from . ungleich_ldap import LdapManager
2019-05-05 20:44:02 +00:00
from decouple import config , Csv
from pyotp import TOTP
2018-10-16 18:25:50 +00:00
2019-05-01 18:39:25 +00:00
import logging
logger = logging . getLogger ( __name__ )
2018-10-16 18:25:50 +00:00
# Imports for the extra stuff not in django
2019-01-26 13:02:37 +00:00
2018-10-15 15:52:15 +00:00
from base64 import b64encode , b64decode
from datetime import datetime
2019-01-26 13:02:37 +00:00
2018-10-16 18:25:50 +00:00
from random import choice , randint
import string
2019-05-05 20:44:02 +00:00
import requests
import json
2018-11-07 12:08:46 +00:00
2019-01-26 16:46:06 +00:00
from django . conf import settings
2019-02-24 19:13:09 +00:00
from django . contrib . auth . mixins import LoginRequiredMixin
2018-10-09 17:49:47 +00:00
2018-10-16 18:25:50 +00:00
2019-05-26 20:15:07 +00:00
admin_seed = config ( ' ADMIN_SEED ' )
admin_name = config ( ' ADMIN_NAME ' )
admin_realm = config ( ' ADMIN_REALM ' )
user_realm = config ( ' USER_REALM ' )
otp_url = config ( ' OTPSERVER ' )
2019-05-02 21:29:01 +00:00
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
2019-05-02 21:36:31 +00:00
link = " {base_url} /activate/ {user} / {pwd} / {fn} / {ln} / {mail} / {token} / " . format (
2019-05-02 21:29:01 +00:00
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
2019-02-19 22:16:05 +00:00
class Index ( FormView ) :
template_name = " landing.html "
form_class = LoginForm
2019-02-23 08:20:58 +00:00
success_url = ' useroptions.html '
def form_valid ( self , form ) :
2019-05-02 08:10:06 +00:00
username = form . cleaned_data . get ( ' username ' )
2019-02-23 08:20:58 +00:00
password = form . cleaned_data . get ( ' password ' )
2019-05-02 08:10:06 +00:00
user = authenticate ( username = username , password = password )
2019-02-23 08:20:58 +00:00
if user is not None :
login ( self . request , user )
return render ( self . request , ' useroptions.html ' , { ' user ' : user } )
return render ( self . request , ' loginfailed.html ' )
2018-10-09 17:49:47 +00:00
2019-02-24 19:14:49 +00:00
@cache_control ( no_cache = True , must_revalidate = True , no_store = True )
def get ( self , request , * args , * * kwargs ) :
if self . request . user . is_authenticated :
return render ( self . request , ' useroptions.html ' ,
{ ' user ' : self . request . user . username } )
return super ( Index , self ) . get ( request , * args , * * kwargs )
2018-10-09 17:49:47 +00:00
class Register ( View ) :
def get ( self , request ) :
return render ( request , ' registeruser.html ' )
# Someone filled out the register page, do some basic checks and throw it at nameko
def post ( self , request ) :
2018-10-10 16:07:22 +00:00
service = ' register an user '
2018-10-09 17:49:47 +00:00
urlname = ' register '
username = request . POST . get ( ' username ' )
2019-01-26 16:46:06 +00:00
2018-10-14 16:17:59 +00:00
if username == " " or not username :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Please supply a username. ' } )
2019-01-26 14:19:58 +00:00
2018-10-09 17:49:47 +00:00
password1 = request . POST . get ( ' password1 ' )
password2 = request . POST . get ( ' password2 ' )
if password1 != password2 :
2019-01-26 14:19:58 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname ,
' service ' : service ,
2019-01-26 16:46:06 +00:00
' error ' : " Passwords don ' t match. " } )
2018-10-23 16:13:25 +00:00
2018-10-09 17:49:47 +00:00
email = request . POST . get ( ' email ' )
2018-10-14 15:48:11 +00:00
try :
validate_email ( email )
except ValidationError :
2019-01-26 16:46:06 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname ,
' service ' : service ,
' error ' : ' The supplied email address is invalid. ' } )
2018-10-14 15:48:11 +00:00
2018-10-09 17:49:47 +00:00
firstname = request . POST . get ( ' firstname ' )
lastname = request . POST . get ( ' lastname ' )
2019-01-26 16:46:06 +00:00
if not firstname or not lastname :
return render ( request , ' error.html ' , { ' urlname ' : urlname ,
' service ' : service ,
' error ' : ' Please enter your firstname and lastname. ' } )
2018-10-09 17:49:47 +00:00
2019-01-26 14:19:58 +00:00
# so nothing strange happens if there are escapable chars
pwd = r ' %s ' % password1
2018-10-09 17:49:47 +00:00
2019-01-26 14:19:58 +00:00
try :
2019-05-02 21:29:01 +00:00
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 <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 ,
body = body ,
from_email = email_from ,
to = to
2019-02-23 20:29:33 +00:00
)
2019-05-02 21:29:01 +00:00
mail . send ( )
2019-01-26 14:19:58 +00:00
except Exception as e :
return render ( request , ' error.html ' , { ' urlname ' : urlname ,
' service ' : service ,
' error ' : e } )
2019-05-02 21:29:01 +00:00
return render ( request , ' confirm_email.html ' )
2018-10-14 15:48:11 +00:00
2019-02-24 19:13:09 +00:00
class ChangeData ( LoginRequiredMixin , View ) :
2019-02-24 19:34:53 +00:00
login_url = reverse_lazy ( ' login_index ' )
2018-10-09 17:49:47 +00:00
# provide the form for the change request
def get ( self , request ) :
2018-10-14 15:48:11 +00:00
urlname = ' change_data '
service = ' get default data for logged in user '
2019-02-24 14:29:40 +00:00
2019-02-24 21:23:43 +00:00
user = request . user
2019-02-24 14:29:40 +00:00
ldap_manager = LdapManager ( )
user_exists , entries = ldap_manager . check_user_exists (
uid = user . username ,
2019-02-24 21:23:43 +00:00
attributes = [ ' uid ' , ' givenName ' , ' sn ' , ' mail ' ] ,
search_base = settings . ENTIRE_SEARCH_BASE
2019-02-24 14:29:40 +00:00
)
if user_exists :
return render (
request ,
' changeuserdata.html ' ,
{ ' user ' : user . username ,
' firstname ' : entries [ 0 ] . givenName
if entries [ 0 ] . givenName . value is not None else ' ' ,
' lastname ' : entries [ 0 ] . sn
if entries [ 0 ] . sn . value is not None else ' ' ,
2019-02-24 16:25:13 +00:00
' email ' : entries [ 0 ] . mail
if entries [ 0 ] . mail . value is not None else ' ' }
2019-02-24 14:29:40 +00:00
)
2018-10-14 15:48:11 +00:00
else :
2019-02-24 14:29:40 +00:00
return render ( request , ' error.html ' ,
{ ' urlname ' : urlname , ' service ' : service ,
' error ' : request . user . username } )
2018-10-09 17:49:47 +00:00
# get the change request
def post ( self , request ) :
# variables for the error page
2018-10-10 16:07:22 +00:00
service = ' change user data '
2018-10-09 17:49:47 +00:00
urlname = ' change_data '
firstname = request . POST . get ( ' firstname ' )
lastname = request . POST . get ( ' lastname ' )
email = request . POST . get ( ' email ' )
2019-01-26 13:02:37 +00:00
2018-10-09 17:49:47 +00:00
# Some sanity checks for the supplied data
if firstname == " " :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Please enter a firstname. ' } )
elif lastname == " " :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Please enter a lastname. ' } )
elif email == " " :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Please enter an email. ' } )
2018-10-14 15:48:11 +00:00
try :
validate_email ( email )
except ValidationError :
2018-10-09 17:49:47 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' The supplied email address is invalid. ' } )
2019-02-24 16:25:13 +00:00
ldap_manager = LdapManager ( )
result , msg = ldap_manager . change_user_details (
uid = request . user . username ,
details = { " givenName " : firstname , " sn " : lastname , " mail " : email }
)
2018-10-14 15:48:11 +00:00
# Data change worked
2019-02-24 16:25:13 +00:00
if result :
return render ( request , ' changeddata.html ' , { ' user ' : request . user . username , ' firstname ' : firstname , ' lastname ' : lastname , ' email ' : email } )
2018-10-14 15:48:11 +00:00
# Data change did not work, display error
else :
2019-02-24 16:25:13 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : msg } )
2018-10-09 17:49:47 +00:00
2019-02-24 19:35:25 +00:00
class ResetPassword ( View ) :
2018-10-09 17:49:47 +00:00
def get ( self , request ) :
return render ( request , ' resetpassword.html ' )
def post ( self , request ) :
2018-10-10 16:07:22 +00:00
urlname = ' reset_password '
service = ' send a password reset request '
2018-10-09 17:49:47 +00:00
user = request . POST . get ( ' user ' )
2018-10-15 15:52:15 +00:00
# First, check if the user exists
2019-02-24 17:42:27 +00:00
ldap_manager = LdapManager ( )
user_exists , entries = ldap_manager . check_user_exists (
uid = user ,
2019-02-24 22:25:12 +00:00
search_base = settings . ENTIRE_SEARCH_BASE ,
2019-02-24 17:42:27 +00:00
attributes = [ ' uid ' , ' givenName ' , ' sn ' , ' mail ' ]
)
2019-02-24 19:35:25 +00:00
if user_exists :
2019-02-24 17:42:27 +00:00
# user exists, so try to get email
# with get_pool().next() as rpc:
# (state, tmp1, tmp2, email) = rpc.getuserdata.get_data(user)
# Either error with the datalookup or no email provided
email = entries [ 0 ] . mail . value
if email is None :
return render (
request , ' error.html ' ,
{ ' urlname ' : urlname , ' service ' : service ,
' error ' : ' Unable to retrieve email address for user. ' }
)
base_url = " {0} :// {1} " . format ( self . request . scheme ,
self . request . get_host ( ) )
# Try to send the email out
emailsend = self . email ( user , email , base_url )
# Email got sent out
if emailsend == True :
return render (
request , ' send_resetrequest.html ' , { ' user ' : user }
)
# Error while trying to send email
else :
return render (
request , ' error.html ' ,
{ ' urlname ' : urlname , ' service ' : service ,
' error ' : emailsend }
)
2018-10-15 15:52:15 +00:00
else :
2019-02-24 17:42:27 +00:00
return render (
request , ' error.html ' ,
{ ' urlname ' : urlname , ' service ' : service ,
' error ' : ' The user does not exist. ' }
)
2018-10-15 15:52:15 +00:00
2018-10-15 19:24:53 +00:00
# Sends an email to the user with the 24h active link for a password reset
2019-02-24 17:42:02 +00:00
def email ( self , user , email , base_url ) :
2018-10-15 19:24:53 +00:00
# getting epoch for the time now in UTC to spare us headache with timezones
creationtime = int ( datetime . utcnow ( ) . timestamp ( ) )
2018-10-16 18:25:50 +00:00
# Construct the data for the email
2019-02-24 17:41:07 +00:00
email_from = settings . EMAIL_FROM_ADDRESS
2018-10-16 18:25:50 +00:00
to = [ ' %s < %s > ' % ( user , email ) ]
2018-10-15 15:52:15 +00:00
subject = ' Password reset request for %s ' % user
2019-02-24 17:42:02 +00:00
link = self . build_reset_link ( user , creationtime , base_url )
2018-10-16 18:25:50 +00:00
body = ' This is an automated email which was triggered by a reset request for the user %s . Please do not reply to this email. \n ' % user
2018-10-15 15:52:15 +00:00
body + = ' If you received this email in error, please disregard it. If you get multiple emails like this, please contact us to look into potential abuse. \n '
body + = ' To reset your password, please follow the link below: \n '
body + = ' %s \n \n ' % link
2018-10-15 19:24:53 +00:00
body + = ' The link will remain active for 24 hours. \n '
2018-10-16 18:25:50 +00:00
# Build the email
mail = EmailMessage (
subject = subject ,
body = body ,
from_email = email_from ,
to = to
)
try :
mail . send ( )
result = True
except :
result = " An error occurred while trying to send the mail. "
return result
2018-10-15 15:52:15 +00:00
2018-10-15 19:24:53 +00:00
# Builds the reset link for the email and puts the token into the database
2019-02-24 17:42:02 +00:00
def build_reset_link ( self , user , epochutc , base_url ) :
2019-01-26 13:02:37 +00:00
# set up the data
2018-10-15 19:24:53 +00:00
tokengen = PasswordResetTokenGenerator ( )
2018-10-16 18:25:50 +00:00
# create some noise for use in the tokengenerator
pseudouser = PseudoUser ( )
token = tokengen . make_token ( pseudouser )
2018-10-15 19:24:53 +00:00
buser = bytes ( user , ' utf-8 ' )
userpart = b64encode ( buser )
2019-01-26 13:02:37 +00:00
# create entry into the database
2018-10-15 19:24:53 +00:00
newdbentry = ResetToken ( user = user , token = token , creation = epochutc )
newdbentry . save ( )
# set up the link
2019-05-01 18:39:25 +00:00
link = " {base_url} /reset/ {user} / {token} / " . format (
base_url = base_url , user = userpart . decode ( ' utf-8 ' ) , token = token
)
logger . debug ( " User reset url is {} " . format ( link ) )
2018-10-15 15:52:15 +00:00
return link
2018-10-15 19:24:53 +00:00
# Catch the resetrequest URL and check it
2018-10-15 15:52:15 +00:00
class ResetRequest ( View ) :
# Gets the URL with user in b64 and the token, and checks it
# Also cleans the database
def get ( self , request , user = None , token = None ) :
# Cleans up outdated tokens
2018-10-15 19:24:53 +00:00
# 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
2019-05-02 21:29:01 +00:00
clean_db ( )
2018-10-15 19:24:53 +00:00
# If user and token are not supplied by django, it was called from somewhere else, so it's
# invalid
2018-10-15 15:52:15 +00:00
if user == None or token == None :
return HttpResponse ( ' Invalid URL. ' , status = 404 )
# extract user from b64 format
tmp_user = bytes ( user , ' utf-8 ' )
user = b64decode ( tmp_user )
user_clean = user . decode ( ' utf-8 ' )
2018-10-15 19:24:53 +00:00
# set checks_out = True if token is found in database
2019-02-24 22:51:32 +00:00
checks_out = False
2018-10-15 19:24:53 +00:00
dbentries = ResetToken . objects . all ( ) . filter ( user = user_clean )
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
2018-10-15 15:52:15 +00:00
if not checks_out :
return HttpResponse ( ' Invalid URL. ' , status = 404 )
2018-10-15 19:24:53 +00:00
# Token was found, supply the form
2018-10-15 15:52:15 +00:00
else :
return render ( request , ' resetpasswordnew.html ' , { ' user ' : user_clean } )
# Gets the post form with the new password and sets it
def post ( self , request ) :
service = ' reset the password '
2018-10-15 19:24:53 +00:00
# get the supplied passwords
2018-10-15 15:52:15 +00:00
password1 = request . POST . get ( " password1 " )
password2 = request . POST . get ( " password2 " )
2018-10-15 19:24:53 +00:00
# get the hidden value of user
2018-10-15 15:52:15 +00:00
user = request . POST . get ( " user " )
2018-10-15 19:24:53 +00:00
# some checks over the supplied data
2019-05-01 21:48:24 +00:00
if user == " " or not user :
2018-10-15 19:24:53 +00:00
return render ( request , ' error.html ' , { ' service ' : service , ' error ' : ' Something went wrong. Did you use the supplied form? ' } )
2018-10-15 15:52:15 +00:00
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 :
2019-05-02 21:29:01 +00:00
return render ( request , ' error.html ' , { ' service ' : service , ' error ' : ' The supplied passwords do not match. ' } )
2018-10-23 17:41:49 +00:00
if len ( password1 ) < 8 :
2019-05-02 21:29:01 +00:00
return render ( request , ' error.html ' , { ' service ' : service ,
' error ' : ' The password is too short, please use a longer one. At least 8 characters. ' } )
2019-02-23 17:47:01 +00:00
ldap_manager = LdapManager ( )
result = ldap_manager . change_password (
2019-02-24 16:24:44 +00:00
user ,
2019-02-23 17:47:01 +00:00
password1
)
# password change successful
if result :
2018-10-15 15:52:15 +00:00
return render ( request , ' changedpassword.html ' , { ' user ' : user } )
2018-10-15 19:24:53 +00:00
# Something went wrong while changing the password
2018-10-15 15:52:15 +00:00
else :
return render ( request , ' error.html ' , { ' service ' : service , ' error ' : result } )
2019-05-02 21:29:01 +00:00
2018-10-09 17:49:47 +00:00
# The logged in user can change the password here
2019-02-24 19:13:09 +00:00
class ChangePassword ( LoginRequiredMixin , View ) :
2019-02-24 19:34:53 +00:00
login_url = reverse_lazy ( ' login_index ' )
2018-10-09 17:49:47 +00:00
# Presents the page for a logged in user
def get ( self , request ) :
if not request . user . is_authenticated :
return render ( request , ' mustbeloggedin.html ' )
return render ( request , ' changepassword.html ' , { ' user ' : request . user } )
2019-01-26 13:02:37 +00:00
2018-10-09 17:49:47 +00:00
# Does some checks on the supplied data and changes the password
def post ( self , request ) :
# Variables for the error page
urlname = ' change_password '
service = ' change the password '
if not request . user . is_authenticated :
return render ( request , ' mustbeloggedin.html ' )
2018-10-10 16:07:22 +00:00
login ( request , request . user )
2018-10-14 17:21:17 +00:00
user = str ( request . user )
2018-10-09 17:49:47 +00:00
oldpassword = request . POST . get ( ' oldpassword ' )
check = authenticate ( request , username = user , password = oldpassword )
# Is the right password for the user supplied?
if check is None :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Wrong password for the user. ' } )
password1 = request . POST . get ( ' password1 ' )
password2 = request . POST . get ( ' password2 ' )
# Are both passwords from the form the same?
if password1 != password2 :
2019-01-26 13:02:37 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service ,
2018-10-09 17:49:47 +00:00
' error ' : ' Please check if you typed the same password both times for the new password ' } )
2018-10-23 17:41:49 +00:00
# Check for password length
if len ( password1 ) < 8 :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service ,
' error ' : ' The password is too short, please use a longer one. At least 8 characters. ' } )
2019-02-23 18:50:42 +00:00
from . ungleich_ldap import LdapManager
ldap_manager = LdapManager ( )
result = ldap_manager . change_password (
2019-02-24 16:24:44 +00:00
user ,
2019-02-23 18:50:42 +00:00
password1
)
2018-10-14 15:48:11 +00:00
# Password was changed
2019-02-23 18:50:42 +00:00
if result :
2019-02-24 22:32:50 +00:00
logout ( request )
2018-10-09 17:49:47 +00:00
return render ( request , ' changedpassword.html ' , { ' user ' : user } )
2018-10-14 15:48:11 +00:00
# Password not changed, instead got some kind of error
2018-10-09 17:49:47 +00:00
else :
2018-10-14 15:48:11 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : result } )
2018-10-09 17:49:47 +00:00
2018-10-14 15:48:11 +00:00
# Deletes an account
2019-02-24 19:13:09 +00:00
class DeleteAccount ( LoginRequiredMixin , View ) :
2019-02-24 19:34:53 +00:00
login_url = reverse_lazy ( ' login_index ' )
2018-10-14 15:48:11 +00:00
# Show the basic form for deleting an account
2018-10-09 17:49:47 +00:00
def get ( self , request ) :
2018-10-10 12:13:49 +00:00
return render ( request , ' deleteaccount.html ' )
2018-10-09 17:49:47 +00:00
2018-10-14 15:48:11 +00:00
# Reads the filled out form
2018-10-10 12:13:49 +00:00
def post ( self , request ) :
# Variables for error page
urlname = ' account_delete '
service = ' delete an account '
# Does the user exist?
2018-10-10 16:07:22 +00:00
username = request . POST . get ( ' username ' )
2019-02-24 16:45:39 +00:00
ldap_manager = LdapManager ( )
user_exists , user_details = ldap_manager . check_user_exists ( username )
if user_exists and request . user . username == username :
# Do user and password match?
password = request . POST . get ( ' password ' )
pwd = r ' %s ' % password
check = authenticate ( request , username = username , password = pwd )
if check is None :
return render ( request , ' error.html ' ,
{ ' urlname ' : urlname , ' service ' : service ,
' error ' : ' Wrong password for user. ' } )
result = ldap_manager . delete_user ( username )
# User deleted
if result :
logout ( request )
return render ( request , ' deleteduser.html ' , { ' user ' : username } )
# User not deleted, got some kind of error
else :
return render ( request , ' error.html ' ,
{ ' urlname ' : urlname , ' service ' : service ,
' error ' : result } )
2018-10-14 15:48:11 +00:00
else :
2019-02-24 16:46:44 +00:00
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Unknown user. ' } )
2018-10-09 17:49:47 +00:00
2018-10-15 19:24:53 +00:00
# Log out the session
2018-10-14 17:21:17 +00:00
class LogOut ( View ) :
def get ( self , request ) :
logout ( request )
2019-02-24 19:15:52 +00:00
return HttpResponse (
" You have been logged out. You will be redirected in 2 seconds. "
" <script> "
" setTimeout(function () { document.location.href= ' / ' ;}, 2000); "
" </script> " ,
status = 200
)
2019-01-26 14:19:58 +00:00
# TO be clarified
# To trick the tokengenerator to work with us, because we don't really
# have the expected user Class since we are reading the user from a form
# We store the tokens and don't have to use the check function,
# some one time data works fine.
class LastLogin ( ) :
def replace ( self , microsecond = 0 , tzinfo = None ) :
return randint ( 1 , 100000 )
class PseudoUser ( ) :
# easiest way to handle the check for lastlogin
last_login = LastLogin ( )
# random alphanumeric strings for primary key and password, just used for token generation
pk = ' ' . join ( choice ( string . ascii_letters + string . digits ) for _ in range ( 20 ) )
password = ' ' . join ( choice ( string . ascii_letters + string . digits ) for _ in range ( 30 ) )
2019-04-23 05:19:45 +00:00
2019-05-02 21:29:01 +00:00
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 ]
)
2019-05-26 20:15:07 +00:00
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 ] ) )
2019-05-02 21:29:01 +00:00
#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 ] } )
2019-04-23 05:19:45 +00:00
class UserCreateAPI ( APIView ) :
def post ( self , request ) :
2019-04-25 20:14:58 +00:00
2019-04-23 05:19:45 +00:00
username = request . POST . get ( ' username ' )
email = request . POST . get ( ' email ' )
firstname = request . POST . get ( ' firstname ' )
lastname = request . POST . get ( ' lastname ' )
if username == " " or not username :
return Response ( ' Please supply a username. ' , 400 )
try :
validate_email ( email )
except ValidationError :
return Response ( ' Email is not valid. ' , 400 )
if not firstname or not lastname :
return Response ( ' Please provide firstname and lastname ' , 400 )
pwd = r ' %s ' % User . objects . make_random_password ( )
2019-05-02 21:29:01 +00:00
base_url = " {0} :// {1} " . format ( self . request . scheme ,
self . request . get_host ( ) )
2019-04-23 05:19:45 +00:00
creationtime = int ( datetime . utcnow ( ) . timestamp ( ) )
2019-05-02 21:29:01 +00:00
link = activate_account_link ( base_url , username , pwd , firstname , lastname , email . creationtime )
2019-04-23 05:19:45 +00:00
# Construct the data for the email
email_from = settings . EMAIL_FROM_ADDRESS
to = [ ' %s < %s > ' % ( username , email ) ]
2019-05-02 21:29:01 +00:00
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 )
2019-04-23 05:19:45 +00:00
body + = ' Your credentials are: \n '
body + = ' Username: %s \n \n ' % username
body + = ' Password: %s \n \n ' % pwd
2019-05-02 21:29:01 +00:00
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 '
2019-04-23 05:19:45 +00:00
# Build the email
mail = EmailMessage (
subject = subject ,
body = body ,
from_email = email_from ,
to = to
)
try :
mail . send ( )
except :
2019-05-02 21:29:01 +00:00
return Response ( ' Failed to send the email ' , 201 )
return Response ( ' Email with activation link successfully sent ' , 200 )
2019-05-05 20:44:02 +00:00
class SeedRetrieveCreate ( APIView ) :
def post ( self , request ) :
try :
username = request . data [ ' username ' ]
2019-05-06 15:42:58 +00:00
password = request . data [ r ' password ' ]
2019-05-05 20:44:02 +00:00
realm = request . data [ ' realm ' ]
2019-05-06 15:42:58 +00:00
print ( password )
2019-05-05 20:44:02 +00:00
except KeyError :
return Response ( ' You need to specify username, password, and realm values ' , 400 )
# authenticate the user against ldap
2019-05-06 15:42:58 +00:00
2019-05-05 20:44:02 +00:00
user = authenticate ( username = username , password = password )
if user is not None :
2019-05-05 22:12:43 +00:00
req = requests . get ( otp_url , data = json . dumps (
2019-05-05 20:44:02 +00:00
{
2019-05-05 22:12:43 +00:00
' auth_token ' : TOTP ( admin_seed ) . now ( ) ,
' auth_name ' : admin_name ,
2019-05-26 20:15:07 +00:00
' auth_realm ' : admin_realm } ) , headers = { ' Content-Type ' : ' application/json ' } )
2019-05-05 22:12:43 +00:00
response_data = json . loads ( req . text )
2019-05-05 20:44:02 +00:00
for elem in response_data :
if elem [ ' name ' ] == username and elem [ ' realm ' ] == realm :
2019-05-06 15:42:58 +00:00
return Response ( elem , 200 )
2019-05-05 20:44:02 +00:00
# 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 :
2019-05-05 22:12:43 +00:00
req = requests . post ( otp_url , data = json . dumps (
2019-05-05 20:44:02 +00:00
{
2019-05-05 22:12:43 +00:00
' auth_token ' : TOTP ( admin_seed ) . now ( ) ,
' auth_name ' : admin_name ,
2019-05-26 20:15:07 +00:00
' auth_realm ' : admin_realm ,
2019-05-05 20:44:02 +00:00
' name ' : username ,
' realm ' : realm
} ) , headers = { ' Content-Type ' : ' application/json ' } )
if req . status_code == 201 :
msg = json . loads ( req . text )
return Response ( msg , 201 )
else :
2019-05-05 22:12:43 +00:00
return Response ( json . loads ( req . text ) , req . status_code )
else :
2019-05-26 20:15:07 +00:00
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 ) ) :
2019-05-26 20:59:52 +00:00
if response_data [ i ] [ ' name ' ] == request . user . username :
2019-05-26 20:15:07 +00:00
value = { ' realm ' : response_data [ i ] [ ' realm ' ] , ' seed ' : response_data [ i ] [ ' seed ' ] }
seedlist . append ( value )
return render ( request , ' seed_list.html ' , { ' seed ' : seedlist } )