From ecbbb2519738084b88390caf4fcdd25b4c38d5f5 Mon Sep 17 00:00:00 2001 From: Kip Parker Date: Wed, 1 May 2024 14:33:19 +0100 Subject: [PATCH 1/6] Update docs with details of signing key pairs --- README.md | 11 +++++++++++ scripts/signingcerts.sh | 5 +++++ 2 files changed, 16 insertions(+) create mode 100755 scripts/signingcerts.sh diff --git a/README.md b/README.md index c871859..7ea732e 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,17 @@ You will need to create a "certs" directory in the root of the project, and move Most of the endpoints require a client certificate to be presented. As the directory service is not yet available, the contents of the certificate will not be checked with an external, so any valid certificate will be acceptable. The certificate **is** used to confirm identity, so the same one must be presented in all requests. +## Creating signing certificates + +A separate set of certificates are required for signing JWTs. These can be generated using the `signingcerts.sh` script in the `scripts` directory. + +```bash +cd scripts +./signingcerts.sh +``` + +The default configuration will expect these certificate to be in authentication/api/certs. The location can be changed by setting the DIRECTORY_CERTIFICATE and DIRECTORY_PRIVATE_KEY environment variables. + ## Running the local docker environment The included docker compose file will bring up both APIs. It uses nginx to proxy requests to uvicorn, with nginx configuration to pass through client certificates to the backend, using the same header as used by AWS ALB (`x-amzn-mtls-clientcert`). diff --git a/scripts/signingcerts.sh b/scripts/signingcerts.sh new file mode 100755 index 0000000..e1ebd0f --- /dev/null +++ b/scripts/signingcerts.sh @@ -0,0 +1,5 @@ +# Create a key pair suitable for signing jwts and creating a jwks endpoint + +openssl ecparam -name prime256v1 -genkey -noout -out server-signing-private-key.pem +openssl ec -in server-signing-private-key.pem -pubout -out server-signing-public-key.pem + From 15c249ea82b08e07bda8acd28b5a9b1d87e2bc2e Mon Sep 17 00:00:00 2001 From: Ciaran Wood Date: Tue, 7 May 2024 13:47:39 +0200 Subject: [PATCH 2/6] use 201 status code for successful PAR response as per spec --- authentication/api/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentication/api/main.py b/authentication/api/main.py index 7fb050d..f0e2b32 100644 --- a/authentication/api/main.py +++ b/authentication/api/main.py @@ -66,7 +66,7 @@ async def docs() -> dict: return {"docs": "/api-docs"} -@app.post("/api/v1/par", response_model=models.PushedAuthorizationResponse) +@app.post("/api/v1/par", response_model=models.PushedAuthorizationResponse, status_code=201) async def pushed_authorization_request( response_type: Annotated[str, Form()], client_id: Annotated[str, Form()], From f2d85ec9f688bcd41a2a5a9a49fb0696c35c5a1d Mon Sep 17 00:00:00 2001 From: Ciaran Wood Date: Tue, 7 May 2024 13:52:22 +0200 Subject: [PATCH 3/6] create new env var "OAUTH_CLIENT_ID" The new env var is used for the FAPI OAuth2 provider's client id. The previous env var "CLIENT_ID" represents the perseus auth server's client id credential which is used to authenticate against the Perseus auth server along with the "CLIENT_SECRET" env var --- authentication/api/conf.py | 1 + authentication/api/main.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/authentication/api/conf.py b/authentication/api/conf.py index c1d6679..eff51da 100644 --- a/authentication/api/conf.py +++ b/authentication/api/conf.py @@ -22,6 +22,7 @@ OAUTH_URL = os.environ.get( "OAUTH_URL", "https://musing-kirch-t48np94ikp.projects.oryapis.com" ) +OAUTH_CLIENT_ID = os.environ.get("OAUTH_CLIENT_ID", "f67916ce-de33-4e2f-a8e3-cbd5f6459c30") AUTHORIZATION_ENDPOINT = os.environ.get( "AUTHORIZATION_ENDPOINT", f"{OAUTH_URL}/oauth2/auth", diff --git a/authentication/api/main.py b/authentication/api/main.py index f0e2b32..8623e44 100644 --- a/authentication/api/main.py +++ b/authentication/api/main.py @@ -151,7 +151,7 @@ async def authorize( # Construct authorization URL with request object and PKCE parameters authorization_url = ( f"{conf.AUTHORIZATION_ENDPOINT}?" - f"client_id={conf.CLIENT_ID}&" + f"client_id={conf.OAUTH_CLIENT_ID}&" f"response_type=code&" f"redirect_uri={par_request['redirect_uri']}&" f"scope={par_request['scope']}&" @@ -187,7 +187,7 @@ async def token( "grant_type": grant_type, "code": code, "redirect_uri": redirect_uri, - "client_id": client_id, + "client_id": conf.OAUTH_CLIENT_ID, "code_verifier": code_verifier, } session = requests.Session() From 45d3111cd7777bce0cf0590a601548dc06974ab1 Mon Sep 17 00:00:00 2001 From: Ciaran Wood Date: Tue, 7 May 2024 13:53:02 +0200 Subject: [PATCH 4/6] use the "ISSUER_URL" env var as the "iss" value in the id token --- authentication/api/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentication/api/auth.py b/authentication/api/auth.py index 4fc03ed..a7d1d90 100644 --- a/authentication/api/auth.py +++ b/authentication/api/auth.py @@ -167,7 +167,7 @@ def get_thumbprint(cert: str) -> str: def create_id_token(subject="platform_user") -> str: claims = { - "iss": "https://perseus-demo-energy.ib1.org", + "iss": f"{conf.ISSUER_URL}", "sub": subject, "aud": conf.CLIENT_ID, "exp": int(time.time()) + 3600, From a18d7621f044cc51eadfcd818d40f960ea2cdc6e Mon Sep 17 00:00:00 2001 From: Kip Parker Date: Tue, 7 May 2024 13:08:45 +0100 Subject: [PATCH 5/6] Align tests to corrected status code for PAR --- authentication/tests/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentication/tests/test_api.py b/authentication/tests/test_api.py index aec7ac2..9abb75f 100644 --- a/authentication/tests/test_api.py +++ b/authentication/tests/test_api.py @@ -39,7 +39,7 @@ def test_pushed_authorization_request(mock_redis_connection): headers={"x-amzn-mtls-clientcert": client_certificate()}, ) - assert response.status_code == 200 + assert response.status_code == 201 print(response.json()) assert "request_uri" in response.json() From 61f27891444bb61cf9f2d30826b366ee54e4f437 Mon Sep 17 00:00:00 2001 From: Kip Parker Date: Tue, 7 May 2024 13:14:36 +0100 Subject: [PATCH 6/6] Change default conf OAUTH_URL to new value which aligns with OAUTH_CLIENT_ID --- authentication/api/conf.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/authentication/api/conf.py b/authentication/api/conf.py index eff51da..88188b3 100644 --- a/authentication/api/conf.py +++ b/authentication/api/conf.py @@ -20,9 +20,11 @@ "CLIENT_SECRET", "uE4NgqeIpuSV_XejQ7Ds3jsgA1yXhjR1MXJ1LbPuyls" ) OAUTH_URL = os.environ.get( - "OAUTH_URL", "https://musing-kirch-t48np94ikp.projects.oryapis.com" + "OAUTH_URL", "https://vigorous-heyrovsky-1trvv0ikx9.projects.oryapis.com" +) +OAUTH_CLIENT_ID = os.environ.get( + "OAUTH_CLIENT_ID", "f67916ce-de33-4e2f-a8e3-cbd5f6459c30" ) -OAUTH_CLIENT_ID = os.environ.get("OAUTH_CLIENT_ID", "f67916ce-de33-4e2f-a8e3-cbd5f6459c30") AUTHORIZATION_ENDPOINT = os.environ.get( "AUTHORIZATION_ENDPOINT", f"{OAUTH_URL}/oauth2/auth",