From 0ac33aa3c45ec8e07e68f0ca96be824e2955d93b Mon Sep 17 00:00:00 2001 From: Thomas M Steenholdt Date: Sun, 12 Aug 2018 07:40:32 -0200 Subject: [PATCH 1/2] Add option to edit users from the comfort of the UI Update user management feature to allow editing user details directly in the admin user interface. Also added an option to reset the two factor authentication data of a user, for when that's needed (lost device, technical issues etc). (cherry picked from commit 3139616282a18c11463c6ecf78888417b2ac1c35) --- app/models.py | 30 +++++++ ...in_createuser.html => admin_edituser.html} | 80 ++++++++++++++++--- app/templates/admin_manageuser.html | 9 ++- app/views.py | 46 ++++++++--- 4 files changed, 143 insertions(+), 22 deletions(-) rename app/templates/{admin_createuser.html => admin_edituser.html} (53%) diff --git a/app/models.py b/app/models.py index 1cd1733..974518e 100644 --- a/app/models.py +++ b/app/models.py @@ -328,6 +328,36 @@ class User(db.Model): db.session.commit() return {'status': True, 'msg': 'Created user successfully'} + def update_local_user(self): + """ + Update local user + """ + # Sanity check - account name + if self.username == "": + return {'status': False, 'msg': 'No user name specified'} + + # read user and check that it exists + user = User.query.filter(User.username == self.username).first() + if not user: + return {'status': False, 'msg': 'User does not exist'} + + # check if new email exists (only if changed) + if user.email != self.email: + checkuser = User.query.filter(User.email == self.email).first() + if checkuser: + return {'status': False, 'msg': 'New email address is already in use'} + + user.firstname = self.firstname + user.lastname = self.lastname + user.email = self.email + + # store new password hash (only if changed) + if self.plain_text_password != "": + user.password = self.get_hashed_password(self.plain_text_password).decode("utf-8") + + db.session.commit() + return {'status': True, 'msg': 'User updated successfully'} + def update_profile(self, enable_otp=None): """ Update user profile diff --git a/app/templates/admin_createuser.html b/app/templates/admin_edituser.html similarity index 53% rename from app/templates/admin_createuser.html rename to app/templates/admin_edituser.html index fe7d4ea..3fdcb39 100644 --- a/app/templates/admin_createuser.html +++ b/app/templates/admin_edituser.html @@ -1,17 +1,17 @@ {% extends "base.html" %} -{% block title %}DNS Control Panel - Create User{% endblock %} +{% block title %}DNS Control Panel - Edit User{% endblock %} {% block dashboard_stat %}

User - Create new + {% if create %}New user{% else %}{{ user.username }}{% endif %}

{% endblock %} @@ -22,11 +22,12 @@
-

Create new user

+

{% if create %}Add{% else %}Edit{% endif %} user

-
+ +
{% if error %}
@@ -58,12 +59,12 @@
- {% if blank_password %} @@ -72,22 +73,81 @@
+ {% if not create %} +
+
+

Two Factor Authentication

+
+
+

If two factor authentication was configured and is causing problems due to a lost device or technical issue, it can be disabled here.

+

The user will need to reconfigure two factor authentication, to re-enable it.

+

Beware: This could compromise security!

+
+ +
+ {% endif %}
-

Help with creating a new user

+

Help with {% if create %}creating a new{% else%}updating a{% endif %} user

Fill in all the fields to the in the form to the left.

+ {% if create %}

Newly created users do not have access to any domains. You will need to grant access to the user once it is created via the domain management buttons on the dashboard.

+ {% else %} +

Password can be left empty to keep the current password.

+

Username cannot be changed.

+ {% endif %}
-{% endblock %} \ No newline at end of file +{% endblock %} +{% block extrascripts %} + +{% endblock %} +{% block modals %} + +{% endblock %} diff --git a/app/templates/admin_manageuser.html b/app/templates/admin_manageuser.html index 03545bb..24d70e9 100644 --- a/app/templates/admin_manageuser.html +++ b/app/templates/admin_manageuser.html @@ -20,7 +20,7 @@

User Management

- + @@ -36,7 +36,7 @@ Email Admin Privileges - Deletion + Action @@ -54,7 +54,10 @@ Revoke  - + + diff --git a/app/views.py b/app/views.py index d294d3d..3cf5760 100644 --- a/app/views.py +++ b/app/views.py @@ -1156,26 +1156,44 @@ def admin(): return render_template('admin.html', domains=domains, users=users, configs=configs, statistics=statistics, uptime=uptime, history_number=history_number) -@app.route('/admin/user/create', methods=['GET', 'POST']) +@app.route('/admin/user/edit/', methods=['GET', 'POST']) +@app.route('/admin/user/edit', methods=['GET', 'POST']) @login_required @admin_role_required -def admin_createuser(): +def admin_edituser(user_username=None): if request.method == 'GET': - return render_template('admin_createuser.html') + if not user_username: + return render_template('admin_edituser.html', create=1) - if request.method == 'POST': + else: + user = User.query.filter(User.username == user_username).first() + return render_template('admin_edituser.html', user=user, create=0) + + elif request.method == 'POST': fdata = request.form - user = User(username=fdata['username'], plain_text_password=fdata['password'], firstname=fdata['firstname'], lastname=fdata['lastname'], email=fdata['email']) + if not user_username: + user_username = fdata['username'] - if fdata['password'] == "": - return render_template('admin_createuser.html', user=user, blank_password=True) + user = User(username=user_username, plain_text_password=fdata['password'], firstname=fdata['firstname'], lastname=fdata['lastname'], email=fdata['email'], reload_info=False) + + create = int(fdata['create']) + if create: + if fdata['password'] == "": + return render_template('admin_edituser.html', user=user, create=create, blank_password=True) + + result = user.create_local_user() + history = History(msg='Created user {0}'.format(user.username), created_by=current_user.username) + + else: + result = user.update_local_user() + history = History(msg='Updated user {0}'.format(user.username), created_by=current_user.username) - result = user.create_local_user(); if result['status']: + history.add() return redirect(url_for('admin_manageuser')) - return render_template('admin_createuser.html', user=user, error=result['msg']) + return render_template('admin_edituser.html', user=user, create=create, error=result['msg']) @app.route('/admin/manageuser', methods=['GET', 'POST']) @@ -1195,6 +1213,16 @@ def admin_manageuser(): jdata = request.json data = jdata['data'] + if jdata['action'] == 'user_otp_disable': + user = User(username=data) + result = user.update_profile(enable_otp=False) + if result: + history = History(msg='Two factor authentication disabled for user {0}'.format(data), created_by=current_user.username) + history.add() + return make_response(jsonify( { 'status': 'ok', 'msg': 'Two factor authentication has been disabled for user.' } ), 200) + else: + return make_response(jsonify( { 'status': 'error', 'msg': 'Cannot disable two factor authentication for user.' } ), 500) + if jdata['action'] == 'delete_user': user = User(username=data) if user.username == current_user.username: From fe4616d609dfdad119903351e52a7b7bd563e96e Mon Sep 17 00:00:00 2001 From: Thomas M Steenholdt Date: Mon, 13 Aug 2018 01:30:56 -0200 Subject: [PATCH 2/2] Do user.otp_secret check properly --- app/templates/admin_edituser.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/admin_edituser.html b/app/templates/admin_edituser.html index 3fdcb39..83e861d 100644 --- a/app/templates/admin_edituser.html +++ b/app/templates/admin_edituser.html @@ -88,7 +88,7 @@

Beware: This could compromise security!

{% endif %}