From 90abb395da68c2fefe6cbbe694edae29ed2c602a Mon Sep 17 00:00:00 2001 From: Stein A Sivertsen Date: Tue, 23 Jan 2024 08:48:23 +0100 Subject: [PATCH] Run7 URI postwork suggestion (#14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove old config not necessary anymore * make modification needed better visible * remove hardcoded URI prefix and introduce CLIENT_ID on episodes * add redirect_uri to config * make sure we use patched env in tests * remove remnants * Add two small clarifications --------- Co-authored-by: Lars Kåre Skjørestad <10708951+larskaare@users.noreply.github.com> --- ex-10/client/lib/app-config.js | 2 +- ex-10/doc/configure_client_anda_api.md | 1 + ex-10/doc/swapping_tech_for_episodes_api.md | 2 +- .../src/core/config.py | 2 +- .../tests/core/test_core.py | 9 +++---- ex-10/got-episodes-api/lib/app-config.js | 2 +- ex-11/client/lib/app-config.js | 2 +- ex-11/doc/client_code_config.md | 3 +-- ex-11/doc/quotes_code_config.md | 2 ++ .../got-episodes-api-python/src/core/auth.py | 2 +- .../src/core/config.py | 2 +- .../tests/core/test_core.py | 4 ++-- ex-11/got-episodes-api/lib/app-config.js | 4 ++-- ex-11/got-quote-api-dotnet/readme.md | 24 ------------------- ex-11/got-quote-api-dotnet/src/Program.cs | 2 +- ex-11/got-quote-api/lib/app-config.js | 4 ++-- ex-11/got-quote-api/readme.md | 1 + src/templates/quote.env.template | 1 + 18 files changed, 25 insertions(+), 44 deletions(-) diff --git a/ex-10/client/lib/app-config.js b/ex-10/client/lib/app-config.js index 50ea3d1..8a1542b 100644 --- a/ex-10/client/lib/app-config.js +++ b/ex-10/client/lib/app-config.js @@ -44,7 +44,7 @@ const msalConfig = { file: tokenCacheFile, }, scopes: { - gotApi: ['api://f6a763f4-932d-4784-8122-f2b526bb2364/Episodes.Read'], + gotApi: ['api://00000000-0000-0000-0000-000000000000/Episodes.Read'], inbox: ['user.read', 'mail.read'], }, }; diff --git a/ex-10/doc/configure_client_anda_api.md b/ex-10/doc/configure_client_anda_api.md index bdcc20b..fdea03b 100644 --- a/ex-10/doc/configure_client_anda_api.md +++ b/ex-10/doc/configure_client_anda_api.md @@ -18,6 +18,7 @@ export NODE_ENV=development export CLIENT_ID="the client id from the AD app object" export TENANT_ID="then tenant id" export PORT=3000 +export REDIRECT_URI=$(aa-get-redirect-uri.sh) export TOKEN_CACHE_FILE="${HOME}/.tcache/cache.json" ``` ### Additional config diff --git a/ex-10/doc/swapping_tech_for_episodes_api.md b/ex-10/doc/swapping_tech_for_episodes_api.md index 63d6e01..05e3a14 100644 --- a/ex-10/doc/swapping_tech_for_episodes_api.md +++ b/ex-10/doc/swapping_tech_for_episodes_api.md @@ -36,7 +36,7 @@ Steps: pytest ``` - In `./src/core/config.py` update the API audience to reflect your API (AppSettings) - - Follow the pattern in the code for this; use only the GUID not the whole URI + - Follow the pattern in the code for this; use the Application ID URI. - Remember to save --Now You-- diff --git a/ex-10/got-episodes-api-python/src/core/config.py b/ex-10/got-episodes-api-python/src/core/config.py index b2dcfec..8a9b015 100644 --- a/ex-10/got-episodes-api-python/src/core/config.py +++ b/ex-10/got-episodes-api-python/src/core/config.py @@ -33,7 +33,7 @@ def get_settings(): port = os.environ.get('PORT', 3100), host = os.environ.get('HOST', '127.0.0.1'), jwks_uri = f"https://login.microsoftonline.com/{os.environ['TENANT_ID']}/discovery/v2.0/keys", - api_audience= f"api://{os.environ.get('EPISODES_API_URI', 'f6a763f4-932d-4784-8122-f2b526bb2364')}" + api_audience= f"{os.environ.get('EPISODES_API_URI', 'api://00000000-0000-0000-0000-000000000000')}" ) except ValidationError as exc: for err in exc.errors(): diff --git a/ex-10/got-episodes-api-python/tests/core/test_core.py b/ex-10/got-episodes-api-python/tests/core/test_core.py index c1768e5..c638575 100644 --- a/ex-10/got-episodes-api-python/tests/core/test_core.py +++ b/ex-10/got-episodes-api-python/tests/core/test_core.py @@ -11,7 +11,7 @@ def patchenv(monkeypatch): monkeypatch.setenv('TENANT_ID', 'test_tenant_id') monkeypatch.setenv('PORT', '7777') monkeypatch.setenv('HOST', 'test_host') - + monkeypatch.setenv('EPISODES_API_URI', 'api://00000000-7e57-c0de-0000-000000000000') yield monkeypatch def test_valid_app_settings(patchenv): @@ -22,10 +22,11 @@ def test_valid_app_settings(patchenv): assert config.host == 'test_host' # Generated assert config.jwks_uri == HttpUrl(f"https://login.microsoftonline.com/{config.tenant_id}/discovery/v2.0/keys") - assert config.api_audience == f"api://f6a763f4-932d-4784-8122-f2b526bb2364" + assert config.api_audience == "api://00000000-7e57-c0de-0000-000000000000" assert config.issuer == HttpUrl(f"https://sts.windows.net/{config.tenant_id}/") -def test_missing_environment_variables(): +def test_missing_environment_variables(patchenv): + patchenv.delenv('TENANT_ID') with pytest.raises(KeyError): get_settings() @@ -38,7 +39,7 @@ def test_get_uvicorn_config(patchenv): def test_get_claims_options(patchenv): expected_claims_options = { "iss": {"essential": True, "value": f"https://sts.windows.net/{os.environ['TENANT_ID']}/",}, - "aud": {"essential": True, "value": f"api://f6a763f4-932d-4784-8122-f2b526bb2364"}, + "aud": {"essential": True, "value": "api://00000000-7e57-c0de-0000-000000000000"}, } result_claims_options = get_claims_options() assert result_claims_options == expected_claims_options diff --git a/ex-10/got-episodes-api/lib/app-config.js b/ex-10/got-episodes-api/lib/app-config.js index 26e7e56..86487ba 100644 --- a/ex-10/got-episodes-api/lib/app-config.js +++ b/ex-10/got-episodes-api/lib/app-config.js @@ -12,7 +12,7 @@ const host = process.env.HOST || 'localhost'; const swaggerHost = process.env.SWAGGER_HOST || host + ':' + port; const jwksUri = 'https://login.microsoftonline.com/' + tenantId + '/discovery/v2.0/keys'; -const apiAudience = 'api://f6a763f4-932d-4784-8122-f2b526bb2364'; +const apiAudience = 'api://00000000-0000-0000-0000-000000000000'; const rateLimitAllowList = function () { return ['127.0.0.1','::1']; diff --git a/ex-11/client/lib/app-config.js b/ex-11/client/lib/app-config.js index ccfdfdb..216401b 100644 --- a/ex-11/client/lib/app-config.js +++ b/ex-11/client/lib/app-config.js @@ -44,7 +44,7 @@ const msalConfig = { file: tokenCacheFile, }, scopes: { - gotApi: ['api://' + process.env.EPISODES_API_URI + '/episodes.read'], + gotApi: [process.env.EPISODES_API_URI + '/episodes.read'], inbox: ['user.read', 'mail.read'], }, }; diff --git a/ex-11/doc/client_code_config.md b/ex-11/doc/client_code_config.md index a27ca1c..b014b64 100644 --- a/ex-11/doc/client_code_config.md +++ b/ex-11/doc/client_code_config.md @@ -28,8 +28,7 @@ Steps: * New environment variables `EPISODES_API_URI` and `EPISODES_API_URL` that needs to be added to then env file * Hint: Microsoft Entra ID -> App Registrations -> Episodes Api -> Expose An Api -> Application ID URI - * Hint: Exclude the prefix 'api://' -* Update the client env file (appsec-course-client-eq.env) + * Update the client env file (appsec-course-client-eq.env) * Run `aa-save-env-files-to-github-user-secret.sh` in a terminal window to persist the new environment variables (don't __reload__) diff --git a/ex-11/doc/quotes_code_config.md b/ex-11/doc/quotes_code_config.md index 8ce4e21..68dece0 100644 --- a/ex-11/doc/quotes_code_config.md +++ b/ex-11/doc/quotes_code_config.md @@ -19,6 +19,7 @@ Steps: export PORT=3200 export QUOTES_API_URI="" export EPISODES_API_URI="" + export EPISODES_API_CLIENT_ID="" ``` * The App @@ -62,6 +63,7 @@ Using the procedure from [exercise-10](../../ex-10/doc/registering_api_in_azure_ export PORT=3200 export QUOTES_API_URI="" export EPISODES_API_URI="" + export EPISODES_API_CLIENT_ID="" ``` ### --Now You-- diff --git a/ex-11/got-episodes-api-python/src/core/auth.py b/ex-11/got-episodes-api-python/src/core/auth.py index cb78c1d..548d218 100644 --- a/ex-11/got-episodes-api-python/src/core/auth.py +++ b/ex-11/got-episodes-api-python/src/core/auth.py @@ -36,7 +36,7 @@ def get_obo_token(assertion: str): "client_id": config.client_id, "client_secret": config.client_secret, "assertion": assertion, - "scope": f"api://{config.quotes_api_uri}/Quote.Read", + "scope": f"{config.quotes_api_uri}/Quote.Read", "requested_token_use": "on_behalf_of", } tokenEndpoint = get_token_endpoint(well_known_conf_url) diff --git a/ex-11/got-episodes-api-python/src/core/config.py b/ex-11/got-episodes-api-python/src/core/config.py index 73e4fd2..bcf9506 100644 --- a/ex-11/got-episodes-api-python/src/core/config.py +++ b/ex-11/got-episodes-api-python/src/core/config.py @@ -43,7 +43,7 @@ def get_settings(): port = os.environ.get('PORT', 3100), host = os.environ.get('HOST', '127.0.0.1'), jwks_uri = f"https://login.microsoftonline.com/{os.environ['TENANT_ID']}/discovery/v2.0/keys", - api_audience= f"api://{os.environ.get('EPISODES_API_URI', '251bc275-eed7-49d6-83b3-9005c9779574')}" + api_audience= os.environ['EPISODES_API_URI'] ) except ValidationError as exc: for err in exc.errors(): diff --git a/ex-11/got-episodes-api-python/tests/core/test_core.py b/ex-11/got-episodes-api-python/tests/core/test_core.py index 35c836e..51bcdad 100644 --- a/ex-11/got-episodes-api-python/tests/core/test_core.py +++ b/ex-11/got-episodes-api-python/tests/core/test_core.py @@ -32,7 +32,7 @@ def test_valid_app_settings(patchenv): assert config.host == 'test_host' # Generated assert config.jwks_uri == HttpUrl(f"https://login.microsoftonline.com/{config.tenant_id}/discovery/v2.0/keys") - assert config.api_audience == f"api://{config.episodes_api_uri}" + assert config.api_audience == f"{config.episodes_api_uri}" assert config.issuer == HttpUrl(f"https://sts.windows.net/{config.tenant_id}/") def test_missing_environment_variables(patchenv): @@ -55,7 +55,7 @@ def test_get_well_known_conf_url(patchenv): def test_get_claims_options(patchenv): expected_claims_options = { "iss": {"essential": True, "value": f"https://sts.windows.net/{os.environ['TENANT_ID']}/",}, - "aud": {"essential": True, "value": f"api://{os.environ['EPISODES_API_URI']}"}, + "aud": {"essential": True, "value": f"{os.environ['EPISODES_API_URI']}"}, } result_claims_options = get_claims_options() assert result_claims_options == expected_claims_options diff --git a/ex-11/got-episodes-api/lib/app-config.js b/ex-11/got-episodes-api/lib/app-config.js index 289d710..965675b 100644 --- a/ex-11/got-episodes-api/lib/app-config.js +++ b/ex-11/got-episodes-api/lib/app-config.js @@ -14,9 +14,9 @@ const host = process.env.HOST || 'localhost'; const swaggerHost = process.env.SWAGGER_HOST || host + ':' + port; const jwksUri = 'https://login.microsoftonline.com/' + tenantId + '/discovery/v2.0/keys'; -const apiAudience = 'api://' + process.env.EPISODES_API_URI; +const apiAudience = process.env.EPISODES_API_URI; const quoteApiUrl = process.env.QUOTES_API_URL + '/api/quote'; -const quoteApiScope = 'api://' + process.env.QUOTES_API_URI + '/quote.read'; +const quoteApiScope = process.env.QUOTES_API_URI + '/quote.read'; const rateLimitAllowList = function () { return ['127.0.0.1','::1']; diff --git a/ex-11/got-quote-api-dotnet/readme.md b/ex-11/got-quote-api-dotnet/readme.md index 65bf3bb..c55d76a 100644 --- a/ex-11/got-quote-api-dotnet/readme.md +++ b/ex-11/got-quote-api-dotnet/readme.md @@ -28,30 +28,6 @@ Expects the following environment variables to execute properly export EPISODES_API_URI="" ``` -Also visit application important settings in `appsettings.json` and correct all fieds for validation of JWT token - -```json -{ - "AzureAd": { - "Instance": "https://login.microsoftonline.com/", - "TenantId": "", - "ClientId": "", - "Jwt": { - "Authority": "https://login.microsoftonline.com//v2.0/", - "TokenValidationParameters": { - "ValidateIssuer": true, - "ValidIssuer": "https://sts.windows.net//", - "ValidateAudience": true, - "ValidAudience": "api://", - "ValidateLifetime": true, - "ValidateIssuerSigningKey": true - } - }, - }, -} - -``` - ### Execute ```sh diff --git a/ex-11/got-quote-api-dotnet/src/Program.cs b/ex-11/got-quote-api-dotnet/src/Program.cs index e13ca45..0b2afd2 100644 --- a/ex-11/got-quote-api-dotnet/src/Program.cs +++ b/ex-11/got-quote-api-dotnet/src/Program.cs @@ -12,7 +12,7 @@ } else { builder.Configuration["AzureAd:Jwt:Authority"] = $"https://login.microsoftonline.com/{TENANT_ID}/v2.0/"; builder.Configuration["AzureAd:Jwt:TokenValidationParameters:ValidIssuer"] = $"https://sts.windows.net/{TENANT_ID}/"; - builder.Configuration["AzureAd:Jwt:TokenValidationParameters:ValidAudience"] = $"api://{QUOTES_API_URI}"; + builder.Configuration["AzureAd:Jwt:TokenValidationParameters:ValidAudience"] = $"{QUOTES_API_URI}"; } builder.Services.AddEndpointsApiExplorer(); diff --git a/ex-11/got-quote-api/lib/app-config.js b/ex-11/got-quote-api/lib/app-config.js index 15ca133..79fd3c4 100644 --- a/ex-11/got-quote-api/lib/app-config.js +++ b/ex-11/got-quote-api/lib/app-config.js @@ -12,8 +12,8 @@ const host = process.env.HOST || 'localhost'; const swaggerHost = process.env.SWAGGER_HOST || host + ':' + port; const jwksUri = 'https://login.microsoftonline.com/' + tenantId + '/discovery/v2.0/keys'; -const apiAudience = 'api://' + process.env.QUOTES_API_URI; // This API -const quoteApiApprovedCallingApps = [process.env.EPISODES_API_URI]; +const apiAudience = process.env.QUOTES_API_URI; // This API +const quoteApiApprovedCallingApps = [process.env.EPISODES_API_CLIENT_ID]; const rateLimitAllowList = function () { return ['127.0.0.1', '::1']; diff --git a/ex-11/got-quote-api/readme.md b/ex-11/got-quote-api/readme.md index 3ba555a..12de5b3 100644 --- a/ex-11/got-quote-api/readme.md +++ b/ex-11/got-quote-api/readme.md @@ -21,6 +21,7 @@ Expects the following environment variables to execute properly export PORT=3200 export QUOTES_API_URI="" export EPISODES_API_URI="" + export EPISODES_API_CLIENT_ID="" Other config, like ratelimiting and **apiAudience** , is defined in './lib/app-config.js' and also needs to be verified. diff --git a/src/templates/quote.env.template b/src/templates/quote.env.template index b72cef9..6e5d372 100644 --- a/src/templates/quote.env.template +++ b/src/templates/quote.env.template @@ -3,4 +3,5 @@ export TENANT_ID='' export PORT=3200 export HOST=127.0.0.1 export EPISODES_API_URI='' +export EPISODES_API_CLIENT_ID='' export QUOTES_API_URI='' \ No newline at end of file