Files
ldap-interface/app/password.py

138 lines
4.3 KiB
Python

"""
Module that represents the /password route
"""
from flask import (
Blueprint,
render_template,
flash,
current_app
)
from flask_wtf import (
FlaskForm
)
from wtforms import (
StringField,
PasswordField,
SubmitField,
EmailField
)
from wtforms.validators import (
ValidationError,
DataRequired,
EqualTo,
Length,
Regexp,
Email
)
from . import (
ldap_client
)
bp = Blueprint('password', __name__, url_prefix='/password')
class ChangePasswordForm(FlaskForm):
"""
A Flask form that asks users about various informations needed
to change their password.
"""
# Minimal password length
minlength = 9
# Form
username = StringField(label=('Login'),
validators=[DataRequired(),
Length(max=64)],
render_kw={"onkeyup": "validate_username()"})
currentpassword = PasswordField(label=('Current password'),
validators=[DataRequired()])
newpassword = PasswordField(label=('New password'),
validators=[DataRequired(),
Length(min=minlength),
Regexp("^(?=.*[a-z])"),
Regexp("^(?=.*[A-Z])"),
Regexp("^(?=.*\\d)"),
],
render_kw={"onkeyup": "validate_username_form"
f"({minlength})"})
confirm_password = PasswordField(
label=('Confirm Password'),
validators=[DataRequired(message='* Required'),
EqualTo('newpassword')],
render_kw={"onkeyup": f"validate_username_form({minlength})"})
submit = SubmitField(
label=('Change my password'),
render_kw={
"disabled": "true",
"onclick": f"validate_username_form({minlength})"})
# Validators
def validate_username(self):
"""
A validation function for the username input field
"""
excluded_chars = " *?!'^+%&/()=}][{$#;\\\""
for char in self.username.data:
if char in excluded_chars:
raise ValidationError(
f"Character {char} is not allowed in an username.")
class ResetPasswordForm(FlaskForm):
"""
A Flask form that asks users about their email, used to
reset their passwords.
"""
email = EmailField(label=('Email address'),
validators=[DataRequired(), Email()],
render_kw={"onkeyup": "validate_email()"})
submit = SubmitField(
label=('Change my password'),
render_kw={
"disabled": "true",
"onclick": "validate_email()"})
@bp.route('/change', methods=["GET", "POST"])
def change():
"""
The /password/change route method
"""
form = ChangePasswordForm()
if form.validate_on_submit():
ldap_params = ldap_client.ClientParams(
address=current_app.config["LDAP_ADDR"],
port=current_app.config["LDAP_PORT"],
base_dn=current_app.config["BASE_DN"],
tls=current_app.config["LDAP_TLS"])
client = ldap_client.Client(ldap_params)
bind_status = client.bind(
form.username.data, form.currentpassword.data)
if bind_status[0] is False:
flash("Connection failed, are you sure that your login and"
f" password are correct ? ({client.link.last_error})")
elif client.change_pwd(bind_status[1],
form.newpassword.data) is False:
flash("An error occured and your password was not changed, sorry."
f"({client.link.last_error})")
client.unbind()
else:
flash('Your password has been changed !')
client.unbind()
return render_template('change.html', form=form)
@bp.route('/reset', methods=["GET"])
def reset():
"""
The /password/reset route method
"""
return render_template('reset.html')