From 23de967334a5f7f2f2daa60884d550e5bd27767e Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Mon, 22 Apr 2024 11:37:36 +0300 Subject: Separate clients' keys from authorisation server's key The authorisation server uses its key to sign any token it generates. It uses the clients' public keys to validate any assertions it receives from a client using the client's public key. --- gn_auth/__init__.py | 23 +++++++++++++---------- gn_auth/auth/authentication/oauth2/server.py | 4 ++-- gn_auth/settings.py | 6 +++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/gn_auth/__init__.py b/gn_auth/__init__.py index 5218673..f7e2620 100644 --- a/gn_auth/__init__.py +++ b/gn_auth/__init__.py @@ -25,8 +25,7 @@ def check_mandatory_settings(app: Flask) -> None: undefined = tuple( setting for setting in ( "SECRET_KEY", "SQL_URI", "AUTH_DB", "AUTH_MIGRATIONS", - "OAUTH2_SCOPE", "SSL_KEY_PAIR_PRIVATE_KEY", - "SSL_KEY_PAIR_PUBLIC_KEY") + "OAUTH2_SCOPE", "SSL_PRIVATE_KEY", "CLIENTS_SSL_PUBLIC_KEYS_DIR") if not ((setting in app.config) and bool(app.config[setting]))) if len(undefined) > 0: raise ConfigurationError( @@ -61,14 +60,18 @@ def load_secrets_conf(app: Flask) -> None: app.config.from_pyfile(secretsfile) -def parse_ssl_key_pair(app): - def __parse_key__(keypathconfig: str, configkey: Optional[str]): - configkey = configkey or keypathconfig - with open(app.config[keypathconfig]) as _sslkey: - app.config[configkey] = JsonWebKey.import_key(_sslkey.read()) +def parse_ssl_public_keys(app): + def __parse_key__(keypath: Path) -> JsonWebKey: + with open(keypath) as _sslkey: + return JsonWebKey.import_key(_sslkey.read()) - __parse_key__("SSL_KEY_PAIR_PUBLIC_KEY", "JWT_PUBLIC_KEY") - __parse_key__("SSL_KEY_PAIR_PRIVATE_KEY", "JWT_PRIVATE_KEY") + key_storage_dir = app.config["CLIENTS_SSL_PUBLIC_KEYS_DIR"] + 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))} + + app.config["SSL_PRIVATE_KEY"] = __parse_key__(app.config["SSL_PRIVATE_KEY"]) def create_app(config: Optional[dict] = None) -> Flask: """Create and return a new flask application.""" @@ -85,7 +88,7 @@ def create_app(config: Optional[dict] = None) -> Flask: override_settings_with_envvars(app) load_secrets_conf(app) - parse_ssl_key_pair(app) + parse_ssl_public_keys(app) # ====== END: Setup configuration ====== check_mandatory_settings(app) diff --git a/gn_auth/auth/authentication/oauth2/server.py b/gn_auth/auth/authentication/oauth2/server.py index db2a0d5..0669139 100644 --- a/gn_auth/auth/authentication/oauth2/server.py +++ b/gn_auth/auth/authentication/oauth2/server.py @@ -66,7 +66,7 @@ def setup_oauth2_server(app: Flask) -> None: server.register_grant(JWTBearerGrant) server.register_token_generator( "urn:ietf:params:oauth:grant-type:jwt-bearer", - JWTBearerTokenGenerator(app.config["JWT_PRIVATE_KEY"])) + JWTBearerTokenGenerator(app.config["SSL_PRIVATE_KEY"])) # register endpoints server.register_endpoint(RevocationEndpoint) @@ -82,4 +82,4 @@ def setup_oauth2_server(app: Flask) -> None: ## Set up the token validators require_oauth.register_token_validator(BearerTokenValidator()) require_oauth.register_token_validator( - JWTBearerTokenValidator(app.config["JWT_PUBLIC_KEY"])) + JWTBearerTokenValidator(app.config["SSL_PRIVATE_KEY"].get_public_key())) diff --git a/gn_auth/settings.py b/gn_auth/settings.py index 59f3eec..489f72d 100644 --- a/gn_auth/settings.py +++ b/gn_auth/settings.py @@ -29,6 +29,6 @@ CORS_HEADERS = [ "Access-Control-Allow-Credentials" ] -# OpenSSL Key-Pair -SSL_KEY_PAIR_PRIVATE_KEY = "" -SSL_KEY_PAIR_PUBLIC_KEY = "" +# OpenSSL keys +CLIENTS_SSL_PUBLIC_KEYS_DIR = "" # keys from registered clients +SSL_PRIVATE_KEY = "" # authorisation server primary key -- cgit v1.2.3