def route(page): endpoint, *args = page.split("/") admin_user = current_user.is_admin if f"/{endpoint}" not in app.rbac["post_requests"]: return jsonify({"alert": "Invalid POST request."}) if not admin_user and f"/{endpoint}" not in current_user.post_requests: return jsonify({"alert": "Error 403 - Operation not allowed."}) form_type = request.form.get("form_type") if request.json: kwargs = request.json elif form_type: form = form_classes[form_type](request.form) if not form.validate_on_submit(): return jsonify({ "invalid_form": True, **{ "errors": form.errors } }) kwargs = form.form_postprocessing(request.form) else: kwargs = request.form try: with db.session_scope(): result = getattr(app, endpoint)(*args, **kwargs) except db.rbac_error: result = {"alert": "Error 403 - Operation not allowed."} except Exception: app.log("error", format_exc(), change_log=False) result = {"alert": "Error 500 - Internal Server Error"} return jsonify(result)
def login(): if request.method == "POST": kwargs, success = request.form.to_dict(), False username = kwargs["name"] try: user = app.authenticate_user(**kwargs) if user: login_user(user, remember=False) session.permanent = True success, log = True, f"User '{username}' logged in" else: log = f"Authentication failed for user '{username}'" except Exception as exc: log = f"Authentication error for user '{username}' ({exc})" finally: app.log("info" if success else "warning", log, logger="security") if success: return redirect( url_for("blueprint.route", page="dashboard")) else: abort(403) if not current_user.is_authenticated: login_form = LoginForm(request.form) methods = app.settings["authentication"]["methods"].items() login_form.authentication_method.choices = [ (method, properties["display_name"]) for method, properties in methods if properties["enabled"] ] return render_template("login.html", login_form=login_form) return redirect(url_for("blueprint.route", page="dashboard"))
def decorated_function(*args, **kwargs): path, method = request.path, request.method if not current_user.is_authenticated: client_address = request.environ.get( "HTTP_X_FORWARDED_FOR", request.environ["REMOTE_ADDR"] ) app.log( "warning", ( f"Unauthorized {request.method} request from " f"'{client_address}' calling the endpoint '{request.url}'" ), ) return redirect(url_for("blueprint.route", page="login")) else: endpoint = path if method == "GET" else f"/{path.split('/')[1]}" if endpoint not in app.rbac["endpoints"][method]: if method == "GET": return render_template("error.html", error=404), 404 else: return jsonify({"alert": "Invalid POST request."}) forbidden_endpoints = app.rbac["groups"][current_user.group][method] if any(url == endpoint for url in forbidden_endpoints): if method == "GET": return render_template("error.html", error=403), 403 else: return jsonify({"alert": "Error 403 Forbidden."}) return function(*args, **kwargs)
def remove_changelog(keep_last_days): deletion_time = datetime.now() - timedelta(days=keep_last_days) app.result_log_deletion( date_time=deletion_time.strftime("%d/%m/%Y %H:%M:%S"), deletion_types=["changelog"], ) app.log("info", f"deleted all changelogs up until {deletion_time}")
def delete_log(keep_last_days, log): deletion_time = datetime.now() - timedelta(days=keep_last_days) app.result_log_deletion( date_time=deletion_time.strftime("%d/%m/%Y %H:%M:%S"), deletion_types=[log], ) app.log("info", f"deleted all logs in '{log}' up until {deletion_time}")
def decorated_function(*args, **kwargs): if not current_user.is_authenticated: client_address = request.environ.get( "HTTP_X_FORWARDED_FOR", request.environ["REMOTE_ADDR"]) app.log( "warning", (f"Unauthorized {request.method} request from " f"'{client_address}' calling the endpoint '{request.url}'"), ) return redirect(url_for("blueprint.route", page="login")) else: return function(*args, **kwargs)
def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except LookupError as exc: rest_abort(404, message=str(exc)) except Exception as exc: rest_abort(500, message=str(exc)) finally: try: db.session.commit() except Exception as exc: db.session.rollback() app.log("error", format_exc()) rest_abort(500, message=str(exc))
def decorated_function(*args, **kwargs): if not current_user.is_authenticated: client_address = request.environ.get( "HTTP_X_FORWARDED_FOR", request.environ["REMOTE_ADDR"]) app.log( "warning", (f"Unauthorized {request.method} request from " f"'{client_address}' calling the endpoint '{request.url}'"), ) return redirect(url_for("blueprint.route", page="login")) else: forbidden_endpoints = app.rbac["groups"][current_user.group]["GET"] if request.method == "GET" and request.path in forbidden_endpoints: return render_template("error.html", error=403), 403 return function(*args, **kwargs)
def wrapper(*args, **kwargs): for index in range(db.retry_commit_number): try: result = func(*args, **kwargs) except Exception as exc: return rest_abort(500, message=str(exc)) try: db.session.commit() return result except Exception as exc: db.session.rollback() app.log("error", f"Rest Call n°{index} failed ({exc}).") stacktrace = format_exc() sleep(db.retry_commit_time * (index + 1)) else: rest_abort(500, message=stacktrace)
def register_plugins(self): for plugin in Path(app.settings["app"]["plugin_path"]).iterdir(): if not Path(plugin / "settings.json").exists(): continue module = import_module(f"eNMS.plugins.{plugin.stem}") with open(plugin / "settings.json", "r") as file: settings = load(file) if not settings["active"]: continue plugin = module.Plugin(self, app, db, **settings) if "rbac" in settings: for requests in ("get_requests", "post_requests"): app.rbac[requests].extend(settings["rbac"].get(requests, [])) app.rbac["menu"]["Plugins"]["pages"].update(settings.get("pages", {})) init_rbac_form(app.rbac) app.log("info", f"Loading plugin: {settings['name']}")
def register_plugins(self): for plugin_path in Path(app.settings["app"]["plugin_path"]).iterdir(): if not Path(plugin_path / "settings.json").exists(): continue try: with open(plugin_path / "settings.json", "r") as file: settings = load(file) if not settings["active"]: continue module = import_module(f"eNMS.plugins.{plugin_path.stem}") module.Plugin(self, app, db, **settings) for setup_file in ("database", "properties", "rbac"): update_file(getattr(app, setup_file), settings.get(setup_file, {})) except Exception as exc: app.log("error", f"Could not load plugin '{plugin_path.stem}' ({exc})") continue app.log("info", f"Loading plugin: {settings['name']}") init_variable_forms(app) db.base.metadata.create_all(bind=db.engine)
def decorated_function(*args, **kwargs): if not current_user.is_authenticated: client_address = request.environ.get( "HTTP_X_FORWARDED_FOR", request.environ["REMOTE_ADDR"] ) app.log( "warning", ( f"Unauthorized {request.method} request from " f"'{client_address}' calling the endpoint '{request.url}'" ), ) return redirect(url_for("blueprint.route", page="login")) else: method = request.method.lower() endpoint = f"/{request.path.split('/')[1]}" endpoint_rbac = app.rbac[f"{method}_requests"].get(endpoint) if not endpoint_rbac: error = 404 elif not current_user.is_admin and ( endpoint_rbac == "admin" or endpoint_rbac == "access" and endpoint not in getattr(current_user, f"{method}_requests") ): error = 403 else: try: return function(*args, **kwargs) except db.rbac_error: error = 403 except Exception: error = 500 app.log("error", format_exc(), change_log=False) if method == "get": return render_template("error.html", error=error), error else: message = { 403: "Operation not allowed.", 404: "Invalid POST request.", 500: "Internal Server Error.", }[error] return jsonify({"alert": f"Error {error} - {message}"})
def login(): if request.method == "POST": try: user = app.authenticate_user(**request.form.to_dict()) if user: login_user(user) return redirect( url_for("blueprint.route", page="dashboard")) else: abort(403) except Exception as exc: app.log("error", f"Authentication failed ({exc})") abort(403) if not current_user.is_authenticated: login_form = LoginForm(request.form) authentication_methods = [] if app.settings["ldap"]["active"]: authentication_methods.append(("LDAP Domain", ) * 2) if app.settings["tacacs"]["active"]: authentication_methods.append(("TACACS", ) * 2) authentication_methods.append(("Local User", ) * 2) login_form.authentication_method.choices = authentication_methods return render_template("login.html", login_form=login_form) return redirect(url_for("blueprint.route", page="dashboard"))
def logout(): logout_log = f"User '{current_user.name}' logging out" app.log("info", logout_log, logger="security") logout_user() return redirect(url_for("blueprint.route", page="login"))
def test_create_logs(user_client): number_of_logs = len(db.fetch_all("changelog")) for i in range(10): app.log("warning", str(i)) db.session.commit() assert len(db.fetch_all("changelog")) == number_of_logs + 11
def test_create_logs(user_client: FlaskClient) -> None: number_of_logs = len(fetch_all("Changelog")) for i in range(10): app.log("warning", str(i)) Session.commit() assert len(fetch_all("Changelog")) == number_of_logs + 10