def setup_session(request): """This fixture is called at a function level. The default app created here should be modified by your tests. """ product = asyncio.run(_product_with_full_access()) print("\nCreating Default App..") # Create a new app app = ApigeeApiDeveloperApps() asyncio.run( app.create_new_app(callback_url="https://example.org/callback")) # Assign the new product to the app asyncio.run(app.add_api_product([product.name])) # Set default JWT Testing resource url asyncio.run( app.set_custom_attributes({ 'jwks-resource-url': 'https://raw.githubusercontent.com/NHSDigital/' 'identity-service-jwks/main/jwks/internal-dev/' '9baed6f4-1361-4a8e-8531-1f8426e3aba8.json' })) asyncio.run(product.update_environments([config.ENVIRONMENT])) oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) resp = asyncio.run( oauth.get_token_response(grant_type="authorization_code")) token = resp["body"]["access_token"] yield product, app, token # Teardown print("\nDestroying Default App..") asyncio.run(app.destroy_app()) asyncio.run(product.destroy_product())
async def test_no_role_provided(self, test_app): oauth = OauthHelper( client_id=test_app.client_id, client_secret=test_app.client_secret, redirect_uri=test_app.callback_url, ) jwt = oauth.create_jwt(kid="test-1") token = await oauth.get_token_response(grant_type="client_credentials", _jwt=jwt) token = token["body"]["access_token"] # Given expected_status_code = 400 expected_error = "invalid role" expected_error_description = "selected_roleid is missing in your token" # When response = requests.get( url=config.USER_ROLE_SHARED_FLOW, headers={"Authorization": f"Bearer {token}"}, ) # Then assert_that(expected_status_code).is_equal_to(response.status_code) assert_that(expected_error).is_equal_to(response.json()["error"]) assert_that(expected_error_description).is_equal_to( response.json()["error_description"])
async def get_token_cis2_token_exchange( test_app_and_product, product_1_scopes, product_2_scopes ): """Call identity server to get an access token""" test_product, test_product2, test_app = test_app_and_product await test_product.update_scopes(product_1_scopes) await test_product2.update_scopes(product_2_scopes) oauth = OauthHelper( client_id=test_app.client_id, client_secret=test_app.client_secret, redirect_uri=test_app.callback_url, ) claims = { "at_hash": "tf_-lqpq36lwO7WmSBIJ6Q", "sub": "787807429511", "auditTrackingId": "91f694e6-3749-42fd-90b0-c3134b0d98f6-1546391", "amr": ["N3_SMARTCARD"], "iss": "https://am.nhsint.auth-ptl.cis2.spineservices.nhs.uk:443/" "openam/oauth2/realms/root/realms/NHSIdentity/realms/Healthcare", "tokenName": "id_token", "aud": "969567331415.apps.national", "c_hash": "bc7zzGkClC3MEiFQ3YhPKg", "acr": "AAL3_ANY", "org.forgerock.openidconnect.ops": "-I45NjmMDdMa-aNF2sr9hC7qEGQ", "s_hash": "LPJNul-wow4m6Dsqxbning", "azp": "969567331415.apps.national", "auth_time": 1610559802, "realm": "/NHSIdentity/Healthcare", "exp": int(time()) + 6000, "tokenType": "JWTToken", "iat": int(time()) - 100, } with open(config.ID_TOKEN_PRIVATE_KEY_ABSOLUTE_PATH, "r") as f: contents = f.read() client_assertion_jwt = oauth.create_jwt(kid="test-1") id_token_jwt = oauth.create_id_token_jwt( kid="identity-service-tests-1", claims=claims, signing_key=contents ) # When token_resp = await oauth.get_token_response( grant_type="token_exchange", data={ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token_type": "urn:ietf:params:oauth:token-type:id_token", "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", "subject_token": id_token_jwt, "client_assertion": client_assertion_jwt, }, ) return token_resp
async def get_token_nhs_login_token_exchange( test_app_and_product, product_1_scopes, product_2_scopes ): """Call nhs login to get an access token""" test_product, test_product2, test_app = test_app_and_product await test_product.update_scopes(product_1_scopes) await test_product2.update_scopes(product_2_scopes) oauth = OauthHelper( client_id=test_app.client_id, client_secret=test_app.client_secret, redirect_uri=test_app.callback_url, ) claims = { "sub": "8dc9fc1d-c3cb-48e1-ba62-b1532539ab6d", "birthdate": "1939-09-26", "nhs_number": "9482807146", "iss": "https://internal-dev.api.service.nhs.uk", "nonce": "randomnonce", "vtm": "https://auth.aos.signin.nhs.uk/trustmark/auth.aos.signin.nhs.uk", "aud": "java_test_client", "id_status": "verified", "token_use": "id", "surname": "CARTHY", "auth_time": 1617272144, "vot": "P9.Cp.Cd", "identity_proofing_level": "P9", "exp": int(time()) + 6000, "iat": int(time()) - 100, "family_name": "CARTHY", "jti": "b6d6a28e-b0bb-44e3-974f-bb245c0b688a", } with open(config.ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH, "r") as f: contents = f.read() client_assertion_jwt = oauth.create_jwt(kid="test-1") id_token_jwt = oauth.create_id_token_jwt( kid="nhs-login", algorithm="RS512", claims=claims, signing_key=contents ) # When token_resp = await oauth.get_token_response( grant_type="token_exchange", data={ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token_type": "urn:ietf:params:oauth:token-type:id_token", "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", "subject_token": id_token_jwt, "client_assertion": client_assertion_jwt, }, ) return token_resp
async def _setup_session(request): product = await _product_with_full_access() app = ApigeeApiDeveloperApps() print("\nCreating Default App..") await app.create_new_app( callback_url="https://nhsd-apim-testing-internal-dev.herokuapp.com/callback" ) await app.add_api_product([product.name]) # Set default JWT Testing resource url await app.set_custom_attributes( { "jwks-resource-url": "https://raw.githubusercontent.com/NHSDigital/" "identity-service-jwks/main/jwks/internal-dev/" "9baed6f4-1361-4a8e-8531-1f8426e3aba8.json" } ) oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) for item in request.node.items: setattr(item.cls, "oauth", oauth) return app, product
async def _token( grant_type: str = "authorization_code", test_app: ApigeeApiDeveloperApps = None, **kwargs, ): if test_app: # Use provided test app oauth = OauthHelper( test_app.client_id, test_app.client_secret, test_app.callback_url ) print(oauth.base_uri) resp = await oauth.get_token_response(grant_type=grant_type, **kwargs) else: # Use default test app resp = await request.cls.oauth.get_token_response( grant_type=grant_type, **kwargs ) if resp["status_code"] != 200: message = "unable to get token" raise RuntimeError( f"\n{'*' * len(message)}\n" f"MESSAGE: {message}\n" f"URL: {resp.get('url')}\n" f"STATUS CODE: {resp.get('status_code')}\n" f"RESPONSE: {resp.get('body')}\n" f"HEADERS: {resp.get('headers')}\n" f"{'*' * len(message)}\n" ) return resp["body"]
async def test_user_invalid_role_in_header(self, test_app): oauth = OauthHelper( client_id=test_app.client_id, client_secret=test_app.client_secret, redirect_uri=test_app.callback_url, ) token = await oauth.get_token_response(grant_type="authorization_code") token = token["body"]["access_token"] # Given expected_status_code = 400 expected_error = "invalid role" expected_error_description = "nhsd-session-urid is invalid" # When response = requests.get( url=config.USER_ROLE_SHARED_FLOW, headers={ "Authorization": f"Bearer {token}", "NHSD-Session-URID": "notAuserRole123", }, ) # Then assert_that(expected_status_code).is_equal_to(response.status_code) assert_that(expected_error).is_equal_to(response.json()["error"]) assert_that(expected_error_description).is_equal_to( response.json()["error_description"])
async def test_user_restricted_scope_combination(self, product_1_scopes, product_2_scopes, test_app_and_product, helper): test_product, test_product2, test_app = test_app_and_product await test_product.update_scopes(product_1_scopes) await test_product2.update_scopes(product_2_scopes) callback_url = await test_app.get_callback_url() oauth = OauthHelper(test_app.client_id, test_app.client_secret, callback_url) assert helper.check_endpoint( verb="POST", endpoint=f"{config.OAUTH_URL}/token", expected_status_code=200, expected_response=[ "access_token", "expires_in", "refresh_count", "refresh_token", "refresh_token_expires_in", "token_type", ], data={ "client_id": test_app.get_client_id(), "client_secret": test_app.get_client_secret(), "redirect_uri": callback_url, "grant_type": "authorization_code", "code": await oauth.get_authenticated_with_simulated_auth(), }, )
async def test_app(): """Programatically create and destroy test app for each test""" apigee_product = ApigeeApiProducts() await apigee_product.create_new_product() await apigee_product.update_proxies([config.SERVICE_NAME]) apigee_app = ApigeeApiDeveloperApps() await apigee_product.update_ratelimits( quota=60000, quota_interval="1", quota_time_unit="minute", rate_limit="1000ps", ) await apigee_app.setup_app( api_products=[apigee_product.name], custom_attributes={ "jwks-resource-url": "https://internal-dev.api.service.nhs.uk/mock-nhsid-jwks/identity-service/nhs-cis2-jwks" }) apigee_app.oauth = OauthHelper(apigee_app.client_id, apigee_app.client_secret, apigee_app.callback_url) api_service_name = get_env("SERVICE_NAME") await apigee_product.update_scopes( ["urn:nhsd:apim:user-nhs-id:aal3:personal-demographics-service"]) yield apigee_app await apigee_app.destroy_app()
def setup_session(request): """This fixture is automatically called once at the start of pytest execution. The default app created here should be modified by your tests. If your test requires specific app config then please create your own using the fixture test_app""" product = asyncio.run(_product_with_full_access()) app = ApigeeApiDeveloperApps() print("\nCreating Default App..") asyncio.run( app.create_new_app( callback_url= "https://nhsd-apim-testing-internal-dev.herokuapp.com/callback")) asyncio.run(app.add_api_product([product.name])) # Set default JWT Testing resource url asyncio.run( app.set_custom_attributes({ 'jwks-resource-url': 'https://raw.githubusercontent.com/NHSDigital/' 'identity-service-jwks/main/jwks/internal-dev/' '9baed6f4-1361-4a8e-8531-1f8426e3aba8.json' })) oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) for item in request.node.items: setattr(item.cls, "oauth", oauth) yield # Teardown print("\nDestroying Default App..") asyncio.run(app.destroy_app()) asyncio.run(product.destroy_product())
async def get_token(self, test_app_and_product): """Call identity server to get an access token""" test_product, test_app = test_app_and_product oauth = OauthHelper(client_id=test_app.client_id, client_secret=test_app.client_secret, redirect_uri=test_app.callback_url) token_resp = await oauth.get_token_response( grant_type="authorization_code") assert token_resp["status_code"] == 200 return token_resp['body']
def test_product_and_app(): """Setup & Teardown an product and app for this api""" product = ApigeeApiProducts() app = ApigeeApiDeveloperApps() loop = asyncio.new_event_loop() loop.run_until_complete(product.create_new_product()) loop.run_until_complete(app.setup_app()) app.oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) yield product, app loop.run_until_complete(app.destroy_app()) loop.run_until_complete(product.destroy_product())
def base_test_app(): """Setup & Teardown an app-restricted app for this api""" app = ApigeeApiDeveloperApps() loop = asyncio.new_event_loop() loop.run_until_complete( app.setup_app( api_products=[get_env("APIGEE_PRODUCT")], custom_attributes=_BASE_CUSTOM_ATTRIBUTES, )) app.oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) yield app loop.run_until_complete(app.destroy_app())
async def test_cis2_user_restricted_scope_combination( self, product_1_scopes, product_2_scopes, expected_filtered_scopes, test_app_and_product, helper, ): test_product, test_product2, test_app = test_app_and_product await test_product.update_scopes(product_1_scopes) await test_product2.update_scopes(product_2_scopes) apigee_trace = ApigeeApiTraceDebug(proxy=config.SERVICE_NAME) callback_url = await test_app.get_callback_url() oauth = OauthHelper(test_app.client_id, test_app.client_secret, callback_url) apigee_trace.add_trace_filter(header_name="Auto-Test-Header", header_value="flow-callback") await apigee_trace.start_trace() assert helper.check_endpoint( verb="POST", endpoint=f"{config.OAUTH_URL}/token", expected_status_code=200, expected_response=[ "access_token", "expires_in", "refresh_count", "refresh_token", "refresh_token_expires_in", "sid", "token_type", ], data={ "client_id": test_app.get_client_id(), "client_secret": test_app.get_client_secret(), "redirect_uri": callback_url, "grant_type": "authorization_code", "code": await oauth.get_authenticated_with_simulated_auth(), }, ) user_restricted_scopes = await apigee_trace.get_apigee_variable_from_trace( name="apigee.user_restricted_scopes") assert ( user_restricted_scopes is not None ), "variable apigee.user_restricted_scopes not found in the trace" user_restricted_scopes = user_restricted_scopes.split(" ") assert expected_filtered_scopes.sort() == user_restricted_scopes.sort()
def test_app(): """Setup & Teardown an app-restricted app for this api""" app = ApigeeApiDeveloperApps() loop = asyncio.new_event_loop() loop.run_until_complete( app.setup_app( api_products=[get_env("APIGEE_PRODUCT")], custom_attributes={ "jwks-resource-url": "https://raw.githubusercontent.com/NHSDigital/identity-service-jwks/main/jwks/internal-dev/9baed6f4-1361-4a8e-8531-1f8426e3aba8.json" # noqa }, ) ) app.oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) yield app loop.run_until_complete(app.destroy_app())
async def test_default_role(self, test_app): oauth = OauthHelper( client_id=test_app.client_id, client_secret=test_app.client_secret, redirect_uri=test_app.callback_url, ) token = await oauth.get_token_response(grant_type="authorization_code") token = token["body"]["access_token"] # Given expected_status_code = 200 expected_response = {"message": "It works!"} # When response = requests.get( url=config.USER_ROLE_SHARED_FLOW, headers={"Authorization": f"Bearer {token}"}, ) # Then assert_that(expected_status_code).is_equal_to(response.status_code) assert_that(expected_response).is_equal_to(response.json())
def test_product_and_app(): """Setup & Teardown an product and app for this api""" product = ApigeeApiProducts() app = ApigeeApiDeveloperApps() loop = asyncio.new_event_loop() loop.run_until_complete(product.create_new_product()) loop.run_until_complete( product.update_scopes([ "urn:nhsd:apim:app:level3:immunisation-history", "urn:nhsd:apim:user-nhs-login:P9:immunisation-history", "urn:nhsd:apim:user-nhs-login:P5:immunisation-history" ])) loop.run_until_complete( app.setup_app( api_products=[product.name], custom_attributes=_BASE_CUSTOM_ATTRIBUTES, )) app.oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) yield product, app loop.run_until_complete(app.destroy_app()) loop.run_until_complete(product.destroy_product())
async def test_authorization_code_flow_remove_external_scopes( self, test_app_and_product, helper, external_scope): product_scope = [ "urn:nhsd:apim:user-nhs-id:aal3:personal-demographics-service" ] test_product, test_product2, test_app = test_app_and_product await test_product.update_scopes(product_scope) await test_product2.update_scopes(product_scope) callback_url = await test_app.get_callback_url() oauth = OauthHelper(test_app.client_id, test_app.client_secret, callback_url) assert helper.check_endpoint( verb="POST", endpoint=f"{config.OAUTH_URL}/token", expected_status_code=200, expected_response=[ "access_token", "expires_in", "refresh_count", "refresh_token", "refresh_token_expires_in", "sid", "token_type", ], data={ "scope": external_scope, "client_id": test_app.get_client_id(), "client_secret": test_app.get_client_secret(), "redirect_uri": callback_url, "grant_type": "authorization_code", "code": await oauth.get_authenticated_with_simulated_auth(), }, )
def test_product_and_app(request): """Setup & Teardown an product and app for this api""" request_params = request.param product = ApigeeApiProducts() app = ApigeeApiDeveloperApps() loop = asyncio.new_event_loop() loop.run_until_complete(product.create_new_product()) loop.run_until_complete(product.update_scopes( request_params['scopes'] )) loop.run_until_complete( app.setup_app( api_products=[product.name], custom_attributes= { "jwks-resource-url": "https://raw.githubusercontent.com/NHSDigital/identity-service-jwks/main/jwks/internal-dev/9baed6f4-1361-4a8e-8531-1f8426e3aba8.json", "nhs-login-allowed-proofing-level": request_params.get('requested_proofing_level') }, ) ) app.oauth = OauthHelper(app.client_id, app.client_secret, app.callback_url) app.request_params = request_params yield product, app loop.run_until_complete(app.destroy_app()) loop.run_until_complete(product.destroy_product())
def _oauth(_test_app): """Return an instance of OauthHelper to the test""" return OauthHelper(client_id=_test_app.client_id, client_secret=_test_app.client_secret, redirect_uri=_test_app.callback_url)