diff options
Diffstat (limited to 'gn_auth/__init__.py')
| -rw-r--r-- | gn_auth/__init__.py | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/gn_auth/__init__.py b/gn_auth/__init__.py index b3df070..d6591e5 100644 --- a/gn_auth/__init__.py +++ b/gn_auth/__init__.py @@ -1,6 +1,8 @@ """Application initialisation module.""" import os import sys +import logging +import warnings from pathlib import Path from typing import Optional, Callable @@ -8,6 +10,7 @@ from flask import Flask from flask_cors import CORS from authlib.jose import JsonWebKey +from gn_auth import hooks from gn_auth.misc_views import misc from gn_auth.auth.views import oauth2 @@ -16,15 +19,22 @@ from gn_auth.auth.authentication.oauth2.server import setup_oauth2_server from . import settings from .errors import register_error_handlers +## Configure warnings: ## +# https://docs.python.org/3/library/warnings.html#the-warnings-filter +# filters form: (action, message, category, module, lineno) +warnings.filterwarnings(action="always", category=DeprecationWarning) + + class ConfigurationError(Exception): """Raised in case of a configuration error.""" + def check_mandatory_settings(app: Flask) -> None: """Verify that mandatory settings are defined in the application""" undefined = tuple( setting for setting in ( "SECRET_KEY", "SQL_URI", "AUTH_DB", "AUTH_MIGRATIONS", - "OAUTH2_SCOPE", "SSL_PRIVATE_KEY", "CLIENTS_SSL_PUBLIC_KEYS_DIR") + "OAUTH2_SCOPES_SUPPORTED") if not ((setting in app.config) and bool(app.config[setting]))) if len(undefined) > 0: raise ConfigurationError( @@ -51,26 +61,52 @@ def load_secrets_conf(app: Flask) -> None: app.config.from_pyfile(secretsfile) -def parse_ssl_keys(app): - """Parse the SSL keys.""" - def __parse_key__(keypath: Path) -> JsonWebKey: - with open(keypath) as _sslkey:# pylint: disable=[unspecified-encoding] - return JsonWebKey.import_key(_sslkey.read()) +def dev_loggers(appl: Flask) -> None: + """Setup the logging handlers.""" + stderr_handler = logging.StreamHandler(stream=sys.stderr) + appl.logger.addHandler(stderr_handler) + + root_logger = logging.getLogger() + root_logger.addHandler(stderr_handler) + root_logger.setLevel(appl.config["LOGLEVEL"]) + + +def gunicorn_loggers(appl: Flask) -> None: + """Use gunicorn logging handlers for the application.""" + logger = logging.getLogger("gunicorn.error") + appl.logger.handlers = logger.handlers + appl.logger.setLevel(logger.level) + + +_LOGGABLE_MODULES_ = ( + "gn_auth.errors", + "gn_auth.errors.common", + "gn_auth.errors.authlib", + "gn_auth.errors.http.http_4xx_errors", + "gn_auth.errors.http.http_5xx_errors" +) + + +def setup_logging(appl: Flask) -> None: + """ + Setup the loggers according to the WSGI server used to run the application. + """ + # https://datatracker.ietf.org/doc/html/draft-coar-cgi-v11-03#section-4.1.17 + # https://wsgi.readthedocs.io/en/latest/proposals-2.0.html#making-some-keys-required + # https://peps.python.org/pep-3333/#id4 + software, *_version_and_comments = os.environ.get( + "SERVER_SOFTWARE", "").split('/') + if bool(software): + gunicorn_loggers(appl) + else: + dev_loggers(appl) - key_storage_dir = Path(app.config["CLIENTS_SSL_PUBLIC_KEYS_DIR"]) - key_storage_dir.mkdir(exist_ok=True) - app.config["SSL_PUBLIC_KEYS"] = { - _key.as_dict()["kid"]: _key for _key in ( - __parse_key__(Path(key_storage_dir).joinpath(key)) - for key in os.listdir(key_storage_dir))} + loglevel = logging.getLevelName(appl.logger.getEffectiveLevel()) + for module_logger in _LOGGABLE_MODULES_: + logging.getLogger(module_logger).setLevel(loglevel) - app.config["SSL_PRIVATE_KEY"] = __parse_key__( - Path(app.config["SSL_PRIVATE_KEY"])) -def create_app( - config: Optional[dict] = None, - setup_logging: Callable[[Flask], None] = lambda appl: None -) -> Flask: +def create_app(config: Optional[dict] = None) -> Flask: """Create and return a new flask application.""" app = Flask(__name__) @@ -85,7 +121,6 @@ def create_app( override_settings_with_envvars(app) load_secrets_conf(app) - parse_ssl_keys(app) # ====== END: Setup configuration ====== setup_logging(app) @@ -104,5 +139,6 @@ def create_app( app.register_blueprint(oauth2, url_prefix="/auth") register_error_handlers(app) + hooks.register_hooks(app) return app |
