Skip to content

Commit df0cc2e

Browse files
authored
Merge pull request #32 from NHSDigital/AMB-804-test-apikey-protected-endpoints-logs
AMB-804 add apikey protected endpoint
2 parents fa20d6a + 7f8b18a commit df0cc2e

File tree

6 files changed

+184
-8
lines changed

6 files changed

+184
-8
lines changed

azure/templates/run-integration-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ steps:
2020
export STATUS_ENDPOINT_API_KEY="$(status-endpoint-api-key)"
2121
export APIGEE_API_TOKEN="$(secret.AccessToken)"
2222
export OAUTH_PROXY="oauth2"
23+
export APP_CLIENT_ID="Too5BdPayTQACdw1AJK1rD4nKUD0Ag7J"
2324
export OAUTH_BASE_URI="https://$(APIGEE_ENVIRONMENT).api.service.nhs.uk"
2425
export ACCESS_TOKEN_HASH_SECRET="$(ACCESS_TOKEN_SECRET)"
2526
./test_env/bin/pytest --reruns 2 --reruns-delay 1 -v --junitxml=test-report.xml
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<VerifyAPIKey async="false" continueOnError="false" enabled="true" name="VerifyApiKey.Apikey">
3+
<DisplayName>VerifyApiKey.Apikey</DisplayName>
4+
<Properties/>
5+
<APIKey ref="request.header.apikey"/>
6+
</VerifyAPIKey>

proxies/live/apiproxy/proxies/default.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@
6363
</Response>
6464
<Condition>(proxy.pathsuffix MatchesPath "/splunk-test") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
6565
</Flow>
66+
<Flow name="ApiKeyProtectedEndpoint">
67+
<Request>
68+
<Step>
69+
<Name>VerifyApiKey.Apikey</Name>
70+
</Step>
71+
</Request>
72+
<Condition>(proxy.pathsuffix MatchesPath "/apikey-protected") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
73+
</Flow>
6674
<Flow name="OpenAccessEndpoint">
6775
<Condition>(proxy.pathsuffix MatchesPath "/open-access") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
6876
</Flow>
@@ -97,6 +105,9 @@
97105
<RouteRule name="NoRouteOpenAccess">
98106
<Condition>(proxy.pathsuffix MatchesPath "/open-access") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
99107
</RouteRule>
108+
<RouteRule name="NoRouteApiKeyProtected">
109+
<Condition>(proxy.pathsuffix MatchesPath "/apikey-protected") and ((request.verb = "GET") or (request.verb = "HEAD"))</Condition>
110+
</RouteRule>
100111
<RouteRule name="shared-flow-testing-target">
101112
<TargetEndpoint>shared-flow-testing-target</TargetEndpoint>
102113
</RouteRule>

tests/configuration/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
SERVICE_BASE_PATH = ENV['service_base_path']
1414
SERVICE_NAME = ENV['service_name']
1515
ACCESS_TOKEN_HASH_SECRET = environ.get("ACCESS_TOKEN_HASH_SECRET")
16+
APP_CLIENT_ID = environ.get("APP_CLIENT_ID")

