Skip to content

Commit 9044e7e

Browse files
Merge pull request #9 from NHSDigital/AMB-577-migrate-tests-from-mock-proxy
AMB-577 Add 200 ok response to user-role-service endpoint
2 parents 5bdb923 + e9d75c6 commit 9044e7e

File tree

6 files changed

+188
-12
lines changed

6 files changed

+188
-12
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ test:
5555

5656
smoketest:
5757
# this target is for end to end smoketests this would be run 'post deploy' to verify an environment is working
58-
poetry run pytest -v --junitxml=smoketest-report.xml -s -m smoketest
58+
poetry run pytest -v tests/api_tests.py --junitxml=smoketest-report.xml -s

azure/templates/run-integration-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ steps:
1717
export OAUTH_PROXY="oauth2"
1818
export SERVICE_NAME="$(FULLY_QUALIFIED_SERVICE_NAME)"
1919
export ID_TOKEN_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(ID_TOKEN_TESTING_PRIVATE_KEY)"
20+
export ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(ID_TOKEN_NHS_LOGIN_PRIVATE_KEY)"
2021
export JWT_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_PRIVATE_KEY)"
2122
export APIGEE_API_TOKEN="$(secret.AccessToken)"
2223
pytest --reruns 5 --reruns-delay 1 -v --junitxml=test-report.xml

proxies/live/apiproxy/proxies/default.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
<Name>FlowCallout.UserRoleService</Name>
77
</Step>
88
</Request>
9+
<Response>
10+
<Step>
11+
<Name>AssignMessage.AddPayloadToPing</Name>
12+
</Step>
13+
</Response>
914
<Condition>proxy.pathsuffix MatchesPath "/user-role-service"</Condition>
1015
</Flow>
1116
<Flow name="OptionsPreFlight">
@@ -67,6 +72,9 @@
6772
<RouteRule name="NoRouteStatus">
6873
<Condition>(proxy.pathsuffix MatchesPath "/_status") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
6974
</RouteRule>
75+
<RouteRule name="NoRouteUserServiceRole">
76+
<Condition>(proxy.pathsuffix MatchesPath "/user-service-role") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
77+
</RouteRule>
7078
<RouteRule name="shared-flow-testing-target">
7179
<TargetEndpoint>shared-flow-testing-target</TargetEndpoint>
7280
</RouteRule>

tests/configuration/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
ENVIRONMENT = ENV["environment"]
66
BASE_URL = f"https://{ENVIRONMENT}.api.service.nhs.uk"
77
BASE_PATH = ENV["base_path"]
8+
9+
# Jwt variables
10+
JWT_PRIVATE_KEY_ABSOLUTE_PATH = ENV["jwt_private_key_absolute_path"]
11+
ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH = ENV["id_token_nhs_login_private_key_absolute_path"]

tests/configuration/environment.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ def get_env(variable_name: str) -> str:
1616
# Apigee
1717
"environment": get_env("APIGEE_ENVIRONMENT"),
1818
"base_path": get_env("SERVICE_BASE_PATH"),
19+
"jwt_private_key_absolute_path": get_env("JWT_PRIVATE_KEY_ABSOLUTE_PATH"),
20+
"id_token_nhs_login_private_key_absolute_path": get_env("ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH")
1921
}

tests/test_endpoints.py

Lines changed: 172 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import pytest
22
import requests
3+
from time import time
34
from assertpy import assert_that
5+
from .configuration import config
46
from api_test_utils.oauth_helper import OauthHelper
57
from api_test_utils.apigee_api_apps import ApigeeApiDeveloperApps
68
from api_test_utils.apigee_api_products import ApigeeApiProducts
79

810

