Loading app.py +42 −3 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ # This file is an original contribution from Telefonica Innovación Digital S.L. import logging from flask import Flask from flask import Flask, request, Response from flask_restx import Api from flask_cors import CORS from swagger.tfs_namespace import tfs_ns Loading @@ -27,6 +27,32 @@ from src.webui.gui import gui_bp from src.config.config import create_config from src.database.db import init_db # Paths that do not require authentication (Swagger UI and its static assets) # /nsc → Swagger UI # /swaggerui → Swagger UI static assets (flask-restx) # /swagger → swagger.json spec file (flask-restx) UNAUTHENTICATED_PREFIXES = ("/nsc", "/swaggerui", "/swagger") def _unauthorized_response(): """Return a 401 response without WWW-Authenticate header to avoid browser popup.""" return Response( response="Unauthorized: valid credentials required.", status=401, headers={} ) def _check_basic_auth(app): """Validate Basic Auth credentials against the configured username and password.""" credentials = request.authorization if not credentials: return False expected_username = app.config["API_USERNAME"] expected_password = app.config["API_PASSWORD"] return credentials.username == expected_username and credentials.password == expected_password def create_app(): """Create Flask application with configured API and namespaces.""" init_db() Loading @@ -46,7 +72,9 @@ def create_app(): version="1.0", title="Network Slice Controller (NSC) API", description="API for orchestrating and realizing transport network slice requests", doc="/nsc" # Swagger UI URL doc="/nsc", # Swagger UI URL authorizations={"basicAuth": {"type": "basic"}}, security="basicAuth" ) # Register namespaces Loading @@ -59,8 +87,19 @@ def create_app(): app.secret_key = "clave-secreta-dev" app.register_blueprint(gui_bp) # Registered after Api and namespaces to ensure flask-restx does not override this hook @app.before_request def enforce_basic_auth(): """Reject any request that does not include valid Basic Auth credentials.""" # Allow unauthenticated access to Swagger UI and its static assets if request.path.startswith(UNAUTHENTICATED_PREFIXES): return None if not _check_basic_auth(app): return _unauthorized_response() return app if __name__ == "__main__": app = create_app() app.run(host="0.0.0.0", port=NSC_PORT, debug=True) No newline at end of file src/config/.env.example +6 −0 Original line number Diff line number Diff line Loading @@ -76,3 +76,9 @@ DATAPLANE_SUPPORT=FRR # WebUI # ------------------------- WEBUI_DEPLOY=true # ------------------------- # API # ------------------------- API_USERNAME=admin API_PASSWORD=admin src/config/config.py +4 −0 Original line number Diff line number Diff line Loading @@ -69,4 +69,8 @@ def create_config(app: Flask): app.config["SDN_CONTROLLER_TYPE"] = os.getenv("SDN_CONTROLLER_TYPE", "TFS") app.config["DATAPLANE_SUPPORT"] = os.getenv("DATAPLANE_SUPPORT", "FRR") # API app.config["API_USERNAME"] = os.getenv("API_USERNAME", "admin") app.config["API_PASSWORD"] = os.getenv("API_PASSWORD", "admin") return app Loading
app.py +42 −3 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ # This file is an original contribution from Telefonica Innovación Digital S.L. import logging from flask import Flask from flask import Flask, request, Response from flask_restx import Api from flask_cors import CORS from swagger.tfs_namespace import tfs_ns Loading @@ -27,6 +27,32 @@ from src.webui.gui import gui_bp from src.config.config import create_config from src.database.db import init_db # Paths that do not require authentication (Swagger UI and its static assets) # /nsc → Swagger UI # /swaggerui → Swagger UI static assets (flask-restx) # /swagger → swagger.json spec file (flask-restx) UNAUTHENTICATED_PREFIXES = ("/nsc", "/swaggerui", "/swagger") def _unauthorized_response(): """Return a 401 response without WWW-Authenticate header to avoid browser popup.""" return Response( response="Unauthorized: valid credentials required.", status=401, headers={} ) def _check_basic_auth(app): """Validate Basic Auth credentials against the configured username and password.""" credentials = request.authorization if not credentials: return False expected_username = app.config["API_USERNAME"] expected_password = app.config["API_PASSWORD"] return credentials.username == expected_username and credentials.password == expected_password def create_app(): """Create Flask application with configured API and namespaces.""" init_db() Loading @@ -46,7 +72,9 @@ def create_app(): version="1.0", title="Network Slice Controller (NSC) API", description="API for orchestrating and realizing transport network slice requests", doc="/nsc" # Swagger UI URL doc="/nsc", # Swagger UI URL authorizations={"basicAuth": {"type": "basic"}}, security="basicAuth" ) # Register namespaces Loading @@ -59,8 +87,19 @@ def create_app(): app.secret_key = "clave-secreta-dev" app.register_blueprint(gui_bp) # Registered after Api and namespaces to ensure flask-restx does not override this hook @app.before_request def enforce_basic_auth(): """Reject any request that does not include valid Basic Auth credentials.""" # Allow unauthenticated access to Swagger UI and its static assets if request.path.startswith(UNAUTHENTICATED_PREFIXES): return None if not _check_basic_auth(app): return _unauthorized_response() return app if __name__ == "__main__": app = create_app() app.run(host="0.0.0.0", port=NSC_PORT, debug=True) No newline at end of file
src/config/.env.example +6 −0 Original line number Diff line number Diff line Loading @@ -76,3 +76,9 @@ DATAPLANE_SUPPORT=FRR # WebUI # ------------------------- WEBUI_DEPLOY=true # ------------------------- # API # ------------------------- API_USERNAME=admin API_PASSWORD=admin
src/config/config.py +4 −0 Original line number Diff line number Diff line Loading @@ -69,4 +69,8 @@ def create_config(app: Flask): app.config["SDN_CONTROLLER_TYPE"] = os.getenv("SDN_CONTROLLER_TYPE", "TFS") app.config["DATAPLANE_SUPPORT"] = os.getenv("DATAPLANE_SUPPORT", "FRR") # API app.config["API_USERNAME"] = os.getenv("API_USERNAME", "admin") app.config["API_PASSWORD"] = os.getenv("API_PASSWORD", "admin") return app