tests/splunk_logging_schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
},
121121
"client_id": {
122122
"type": "string",
123-
"pattern": "(^[0-9A-Za-z]{32}$)|^$"
123+
"pattern": "(^[0-9A-Za-z]{32}$)|Not provided"
124124
},
125125
"application_id": {
126126
"type": "string",

tests/test_splunk_logging.py

Lines changed: 164 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
import requests
88
from jsonschema import validate
99

10-
from .configuration.config import SERVICE_BASE_PATH, ENVIRONMENT, ACCESS_TOKEN_HASH_SECRET
10+
from .configuration.config import SERVICE_BASE_PATH, ENVIRONMENT, ACCESS_TOKEN_HASH_SECRET, APP_CLIENT_ID
1111

1212

1313
class TestSplunkLogging:
14-
url = f"https://{ENVIRONMENT}.api.service.nhs.uk/{SERVICE_BASE_PATH}/splunk-test"
14+
oauth_protected_url = f"https://{ENVIRONMENT}.api.service.nhs.uk/{SERVICE_BASE_PATH}/splunk-test"
15+
apikey_protected_url = f"https://{ENVIRONMENT}.api.service.nhs.uk/{SERVICE_BASE_PATH}/apikey-protected"
1516
open_access_url = f"https://{ENVIRONMENT}.api.service.nhs.uk/{SERVICE_BASE_PATH}/open-access"
1617

1718
@staticmethod
@@ -37,7 +38,7 @@ async def test_splunk_auth_with_client_credentials(self, get_token_client_creden
3738
# When
3839
await debug.start_trace()
3940
requests.get(
40-
url=self.url,
41+
url=self.oauth_protected_url,
4142
headers={"Authorization": f"Bearer {token}"},
4243
)
4344
payload = await self._get_payload_from_splunk(debug)
@@ -65,7 +66,7 @@ async def test_splunk_auth_with_authorization_code(self, get_token, debug):
6566
# When
6667
await debug.start_trace()
6768
requests.get(
68-
url=self.url,
69+
url=self.oauth_protected_url,
6970
headers={"Authorization": f"Bearer {token}"},
7071
)
7172
payload = await self._get_payload_from_splunk(debug)
@@ -93,7 +94,7 @@ async def test_splunk_auth_with_cis2_token_exchange(self, get_token_cis2_token_e
9394
# When
9495
await debug.start_trace()
9596
requests.get(
96-
url=self.url,
97+
url=self.oauth_protected_url,
9798
headers={"Authorization": f"Bearer {token}"},
9899
)
99100
payload = await self._get_payload_from_splunk(debug)
@@ -121,7 +122,7 @@ async def test_splunk_auth_with_nhs_login_token_exchange(self, get_token_nhs_log
121122
# When
122123
await debug.start_trace()
123124
requests.get(
124-
url=self.url,
125+
url=self.oauth_protected_url,
125126
headers={"Authorization": f"Bearer {token}"},
126127
)
127128
payload = await self._get_payload_from_splunk(debug)
@@ -139,6 +140,162 @@ async def test_splunk_auth_with_nhs_login_token_exchange(self, get_token_nhs_log
139140
auth_user = auth["user"]
140141
assert auth_user["user_id"] == "900000000001"
141142

143+
@pytest.mark.splunk
144+
@pytest.mark.asyncio
145+
async def test_splunk_auth_with_invalid_token(self, debug):
146+
# Given
147+
token = "invalid token"
148+
expected_hashed_token = ""
149+
150+
# When
151+
await debug.start_trace()
152+
requests.get(
153+
url=self.oauth_protected_url,
154+
headers={"Authorization": f"Bearer {token}"},
155+
)
156+
payload = await self._get_payload_from_splunk(debug)
157+
158+
# Then
159+
auth = payload["auth"]
160+
assert auth["access_token_hash"] == expected_hashed_token
161+
162+
auth_meta = auth["meta"]
163+
assert auth_meta["auth_type"] == "app"
164+
assert auth_meta["grant_type"] == ""
165+
assert auth_meta["level"] == "Level0"
166+
assert auth_meta["provider"] == "apim"
167+
168+
auth_user = auth["user"]
169+
assert auth_user["user_id"] == ""
170+
171+
meta = payload["meta"]
172+
assert meta["client_id"] == "Not provided"
173+
assert meta["application"] == "unknown"
174+
assert meta["product"] == ""
175+
176+
@pytest.mark.splunk
177+
@pytest.mark.asyncio
178+
async def test_splunk_auth_with_expired_token(self, debug):
179+
# Given
180+
token = "zRygtc34R2pwxbiUktLsMJWX0iJW"
181+
expected_hashed_token = ""
182+
183+
# When
184+
await debug.start_trace()
185+
requests.get(
186+
url=self.oauth_protected_url,
187+
headers={"Authorization": f"Bearer {token}"},
188+
)
189+
payload = await self._get_payload_from_splunk(debug)
190+
191+
# Then
192+
auth = payload["auth"]
193+
assert auth["access_token_hash"] == expected_hashed_token
194+
195+
auth_meta = auth["meta"]
196+
assert auth_meta["auth_type"] == "app"
197+
assert auth_meta["grant_type"] == ""
198+
assert auth_meta["level"] == "Level0"
199+
assert auth_meta["provider"] == "apim"
200+
201+
auth_user = auth["user"]
202+
assert auth_user["user_id"] == ""
203+
204+
meta = payload["meta"]
205+
assert meta["client_id"] == "Not provided"
206+
assert meta["application"] == "unknown"
207+
assert meta["product"] == ""
208+
209+
@pytest.mark.splunk
210+
@pytest.mark.asyncio
211+
@pytest.mark.debug
212+
async def test_splunk_auth_with_apikey(self, debug):
213+
# Given
214+
apikey = APP_CLIENT_ID
215+
216+
# When
217+
await debug.start_trace()
218+
requests.get(
219+
url=self.apikey_protected_url,
220+
headers={"apikey": apikey},
221+
)
222+
payload = await self._get_payload_from_splunk(debug)
223+
224+
# Then
225+
auth = payload["auth"]
226+
assert auth["access_token_hash"] == ""
227+
228+
auth_meta = auth["meta"]
229+
assert auth_meta["auth_type"] == "app"
230+
assert auth_meta["grant_type"] == ""
231+
assert auth_meta["level"] == "Level0"
232+
assert auth_meta["provider"] == "apim"
233+
234+
auth_user = auth["user"]
235+
assert auth_user["user_id"] == ""
236+
237+
meta = payload["meta"]
238+
assert meta["client_id"] == apikey
239+
240+
@pytest.mark.splunk
241+
@pytest.mark.asyncio
242+
async def test_splunk_auth_with_invalid_apikey(self, debug):
243+
# Given
244+
apikey = "invalid api key"
245+
246+
# When
247+
await debug.start_trace()
248+
requests.get(
249+
url=self.apikey_protected_url,
250+
headers={"apikey": apikey},
251+
)
252+
payload = await self._get_payload_from_splunk(debug)
253+
254+
# Then
255+
auth = payload["auth"]
256+
assert auth["access_token_hash"] == ""
257+
258+
auth_meta = auth["meta"]
259+
assert auth_meta["auth_type"] == "app"
260+
assert auth_meta["grant_type"] == ""
261+
assert auth_meta["level"] == "Level0"
262+
assert auth_meta["provider"] == "apim"
263+
264+
auth_user = auth["user"]
265+
assert auth_user["user_id"] == ""
266+
267+
meta = payload["meta"]
268+
assert meta["client_id"] == "Not provided"
269+
assert meta["application"] == "unknown"
270+
assert meta["product"] == ""
271+
272+
@pytest.mark.splunk
273+
@pytest.mark.asyncio
274+
async def test_splunk_auth_open_access(self, debug):
275+
# When
276+
await debug.start_trace()
277+
requests.get(
278+
url=self.open_access_url,
279+
)
280+
payload = await self._get_payload_from_splunk(debug)
281+
282+
# Then
283+
auth = payload["auth"]
284+
assert auth["access_token_hash"] == ""
285+
286+
auth_meta = auth["meta"]
287+
assert auth_meta["auth_type"] == "app"
288+
assert auth_meta["grant_type"] == ""
289+
assert auth_meta["level"] == "Level0"
290+
assert auth_meta["provider"] == "apim"
291+
292+
auth_user = auth["user"]
293+
assert auth_user["user_id"] == ""
294+
295+
meta = payload["meta"]
296+
assert meta["client_id"] == "Not provided"
297+
assert meta["application"] == "unknown"
298+
142299
@pytest.mark.splunk
143300
@pytest.mark.asyncio
144301
async def test_splunk_payload_schema(self, get_token, debug):
@@ -148,7 +305,7 @@ async def test_splunk_payload_schema(self, get_token, debug):
148305
# When
149306
await debug.start_trace()
150307
requests.get(
151-
url=self.url,
308+
url=self.oauth_protected_url,
152309
headers={"Authorization": f"Bearer {token}"},
153310
)
154311
payload = await self._get_payload_from_splunk(debug)

0 commit comments

Comments
 (0)