about summary refs log tree commit diff
path: root/gn_auth/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'gn_auth/__init__.py')
-rw-r--r--gn_auth/__init__.py74
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