diff --git a/OVERVIEW.md b/OVERVIEW.md index 5d6dbc99..ecf16bf3 100644 --- a/OVERVIEW.md +++ b/OVERVIEW.md @@ -52,6 +52,18 @@ Redis and ARDB overview | ail:current_background_script | **name of the background script currently executed** | | ail:current_background_script_stat | **progress in % of the background script** | +##### User Management: +| Key | Field | Value | +| ------ | ------ | ------ | +| user:all | **user id** | **password hash** | + +| Key | Value | +| ------ | ------ | +| user:request_password_change | **user id** | +| user:admin | **user id** | +| | | +| user_role:**role** | **user id** | + ## DB2 - TermFreq: ##### Set: diff --git a/bin/packages/User.py b/bin/packages/User.py index b46069f1..3dfe31a5 100755 --- a/bin/packages/User.py +++ b/bin/packages/User.py @@ -1,36 +1,65 @@ #!/usr/bin/env python3 # -*-coding:UTF-8 -* +import os import redis +import bcrypt +import configparser from flask_login import UserMixin class User(UserMixin): def __init__(self, id): - self.id = 'abcdef' + + configfile = os.path.join(os.environ['AIL_BIN'], 'packages/config.cfg') + if not os.path.exists(configfile): + raise Exception('Unable to find the configuration file. \ + Did you set environment variables? \ + Or activate the virtualenv.') + + cfg = configparser.ConfigParser() + cfg.read(configfile) + + self.r_serv_db = redis.StrictRedis( + host=cfg.get("ARDB_DB", "host"), + port=cfg.getint("ARDB_DB", "port"), + db=cfg.getint("ARDB_DB", "db"), + 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_active(): - # return True or False #def is_anonymous(): @classmethod def get(self_class, id): - print(id) return self_class(id) def check_password(self, password): + password = password.encode() print(self.id) - if password=='admin': - print('password ok') + hashed_password = self.r_serv_db.hget('user:all', self.id).encode() + if bcrypt.checkpw(password, hashed_password): + print('password correct') return True else: return False - def set_password(self): - return True + def request_password_change(self): + if self.r_serv_db.sismember('user:request_password_change', self.id): + 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/pip3_packages_requirement.txt b/pip3_packages_requirement.txt index 4f9d1f87..4f5372bc 100644 --- a/pip3_packages_requirement.txt +++ b/pip3_packages_requirement.txt @@ -47,6 +47,7 @@ texttable flask flask-login +bcrypt #DomainClassifier DomainClassifier diff --git a/var/www/Flask_server.py b/var/www/Flask_server.py index 907f1fd4..a689089f 100755 --- a/var/www/Flask_server.py +++ b/var/www/Flask_server.py @@ -11,6 +11,8 @@ import calendar from flask import Flask, render_template, jsonify, request, Request, session, redirect, url_for from flask_login import LoginManager, current_user, login_user, logout_user, login_required +import bcrypt + import flask import importlib import os @@ -28,6 +30,41 @@ from pytaxonomies import Taxonomies # Import config import Flask_config +def flask_init(): + int_user_management() + +def int_user_management(): + # # TODO: check for admin account + # check if an account exists + if not r_serv_db.hexists('user:all'): + password = 'admin@admin.test' + create_user_db('admin', password, default=True) + +def hashing_password(bytes_password): + hashed = bcrypt.hashpw(bytes_password, bcrypt.gensalt()) + return hashed + +def verify_password(id, bytes_password): + hashed_password = r_serv_db.hget('user:all', id) + if bcrypt.checkpw(password, hashed): + return True + else: + return False + +def create_user_db(username_id , password, default=False): + ## TODO: validate username + ## TODO: validate password + + if username_id == '__anonymous__': + ## TODO: return 500 + return 'ERROR' + + password = password.encode() + password_hash = hashing_password(password) + r_serv_db.hset('user:all', username_id, password_hash) + if default: + r_serv_db.set('user:request_password_change', username_id) + # CONFIG # cfg = Flask_config.cfg baseUrl = cfg.get("Flask", "baseurl") @@ -35,6 +72,20 @@ baseUrl = baseUrl.replace('/', '') if baseUrl != '': baseUrl = '/'+baseUrl +# ========= REDIS =========# +r_serv_db = redis.StrictRedis( + host=cfg.get("ARDB_DB", "host"), + port=cfg.getint("ARDB_DB", "port"), + db=cfg.getint("ARDB_DB", "db"), + decode_responses=True) +r_serv_tags = redis.StrictRedis( + host=cfg.get("ARDB_Tags", "host"), + port=cfg.getint("ARDB_Tags", "port"), + db=cfg.getint("ARDB_Tags", "db"), + decode_responses=True) + +# ========= =========# + Flask_config.app = Flask(__name__, static_url_path=baseUrl+'/static/') app = Flask_config.app app.config['MAX_CONTENT_LENGTH'] = 900 * 1024 * 1024 @@ -152,6 +203,8 @@ def login(): #print(user.is_authenticated) if user and user.check_password(password): login_user(user) ## TODO: use remember me ? + #print(user.request_password_change()) + print(user.is_active) return redirect(url_for('dashboard.index')) else: return 'incorrect password' @@ -167,7 +220,27 @@ def login(): @login_required def logout(): logout_user() - return redirect(url_for('dashboard.index')) + return redirect(url_for('login')) + +@app.route('/create_user') +@login_required +def create_user(): + username = request.form.get('username') + password = request.form.get('password') + #role = request.form.get('role') ## TODO: create role + + ## TODO: validate username + ## TODO: validate password + + username = 'admin@admin.test' + password = 'admin' + + if r_serv_db.hexists('user:all', username): + return 'this id is not available' + + create_user_db(username, password) + + return 'True' @app.route('/searchbox/') @@ -176,11 +249,6 @@ def searchbox(): # ========== INITIAL taxonomies ============ -r_serv_tags = redis.StrictRedis( - host=cfg.get("ARDB_Tags", "host"), - port=cfg.getint("ARDB_Tags", "port"), - db=cfg.getint("ARDB_Tags", "db"), - decode_responses=True) # add default ail taxonomies r_serv_tags.sadd('active_taxonomies', 'infoleak') r_serv_tags.sadd('active_taxonomies', 'gdpr') @@ -195,11 +263,6 @@ for tag in taxonomies.get('fpf').machinetags(): r_serv_tags.sadd('active_tag_fpf', tag) # ========== INITIAL tags auto export ============ -r_serv_db = redis.StrictRedis( - host=cfg.get("ARDB_DB", "host"), - port=cfg.getint("ARDB_DB", "port"), - db=cfg.getint("ARDB_DB", "db"), - decode_responses=True) infoleak_tags = taxonomies.get('infoleak').machinetags() infoleak_automatic_tags = [] for tag in taxonomies.get('infoleak').machinetags(): diff --git a/var/www/modules/Decorator.py b/var/www/modules/Decorator.py new file mode 100644 index 00000000..c1ab7755 --- /dev/null +++ b/var/www/modules/Decorator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*-coding:UTF-8 -* + +from functools import wraps +from flask_login import LoginManager, current_user, login_user, logout_user, login_required + +from flask import request + +def login_required(role="ANY"): + @wraps(role) + def decorated_view(*args, **kwargs): + if not current_user.is_authenticated: + return current_app.login_manager.unauthorized() + elif (not current_user.is_in_role(role)) and (role != "ANY"): + return login_manager.unauthorized() + return func(*args, **kwargs) + return decorated_view diff --git a/var/www/modules/dashboard/Flask_dashboard.py b/var/www/modules/dashboard/Flask_dashboard.py index 7ebf6747..0bbcccac 100644 --- a/var/www/modules/dashboard/Flask_dashboard.py +++ b/var/www/modules/dashboard/Flask_dashboard.py @@ -13,6 +13,7 @@ import flask from Date import Date from flask import Flask, render_template, jsonify, request, Blueprint, url_for +from flask_login import login_required # ============ VARIABLES ============ import Flask_config @@ -109,10 +110,12 @@ def datetime_from_utc_to_local(utc_str): # ============ ROUTES ============ @dashboard.route("/_logs") +@login_required def logs(): return flask.Response(event_stream(), mimetype="text/event-stream") @dashboard.route("/_get_last_logs_json") +@login_required def get_last_logs_json(): date = datetime.datetime.now().strftime("%Y%m%d") @@ -154,11 +157,13 @@ def get_last_logs_json(): @dashboard.route("/_stuff", methods=['GET']) +@login_required def stuff(): return jsonify(row1=get_queues(r_serv)) @dashboard.route("/") +@login_required def index(): default_minute = cfg.get("Flask", "minute_processed_paste") threshold_stucked_module = cfg.getint("Module_ModuleInformation", "threshold_stucked_module") diff --git a/var/www/modules/hiddenServices/Flask_hiddenServices.py b/var/www/modules/hiddenServices/Flask_hiddenServices.py index 76c61667..42b36006 100644 --- a/var/www/modules/hiddenServices/Flask_hiddenServices.py +++ b/var/www/modules/hiddenServices/Flask_hiddenServices.py @@ -17,6 +17,8 @@ from flask_login import login_required from Date import Date from HiddenServices import HiddenServices +from Decorator import login_required + # ============ VARIABLES ============ import Flask_config @@ -35,6 +37,7 @@ list_types=['onion', 'regular'] dic_type_name={'onion':'Onion', 'regular':'Website'} # ============ FUNCTIONS ============ + def one(): return 1 @@ -233,6 +236,7 @@ def delete_auto_crawler(url): # ============= ROUTES ============== @hiddenServices.route("/crawlers/", methods=['GET']) +#@login_required(role="ADMIN") @login_required def dashboard(): crawler_metadata_onion = get_crawler_splash_status('onion')