911
class TestEndpoints:
10-
1112
@pytest.fixture()
1213
def app(self):
1314
"""
@@ -40,11 +41,21 @@ async def test_app_and_product(self, app, product):
4041

4142
await app.create_new_app()
4243

43-
await product.update_scopes([
44-
"urn:nhsd:apim:app:level3:shared-flow-testing",
45-
"urn:nhsd:apim:user-nhs-id:aal3:shared-flow-testing"
46-
])
44+
await product.update_scopes(
45+
[
46+
"urn:nhsd:apim:app:level3:shared-flow-testing",
47+
"urn:nhsd:apim:user-nhs-id:aal3:shared-flow-testing",
48+
"urn:nhsd:apim:user-nhs-login:P9:shared-flow-testing",
49+
]
50+
)
4751
await app.add_api_product([product.name])
52+
await app.set_custom_attributes(
53+
{
54+
"jwks-resource-url": "https://raw.githubusercontent.com/NHSDigital/"
55+
"identity-service-jwks/main/jwks/internal-dev/"
56+
"9baed6f4-1361-4a8e-8531-1f8426e3aba8.json"
57+
}
58+
)
4859

4960
yield product, app
5061

@@ -58,22 +69,130 @@ async def get_token(self, test_app_and_product):
5869
oauth = OauthHelper(
5970
client_id=test_app.client_id,
6071
client_secret=test_app.client_secret,
61-
redirect_uri=test_app.callback_url
62-
)
72+
redirect_uri=test_app.callback_url,
73+
)
6374
token_resp = await oauth.get_token_response(grant_type="authorization_code")
6475
assert token_resp["status_code"] == 200
65-
return token_resp['body']
76+
return token_resp["body"]
77+
78+
@pytest.fixture()
79+
async def get_token_client_credentials(self, test_app_and_product):
80+
"""Call identity server to get an access token"""
81+
test_product, test_app = test_app_and_product
82+
oauth = OauthHelper(
83+
client_id=test_app.client_id,
84+
client_secret=test_app.client_secret,
85+
redirect_uri=test_app.callback_url,
86+
)
87+
jwt = oauth.create_jwt(kid="test-1")
88+
token_resp = await oauth.get_token_response(
89+
grant_type="client_credentials", _jwt=jwt
90+
)
91+
assert token_resp["status_code"] == 200
92+
return token_resp["body"]
93+
94+
@pytest.fixture()
95+
async def get_token_nhs_login_token_exchange(self, test_app_and_product):
96+
"""Call identity server to get an access token"""
97+
test_product, test_app = test_app_and_product
98+
oauth = OauthHelper(
99+
client_id=test_app.client_id,
100+
client_secret=test_app.client_secret,
101+
redirect_uri=test_app.callback_url,
102+
)
103+
104+
id_token_claims = {
105+
"aud": "tf_-APIM-1",
106+
"id_status": "verified",
107+
"token_use": "id",
108+
"auth_time": 1616600683,
109+
"iss": "https://internal-dev.api.service.nhs.uk",
110+
"vot": "P9.Cp.Cd",
111+
"exp": int(time()) + 600,
112+
"iat": int(time()) - 10,
113+
"vtm": "https://auth.sandpit.signin.nhs.uk/trustmark/auth.sandpit.signin.nhs.uk",
114+
"jti": "b68ddb28-e440-443d-8725-dfe0da330118",
115+
"identity_proofing_level": "P9",
116+
}
117+
id_token_headers = {
118+
"sub": "49f470a1-cc52-49b7-beba-0f9cec937c46",
119+
"aud": "APIM-1",
120+
"kid": "nhs-login",
121+
"iss": "https://internal-dev.api.service.nhs.uk",
122+
"typ": "JWT",
123+
"exp": 1616604574,
124+
"iat": 1616600974,
125+
"alg": "RS512",
126+
"jti": "b68ddb28-e440-443d-8725-dfe0da330118",
127+
}
128+
with open(config.ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH, "r") as f:
129+
contents = f.read()
130+
131+
client_assertion_jwt = oauth.create_jwt(kid="test-1")
132+
id_token_jwt = oauth.create_id_token_jwt(
133+
algorithm="RS512",
134+
claims=id_token_claims,
135+
headers=id_token_headers,
136+
signing_key=contents,
137+
)
138+
139+
# When
140+
token_resp = await oauth.get_token_response(
141+
grant_type="token_exchange",
142+
data={
143+
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
144+
"subject_token_type": "urn:ietf:params:oauth:token-type:id_token",
145+
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
146+
"subject_token": id_token_jwt,
147+
"client_assertion": client_assertion_jwt,
148+
},
149+
)
150+
assert token_resp["status_code"] == 200
151+
return token_resp["body"]
152+
153+
@pytest.mark.asyncio
154+
async def test_happy_path(self, get_token):
155+
# Given
156+
token = get_token["access_token"]
157+
expected_status_code = 200
158+
159+
# When
160+
response = requests.get(
161+
url="https://internal-dev.api.service.nhs.uk/shared-flow-testing/user-role-service",
162+
headers={
163+
"Authorization": f"Bearer {token}",
164+
"NHSD-Session-URID": "555254242102",
165+
},
166+
)
66167

67-
def test_user_invalid_role_in_header(self, get_token):
168+
# Then
169+
assert_that(expected_status_code).is_equal_to(response.status_code)
170+
171+
@pytest.mark.asyncio
172+
async def test_default_role(self, get_token):
173+
# Given
174+
token = get_token["access_token"]
175+
expected_status_code = 200
176+
177+
# When
178+
response = requests.get(
179+
url="https://internal-dev.api.service.nhs.uk/shared-flow-testing/user-role-service",
180+
headers={"Authorization": f"Bearer {token}"},
181+
)
182+
# Then
183+
assert_that(expected_status_code).is_equal_to(response.status_code)
184+
185+
@pytest.mark.asyncio
186+
async def test_user_invalid_role_in_header(self, get_token):
68187
# Given
69-
token = get_token['access_token']
188+
token = get_token["access_token"]
70189
expected_status_code = 400
71190
expected_error = "invalid role"
72191
expected_error_description = "nhsd-session-urid is invalid"
73192

74193
# When
75194
response = requests.get(
76-
url='https://internal-dev.api.service.nhs.uk/shared-flow-testing-pr-6/user-role-service',
195+
url="https://internal-dev.api.service.nhs.uk/shared-flow-testing/user-role-service",
77196
headers={
78197
"Authorization": f"Bearer {token}",
79198
"NHSD-Session-URID": "notAuserRole123",
@@ -86,3 +205,45 @@ def test_user_invalid_role_in_header(self, get_token):
86205
assert_that(expected_error_description).is_equal_to(
87206
response.json()["error_description"]
88207
)
208+
209+
@pytest.mark.asyncio
210+
async def test_no_role_provided(self, get_token_client_credentials):
211+
token = get_token_client_credentials["access_token"]
212+
# Given
213+
expected_status_code = 400
214+
expected_error = "invalid role"
215+
expected_error_description = "selected_roleid is missing in your token"
216+
217+
# When
218+
response = requests.get(
219+
url="https://internal-dev.api.service.nhs.uk/shared-flow-testing/user-role-service",
220+
headers={"Authorization": f"Bearer {token}"},
221+
)
222+
# Then
223+
assert_that(expected_status_code).is_equal_to(response.status_code)
224+
assert_that(expected_error).is_equal_to(response.json()["error"])
225+
assert_that(expected_error_description).is_equal_to(
226+
response.json()["error_description"]
227+
)
228+
229+
@pytest.mark.asyncio
230+
async def test_nhs_login_exchanged_token_no_role_provided(
231+
self, get_token_nhs_login_token_exchange
232+
):
233+
token = get_token_nhs_login_token_exchange["access_token"]
234+
# Given
235+
expected_status_code = 400
236+
expected_error = "invalid role"
237+
expected_error_description = "selected_roleid is missing in your token"
238+
239+
# When
240+
response = requests.get(
241+
url="https://internal-dev.api.service.nhs.uk/shared-flow-testing/user-role-service",
242+
headers={"Authorization": f"Bearer {token}"},
243+
)
244+
# Then
245+
assert_that(expected_status_code).is_equal_to(response.status_code)
246+
assert_that(expected_error).is_equal_to(response.json()["error"])
247+
assert_that(expected_error_description).is_equal_to(
248+
response.json()["error_description"]
249+
)

0 commit comments

Comments
 (0)