From c8d2b8cb95f8b03126a8bd02cab6abbab05e39e6 Mon Sep 17 00:00:00 2001 From: Terrtia Date: Wed, 14 Aug 2019 12:53:51 +0200 Subject: [PATCH] chg: [UI] add user management --- server/documentation/Database.md | 33 +++- server/lib/User.py | 64 +++++++ server/requirement.txt | 2 + server/web/Flask_server.py | 199 +++++++++++++++++++++- server/web/Role_Manager.py | 183 ++++++++++++++++++++ server/web/create_default_user.py | 46 +++++ server/web/templates/403.html | 67 ++++++++ server/web/templates/change_password.html | 108 ++++++++++++ server/web/templates/login.html | 85 +++++++++ 9 files changed, 777 insertions(+), 10 deletions(-) create mode 100755 server/lib/User.py create mode 100644 server/web/Role_Manager.py create mode 100755 server/web/create_default_user.py create mode 100644 server/web/templates/403.html create mode 100644 server/web/templates/change_password.html create mode 100644 server/web/templates/login.html diff --git a/server/documentation/Database.md b/server/documentation/Database.md index 199adc5..c0de286 100644 --- a/server/documentation/Database.md +++ b/server/documentation/Database.md @@ -7,12 +7,35 @@ D4 core server is a complete server to handle clients (sensors) including the decapsulation of the [D4 protocol](https://github.com/D4-project/architecture/tree/master/format), control of sensor registrations, management of decoding protocols and dispatching to adequate decoders/analysers. -## Database map +## Database map - Metadata -| Key | Value | -| --- | --- | -| | | -| | | | +``` + DB 0 - Stats + sensor configs + DB 1 - Users + DB 2 - Analyzer queue +``` + +### DB 1 + +##### User Management: +| Hset Key | Field | Value | +| ------ | ------ | ------ | +| user:all | **user id** | **password hash** | +| | | | +| user:tokens | **token** | **user id** | +| | | | +| user_metadata:**user id** | token | **token** | +| | change_passwd | **boolean** | +| | role | **role** | + +| Set Key | Value | +| ------ | ------ | +| user_role:**role** | **user id** | + + +| Zrank Key | Field | Value | +| ------ | ------ | ------ | +| ail:all_role | **role** | **int, role priority (1=admin)** | ### Server | Key | Value | diff --git a/server/lib/User.py b/server/lib/User.py new file mode 100755 index 0000000..74552a7 --- /dev/null +++ b/server/lib/User.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# -*-coding:UTF-8 -* + +import os +import redis +import bcrypt + +from flask_login import UserMixin + +class User(UserMixin): + + def __init__(self, id): + host_redis_metadata = os.getenv('D4_REDIS_METADATA_HOST', "localhost") + port_redis_metadata = int(os.getenv('D4_REDIS_METADATA_PORT', 6380)) + + self.r_serv_db = redis.StrictRedis( + host=host_redis_metadata, + port=port_redis_metadata, + db=1, + decode_responses=True) + + if self.r_serv_db.hexists('user:all', id): + self.id = id + else: + self.id = "__anonymous__" + + # return True or False + #def is_authenticated(): + + # return True or False + #def is_anonymous(): + + @classmethod + def get(self_class, id): + return self_class(id) + + def user_is_anonymous(self): + if self.id == "__anonymous__": + return True + else: + return False + + def check_password(self, password): + if self.user_is_anonymous(): + return False + + password = password.encode() + hashed_password = self.r_serv_db.hget('user:all', self.id).encode() + if bcrypt.checkpw(password, hashed_password): + return True + else: + return False + + def request_password_change(self): + if self.r_serv_db.hget('user_metadata:{}'.format(self.id), 'change_passwd') == 'True': + return True + else: + return False + + def is_in_role(self, role): + if self.r_serv_db.sismember('user_role:{}'.format(role), self.id): + return True + else: + return False diff --git a/server/requirement.txt b/server/requirement.txt index 68a556b..934c0ca 100644 --- a/server/requirement.txt +++ b/server/requirement.txt @@ -1,6 +1,8 @@ twisted[tls] redis flask +flask-login +bcrypt #sudo python3 -m pip install --upgrade service_identity diff --git a/server/web/Flask_server.py b/server/web/Flask_server.py index 81a07b7..4eed83f 100755 --- a/server/web/Flask_server.py +++ b/server/web/Flask_server.py @@ -3,12 +3,14 @@ import os import re +import ssl import sys -import uuid -import time import json -import redis +import time +import uuid import flask +import redis +import random import datetime import ipaddress import configparser @@ -16,6 +18,17 @@ import configparser import subprocess from flask import Flask, render_template, jsonify, request, Blueprint, redirect, url_for +from flask_login import LoginManager, current_user, login_user, logout_user, login_required + +import bcrypt + +# Import Role_Manager +from Role_Manager import create_user_db, check_password_strength, check_user_role_integrity +from Role_Manager import login_admin, login_analyst + +sys.path.append(os.path.join(os.environ['D4_HOME'], 'lib')) + +from User import User baseUrl = '' if baseUrl != '': @@ -59,6 +72,12 @@ redis_server_metadata = redis.StrictRedis( db=0, decode_responses=True) +redis_users = redis.StrictRedis( + host=host_redis_metadata, + port=port_redis_metadata, + db=1, + decode_responses=True) + redis_server_analyzer = redis.StrictRedis( host=host_redis_metadata, port=port_redis_metadata, @@ -71,9 +90,31 @@ json_type_description = {} for type_info in json_type: json_type_description[type_info['type']] = type_info +Flask_dir = os.path.join(os.environ['D4_HOME'], 'web') + +# ========= TLS =========# +ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) +ssl_context.load_cert_chain(certfile=os.path.join(Flask_dir, 'server.crt'), keyfile=os.path.join(Flask_dir, 'server.key')) +#print(ssl_context.get_ciphers()) +# ========= =========# + app = Flask(__name__, static_url_path=baseUrl+'/static/') app.config['MAX_CONTENT_LENGTH'] = 900 * 1024 * 1024 +# ========= session ======== +app.secret_key = str(random.getrandbits(256)) +login_manager = LoginManager() +login_manager.login_view = 'login' +login_manager.init_app(app) +# ========= =========# + +# ========= LOGIN MANAGER ======== + +@login_manager.user_loader +def load_user(user_id): + return User.get(user_id) +# ========= =========# + # ========== FUNCTIONS ============ def is_valid_uuid_v4(header_uuid): try: @@ -195,19 +236,137 @@ def get_uuid_disk_statistics(uuid_name, date_day='', type='', all_types_on_disk= @app.errorhandler(404) def page_not_found(e): - return render_template('404.html'), 404 + # API - JSON + if request.path.startswith('/api/'): + return Response(json.dumps({"status": "error", "reason": "404 Not Found"}, indent=2, sort_keys=True), mimetype='application/json'), 404 + # UI - HTML Template + else: + return render_template('404.html'), 404 + +@app.errorhandler(405) +def _handle_client_error(e): + if request.path.startswith('/api/'): + res_dict = {"status": "error", "reason": "Method Not Allowed: The method is not allowed for the requested URL"} + anchor_id = request.path[8:] + anchor_id = anchor_id.replace('/', '_') + api_doc_url = 'https://d4-project.org#{}'.format(anchor_id) + res_dict['documentation'] = api_doc_url + return Response(json.dumps(res_dict, indent=2, sort_keys=True), mimetype='application/json'), 405 + else: + return # ========== ROUTES ============ +@app.route('/login', methods=['POST', 'GET']) +def login(): + + ''' + current_ip = request.remote_addr + login_failed_ip = r_cache.get('failed_login_ip:{}'.format(current_ip)) + + # brute force by ip + if login_failed_ip: + login_failed_ip = int(login_failed_ip) + if login_failed_ip >= 5: + error = 'Max Connection Attempts reached, Please wait {}s'.format(r_cache.ttl('failed_login_ip:{}'.format(current_ip))) + return render_template("login.html", error=error) + ''' + + if request.method == 'POST': + username = request.form.get('username') + password = request.form.get('password') + #next_page = request.form.get('next_page') + + if username is not None: + user = User.get(username) + ''' + login_failed_user_id = r_cache.get('failed_login_user_id:{}'.format(username)) + # brute force by user_id + if login_failed_user_id: + login_failed_user_id = int(login_failed_user_id) + if login_failed_user_id >= 5: + error = 'Max Connection Attempts reached, Please wait {}s'.format(r_cache.ttl('failed_login_user_id:{}'.format(username))) + return render_template("login.html", error=error) + ''' + + if user and user.check_password(password): + #if not check_user_role_integrity(user.get_id()): + # error = 'Incorrect User ACL, Please contact your administrator' + # return render_template("login.html", error=error) + login_user(user) ## TODO: use remember me ? + if user.request_password_change(): + return redirect(url_for('change_password')) + else: + return redirect(url_for('index')) + # login failed + else: + # set brute force protection + #logger.warning("Login failed, ip={}, username={}".format(current_ip, username)) + #r_cache.incr('failed_login_ip:{}'.format(current_ip)) + #r_cache.expire('failed_login_ip:{}'.format(current_ip), 300) + #r_cache.incr('failed_login_user_id:{}'.format(username)) + #r_cache.expire('failed_login_user_id:{}'.format(username), 300) + # + + error = 'Password Incorrect' + return render_template("login.html", error=error) + + return 'please provide a valid username' + + else: + #next_page = request.args.get('next') + error = request.args.get('error') + return render_template("login.html" , error=error) + +@app.route('/change_password', methods=['POST', 'GET']) +@login_required +def change_password(): + password1 = request.form.get('password1') + password2 = request.form.get('password2') + error = request.args.get('error') + + if error: + return render_template("change_password.html", error=error) + + if current_user.is_authenticated and password1!=None: + if password1==password2: + if check_password_strength(password1): + user_id = current_user.get_id() + create_user_db(user_id , password1, update=True) + return redirect(url_for('index')) + else: + error = 'Incorrect password' + return render_template("change_password.html", error=error) + else: + error = "Passwords don't match" + return render_template("change_password.html", error=error) + else: + error = 'Please choose a new password' + return render_template("change_password.html", error=error) + +@app.route('/logout') +@login_required +def logout(): + logout_user() + return redirect(url_for('login')) + +# role error template +@app.route('/role', methods=['POST', 'GET']) +@login_required +def role(): + return render_template("error/403.html"), 403 + @app.route('/test') def test(): return 'test' @app.route('/') +@login_required def index(): date = datetime.datetime.now().strftime("%Y/%m/%d") return render_template("index.html", date=date) @app.route('/_json_daily_uuid_stats') +@login_required def _json_daily_uuid_stats(): date = datetime.datetime.now().strftime("%Y%m%d") daily_uuid = redis_server_metadata.zrange('daily_uuid:{}'.format(date), 0, -1, withscores=True) @@ -219,6 +378,7 @@ def _json_daily_uuid_stats(): return jsonify(data_daily_uuid) @app.route('/_json_daily_type_stats') +@login_required def _json_daily_type_stats(): date = datetime.datetime.now().strftime("%Y%m%d") daily_uuid = redis_server_metadata.zrange('daily_type:{}'.format(date), 0, -1, withscores=True) @@ -235,6 +395,7 @@ def _json_daily_type_stats(): return jsonify(data_daily_uuid) @app.route('/sensors_status') +@login_required def sensors_status(): active_connection_filter = request.args.get('active_connection_filter') if active_connection_filter is None: @@ -314,6 +475,7 @@ def sensors_status(): active_connection_filter=active_connection_filter) @app.route('/show_active_uuid') +@login_required def show_active_uuid(): #swap switch value active_connection_filter = request.args.get('show_active_connection') @@ -328,6 +490,7 @@ def show_active_uuid(): return redirect(url_for('sensors_status', active_connection_filter=active_connection_filter)) @app.route('/server_management') +@login_required def server_management(): blacklisted_ip = request.args.get('blacklisted_ip') unblacklisted_ip = request.args.get('unblacklisted_ip') @@ -398,6 +561,7 @@ def server_management(): blacklisted_uuid=blacklisted_uuid, unblacklisted_uuid=unblacklisted_uuid) @app.route('/uuid_management') +@login_required def uuid_management(): uuid_sensor = request.args.get('uuid') if is_valid_uuid_v4(uuid_sensor): @@ -470,6 +634,7 @@ def uuid_management(): return 'Invalid uuid' @app.route('/blacklisted_ip') +@login_required def blacklisted_ip(): blacklisted_ip = request.args.get('blacklisted_ip') unblacklisted_ip = request.args.get('unblacklisted_ip') @@ -495,6 +660,7 @@ def blacklisted_ip(): unblacklisted_ip=unblacklisted_ip, blacklisted_ip=blacklisted_ip) @app.route('/blacklisted_uuid') +@login_required def blacklisted_uuid(): blacklisted_uuid = request.args.get('blacklisted_uuid') unblacklisted_uuid = request.args.get('unblacklisted_uuid') @@ -521,6 +687,7 @@ def blacklisted_uuid(): @app.route('/uuid_change_stream_max_size') +@login_required def uuid_change_stream_max_size(): uuid_sensor = request.args.get('uuid') user = request.args.get('redirect') @@ -539,6 +706,7 @@ def uuid_change_stream_max_size(): return 'Invalid uuid' @app.route('/uuid_change_description') +@login_required def uuid_change_description(): uuid_sensor = request.args.get('uuid') description = request.args.get('description') @@ -550,6 +718,7 @@ def uuid_change_description(): # # TODO: check analyser uuid dont exist @app.route('/add_new_analyzer') +@login_required def add_new_analyzer(): type = request.args.get('type') user = request.args.get('redirect') @@ -576,6 +745,7 @@ def add_new_analyzer(): return 'Invalid uuid' @app.route('/empty_analyzer_queue') +@login_required def empty_analyzer_queue(): analyzer_uuid = request.args.get('analyzer_uuid') type = request.args.get('type') @@ -598,6 +768,7 @@ def empty_analyzer_queue(): return 'Invalid uuid' @app.route('/remove_analyzer') +@login_required def remove_analyzer(): analyzer_uuid = request.args.get('analyzer_uuid') type = request.args.get('type') @@ -623,6 +794,7 @@ def remove_analyzer(): return 'Invalid uuid' @app.route('/analyzer_change_max_size') +@login_required def analyzer_change_max_size(): analyzer_uuid = request.args.get('analyzer_uuid') user = request.args.get('redirect') @@ -641,6 +813,7 @@ def analyzer_change_max_size(): return 'Invalid uuid' @app.route('/kick_uuid') +@login_required def kick_uuid(): uuid_sensor = request.args.get('uuid') if is_valid_uuid_v4(uuid_sensor): @@ -650,6 +823,7 @@ def kick_uuid(): return 'Invalid uuid' @app.route('/blacklist_uuid') +@login_required def blacklist_uuid(): uuid_sensor = request.args.get('uuid') user = request.args.get('redirect') @@ -670,6 +844,7 @@ def blacklist_uuid(): return 'Invalid uuid' @app.route('/unblacklist_uuid') +@login_required def unblacklist_uuid(): uuid_sensor = request.args.get('uuid') user = request.args.get('redirect') @@ -693,6 +868,7 @@ def unblacklist_uuid(): return 'Invalid uuid' @app.route('/blacklist_ip') +@login_required def blacklist_ip(): ip = request.args.get('ip') user = request.args.get('redirect') @@ -718,6 +894,7 @@ def blacklist_ip(): return 'Invalid ip' @app.route('/unblacklist_ip') +@login_required def unblacklist_ip(): ip = request.args.get('ip') user = request.args.get('redirect') @@ -745,6 +922,7 @@ def unblacklist_ip(): return 'Invalid ip' @app.route('/blacklist_ip_by_uuid') +@login_required def blacklist_ip_by_uuid(): uuid_sensor = request.args.get('uuid') user = request.args.get('redirect') @@ -756,6 +934,7 @@ def blacklist_ip_by_uuid(): return 'Invalid uuid' @app.route('/unblacklist_ip_by_uuid') +@login_required def unblacklist_ip_by_uuid(): uuid_sensor = request.args.get('uuid') user = request.args.get('redirect') @@ -767,6 +946,7 @@ def unblacklist_ip_by_uuid(): return 'Invalid uuid' @app.route('/add_accepted_type') +@login_required def add_accepted_type(): type = request.args.get('type') extended_type_name = request.args.get('extended_type_name') @@ -786,6 +966,7 @@ def add_accepted_type(): return 'Invalid type' @app.route('/remove_accepted_type') +@login_required def remove_accepted_type(): type = request.args.get('type') user = request.args.get('redirect') @@ -798,6 +979,7 @@ def remove_accepted_type(): return 'Invalid type' @app.route('/remove_accepted_extended_type') +@login_required def remove_accepted_extended_type(): type_name = request.args.get('type_name') redis_server_metadata.srem('server:accepted_extended_type', type_name) @@ -805,6 +987,7 @@ def remove_accepted_extended_type(): # demo function @app.route('/delete_data') +@login_required def delete_data(): date = datetime.datetime.now().strftime("%Y%m%d") redis_server_metadata.delete('daily_type:{}'.format(date)) @@ -813,6 +996,7 @@ def delete_data(): # demo function @app.route('/set_uuid_hmac_key') +@login_required def set_uuid_hmac_key(): uuid_sensor = request.args.get('uuid') user = request.args.get('redirect') @@ -824,6 +1008,7 @@ def set_uuid_hmac_key(): # demo function @app.route('/whois_data') +@login_required def whois_data(): ip = request.args.get('ip') if is_valid_ip: @@ -832,11 +1017,13 @@ def whois_data(): return 'Invalid IP' @app.route('/generate_uuid') +@login_required def generate_uuid(): new_uuid = uuid.uuid4() return jsonify({'uuid': new_uuid}) @app.route('/get_analyser_sample') +@login_required def get_analyser_sample(): type = request.args.get('type') analyzer_uuid = request.args.get('analyzer_uuid') @@ -864,6 +1051,7 @@ def get_analyser_sample(): return jsonify('Incorrect UUID') @app.route('/get_uuid_type_history_json') +@login_required def get_uuid_type_history_json(): uuid_sensor = request.args.get('uuid_sensor') if is_valid_uuid_v4(uuid_sensor): @@ -894,6 +1082,7 @@ def get_uuid_type_history_json(): return jsonify('Incorrect UUID') @app.route('/get_uuid_stats_history_json') +@login_required def get_uuid_stats_history_json(): uuid_sensor = request.args.get('uuid_sensor') stats = request.args.get('stats') @@ -925,4 +1114,4 @@ def get_uuid_stats_history_json(): if __name__ == "__main__": - app.run(host='0.0.0.0', port=7000, threaded=True) + app.run(host='0.0.0.0', port=7000, threaded=True, ssl_context=ssl_context) diff --git a/server/web/Role_Manager.py b/server/web/Role_Manager.py new file mode 100644 index 0000000..48c1eee --- /dev/null +++ b/server/web/Role_Manager.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +# -*-coding:UTF-8 -* + +import os +import re +import redis +import bcrypt + +from functools import wraps +from flask_login import LoginManager, current_user, login_user, logout_user, login_required + +from flask import request, current_app + +login_manager = LoginManager() +login_manager.login_view = 'role' + +host_redis_metadata = os.getenv('D4_REDIS_METADATA_HOST', "localhost") +port_redis_metadata = int(os.getenv('D4_REDIS_METADATA_PORT', 6380)) + +r_serv_db = redis.StrictRedis( + host=host_redis_metadata, + port=port_redis_metadata, + db=1, + decode_responses=True) + +default_passwd_file = os.path.join(os.environ['D4_HOME'], 'DEFAULT_PASSWORD') + +regex_password = r'^(?=(.*\d){2})(?=.*[a-z])(?=.*[A-Z]).{10,100}$' +regex_password = re.compile(regex_password) + +############################################################### +############### CHECK ROLE ACCESS ################## +############################################################### + +def login_admin(func): + @wraps(func) + def decorated_view(*args, **kwargs): + if not current_user.is_authenticated: + return login_manager.unauthorized() + elif (not current_user.is_in_role('admin')): + return login_manager.unauthorized() + return func(*args, **kwargs) + return decorated_view + +def login_analyst(func): + @wraps(func) + def decorated_view(*args, **kwargs): + if not current_user.is_authenticated: + return login_manager.unauthorized() + elif (not current_user.is_in_role('analyst')): + return login_manager.unauthorized() + return func(*args, **kwargs) + return decorated_view + + + +############################################################### +############################################################### +############################################################### + +def gen_password(length=30, charset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_!@#$%^&*()"): + random_bytes = os.urandom(length) + len_charset = len(charset) + indices = [int(len_charset * (byte / 256.0)) for byte in random_bytes] + return "".join([charset[index] for index in indices]) + +def gen_token(length=41, charset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"): + random_bytes = os.urandom(length) + len_charset = len(charset) + indices = [int(len_charset * (byte / 256.0)) for byte in random_bytes] + return "".join([charset[index] for index in indices]) + +def generate_new_token(user_id): + # create user token + current_token = r_serv_db.hget('user_metadata:{}'.format(user_id), 'token') + if current_token: + r_serv_db.hdel('user:tokens', current_token) + token = gen_token(41) + r_serv_db.hset('user:tokens', token, user_id) + r_serv_db.hset('user_metadata:{}'.format(user_id), 'token', token) + +def get_default_admin_token(): + if r_serv_db.exists('user_metadata:admin@admin.test'): + return r_serv_db.hget('user_metadata:admin@admin.test', 'token') + else: + return '' + +def create_user_db(username_id , password, default=False, role=None, update=False): + password = password.encode() + password_hash = hashing_password(password) + + # create user token + generate_new_token(username_id) + + if update: + r_serv_db.hdel('user_metadata:{}'.format(username_id), 'change_passwd') + # remove default user password file + if username_id=='admin@admin.test': + os.remove(default_passwd_file) + else: + if default: + r_serv_db.hset('user_metadata:{}'.format(username_id), 'change_passwd', 'True') + if role: + if role in get_all_role(): + for role_to_add in get_all_user_role(role): + r_serv_db.sadd('user_role:{}'.format(role_to_add), username_id) + r_serv_db.hset('user_metadata:{}'.format(username_id), 'role', role) + + r_serv_db.hset('user:all', username_id, password_hash) + +def edit_user_db(user_id, role, password=None): + if password: + password_hash = hashing_password(password.encode()) + r_serv_db.hset('user:all', user_id, password_hash) + + current_role = r_serv_db.hget('user_metadata:{}'.format(user_id), 'role') + if role != current_role: + request_level = get_role_level(role) + current_role = get_role_level(current_role) + + if current_role < request_level: + role_to_remove = get_user_role_by_range(current_role -1, request_level - 2) + for role_id in role_to_remove: + r_serv_db.srem('user_role:{}'.format(role_id), user_id) + r_serv_db.hset('user_metadata:{}'.format(user_id), 'role', role) + else: + role_to_add = get_user_role_by_range(request_level -1, current_role) + for role_id in role_to_add: + r_serv_db.sadd('user_role:{}'.format(role_id), user_id) + r_serv_db.hset('user_metadata:{}'.format(user_id), 'role', role) + +def delete_user_db(user_id): + if r_serv_db.exists('user_metadata:{}'.format(user_id)): + role_to_remove =get_all_role() + for role_id in role_to_remove: + r_serv_db.srem('user_role:{}'.format(role_id), user_id) + user_token = r_serv_db.hget('user_metadata:{}'.format(user_id), 'token') + r_serv_db.hdel('user:tokens', user_token) + r_serv_db.delete('user_metadata:{}'.format(user_id)) + r_serv_db.hdel('user:all', user_id) + +def hashing_password(bytes_password): + hashed = bcrypt.hashpw(bytes_password, bcrypt.gensalt()) + return hashed + +def check_password_strength(password): + result = regex_password.match(password) + if result: + return True + else: + return False + +def get_all_role(): + return r_serv_db.zrange('d4:all_role', 0, -1) + +def get_role_level(role): + return int(r_serv_db.zscore('d4:all_role', role)) + +def get_all_user_role(user_role): + current_role_val = get_role_level(user_role) + return r_serv_db.zrange('d4:all_role', current_role_val -1, -1) + +def get_all_user_upper_role(user_role): + current_role_val = get_role_level(user_role) + # remove one rank + if current_role_val > 1: + return r_serv_db.zrange('d4:all_role', 0, current_role_val -2) + else: + return [] + +def get_user_role_by_range(inf, sup): + return r_serv_db.zrange('d4:all_role', inf, sup) + +def get_user_role(user_id): + return r_serv_db.hget('user_metadata:{}'.format(user_id), 'role') + +def check_user_role_integrity(user_id): + user_role = get_user_role(user_id) + all_user_role = get_all_user_role(user_role) + res = True + if user_role not in all_user_role: + return False + return res diff --git a/server/web/create_default_user.py b/server/web/create_default_user.py new file mode 100755 index 0000000..fdb5dbf --- /dev/null +++ b/server/web/create_default_user.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# -*-coding:UTF-8 -* + +import os +import sys +import redis +import configparser + +sys.path.append(os.path.join(os.environ['D4_HOME'], 'lib')) + +from Role_Manager import create_user_db, edit_user_db, get_default_admin_token, gen_password + +host_redis_metadata = os.getenv('D4_REDIS_METADATA_HOST', "localhost") +port_redis_metadata = int(os.getenv('D4_REDIS_METADATA_HOST', 6380)) + +r_serv = redis.StrictRedis( + host=host_redis_metadata, + port=port_redis_metadata, + db=1, + decode_responses=True) + + +if __name__ == "__main__": + + # create role_list + if not r_serv.exists('d4:all_role'): + role_dict = {'admin': 1, 'user': 1, 'sensor_register': 20} + r_serv.zadd('d4:all_role', role_dict) + + username = 'admin@admin.test' + password = gen_password() + if r_serv.exists('user_metadata:admin@admin.test'): + edit_user_db(username, password=password, role='admin') + else: + create_user_db(username, password, role='admin', default=True) + token = get_default_admin_token() + + default_passwd_file = os.path.join(os.environ['D4_HOME'], 'DEFAULT_PASSWORD') + to_write_str = '# Password Generated by default\n# This file is deleted after the first login\n#\nemail=admin@admin.test\npassword=' + to_write_str = to_write_str + password + '\nAPI_Key=' + token + with open(default_passwd_file, 'w') as f: + f.write(to_write_str) + + print('new user created: {}'.format(username)) + print('password: {}'.format(password)) + print('token: {}'.format(token)) diff --git a/server/web/templates/403.html b/server/web/templates/403.html new file mode 100644 index 0000000..ed335bf --- /dev/null +++ b/server/web/templates/403.html @@ -0,0 +1,67 @@ + + + + + 403 - D4-Project + + + + + + + + + + + +
+
+
+

403 Forbidden

+
+
+
+
+
+
+
+                                  ,d8       ,a8888a,     ad888888b,
+                                ,d888     ,8P"'  `"Y8,  d8"     "88
+                              ,d8" 88    ,8P        Y8,         a8P
+                            ,d8"   88    88          88      aad8"
+                          ,d8"     88    88          88      ""Y8,
+                          8888888888888  `8b        d8'         "8b
+                                   88     `8ba,  ,ad8'  Y8,     a88
+                                   88       "Y8888P"     "Y888888P'
+
+88888888888                       88           88           88           88
+88                                88           ""           88           88
+88                                88                        88           88
+88aaaaa   ,adPPYba,   8b,dPPYba,  88,dPPYba,   88   ,adPPYb,88   ,adPPYb,88   ,adPPYba,  8b,dPPYba,
+88"""""  a8"     "8a  88P'   "Y8  88P'    "8a  88  a8"    `Y88  a8"    `Y88  a8P_____88  88P'   `"8a
+88       8b       d8  88          88       d8  88  8b       88  8b       88  8PP"""""""  88       88
+88       "8a,   ,a8"  88          88b,   ,a8"  88  "8a,   ,d88  "8a,   ,d88  "8b,   ,aa  88       88
+88        `"YbbdP"'   88          8Y"Ybbd8"'   88   `"8bbdP"Y8   `"8bbdP"Y8   `"Ybbd8"'  88       88
+
+
+ +{% include 'navfooter.html' %} + + + + diff --git a/server/web/templates/change_password.html b/server/web/templates/change_password.html new file mode 100644 index 0000000..e3ec673 --- /dev/null +++ b/server/web/templates/change_password.html @@ -0,0 +1,108 @@ + + + + + + D4-Project + + + + + + + + + + + + + + + + + +
+ +

Change Password

+ + + + + {% if error %} +
+ {{error}} +
+ {% endif %} + + +
+
+
+
Password Requirements
+ + +
+ + + diff --git a/server/web/templates/login.html b/server/web/templates/login.html new file mode 100644 index 0000000..b54c290 --- /dev/null +++ b/server/web/templates/login.html @@ -0,0 +1,85 @@ + + + + + + D4-Project + + + + + + + + + + + + + + + + + +
+ +

Please sign in

+ + + + + {% if error %} +
+ {{error}} +
+ {% endif %} + +
+ + +