Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions proxies/live/apiproxy/policies/MirrorRequestHeaders.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Script async="false" continueOnError="true" enabled="true" name="MirrorRequestHeaders">
<DisplayName>Mirror Request Headers</DisplayName>
<Properties/>
<ResourceURL>py://mirror-request-headers.py</ResourceURL>
</Script>
6 changes: 6 additions & 0 deletions proxies/live/apiproxy/policies/TranslateRequestHeaders.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Script async="false" continueOnError="true" enabled="true" name="TranslateRequestHeaders">
<DisplayName>Translate Request Headers</DisplayName>
<Properties/>
<ResourceURL>py://translate-request-headers.py</ResourceURL>
</Script>
10 changes: 10 additions & 0 deletions proxies/live/apiproxy/resources/py/mirror-request-headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
translated_header_names = ["X-Request-ID", "X-Correlation-ID"]
for translated_header_name in translated_header_names:
# Access original request headers dictionary
original_request_header = flow.getVariable("original_request_header." + translated_header_name)
if original_request_header:
original_request_header = original_request_header.split("=")
# Remove original response header
flow.removeVariable("response.header." + translated_header_name)
# Mirror original request header
flow.setVariable("response.header." + original_request_header[0], original_request_header[1])
27 changes: 27 additions & 0 deletions proxies/live/apiproxy/resources/py/translate-request-headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
def get_request_headers():
request_header_names = flow.getVariable("request.headers.names")
request_headers = {}
for name in request_header_names:
request_headers[name] = flow.getVariable("request.header." + name)

return request_headers


# Access request headers dictionary
request_headers = get_request_headers()

# Map of lowercase header name to desired parcel case header name
request_header_translation = {"x-request-id": "X-Request-ID", "x-correlation-id": "X-Correlation-ID"}

# Loop through request headers
for original_header_name, header_value in request_headers.items():
desired_header_name = request_header_translation.get(original_header_name.lower())
if desired_header_name:
# Store original header against the desired name for mirroring in response
flow.setVariable(
"original_request_header." + desired_header_name, "%s=%s" % (original_header_name, header_value)
)
# Remove original request header
flow.removeVariable("request.header." + original_header_name)
# Set header with correct casing
flow.setVariable("request.header." + desired_header_name, header_value)
25 changes: 22 additions & 3 deletions proxies/live/apiproxy/targets/target.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<Step>
<Name>FlowCallout.ApplyRateLimiting</Name>
</Step>
<Step>
<Name>TranslateRequestHeaders</Name>
</Step>
<Step>
<Name>AddDeveloperAppData</Name>
</Step>
Expand Down Expand Up @@ -45,7 +48,7 @@
</Step>
</Request>
</Flow>
<Flow name ="User Restricted">
<Flow name="User Restricted">
<Condition>accesstoken.auth_type = "user"</Condition>
<Request>
<Step>
Expand All @@ -64,28 +67,44 @@
</Request>
</Flow>
</Flows>

<PostFlow>
<Response>
<Step>
<Name>SetMimeType</Name>
</Step>
<Step>
<Name>MirrorRequestHeaders</Name>
</Step>
</Response>
</PostFlow>
<FaultRules>
<DefaultFaultRule name="default">
<Step>
<Name>MirrorRequestHeaders</Name>
</Step>
</DefaultFaultRule>
<FaultRule name="401_Unauthorized">
<Step>
<Name>MirrorRequestHeaders</Name>
</Step>
<Step>
<Name>RaiseFault.401Unauthorized</Name>
</Step>
<Condition>oauthV2.OauthV2.VerifyAccessToken.failed = true or fault.name = "invalid_access_token" or fault.name = "InvalidAccessToken" or fault.name = "access_token_not_approved" or fault.name = "apiresource_doesnot_exist" or fault.name = "InvalidAPICallAsNo" or fault.name = "ApiProductMatchFound" or fault.name = "access_token_expired"</Condition>
</FaultRule>
<FaultRule name="404_Not_Found">
<Step>
<Name>MirrorRequestHeaders</Name>
</Step>
<Step>
<Name>RaiseFault.404NotFound</Name>
</Step>
<Condition>response.header.x-amzn-ErrorType = "IncompleteSignatureException"</Condition>
</FaultRule>
<FaultRule name="ApplicationOperationOutcome">
<Step>
<Name>MirrorRequestHeaders</Name>
</Step>
<Step>
<Name>RaiseFault.ApplicationOperationOutcome</Name>
<Condition>response.header.x-amzn-RequestId != null</Condition>
Expand All @@ -101,4 +120,4 @@
<Property name="request.retain.headers">User-Agent,Referer,Accept-Language</Property>
</Properties>
</HTTPTargetConnection>
</TargetEndpoint>
</TargetEndpoint>
3 changes: 3 additions & 0 deletions specification/validated-relationships-service-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ info:
|[NHS login - combined authentication and authorisation](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/user-restricted-restful-apis-nhs-login-combined-authentication-and-authorisation) |OAuth 2.0 authorisation code with API key and secret |No need to integrate and onboard separately with NHS login. |No access to user information. |
|[NHS login - separate authentication and authorisation](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/user-restricted-restful-apis-nhs-login-separate-authentication-and-authorisation) |OAuth 2.0 token exchange with signed JWT |Gives access to user information. |Need to integrate and onboard separately with NHS login. |

## Headers
This API is case-insensitive when processing request headers, meaning it will accept headers regardless of the letter casing used. (e.g. X-Request-Id, x-request-id are treated the same). When sending headers back in the response, we preserve the exact casing as received in the original request.

## Errors
We use standard HTTP status codes to show whether an API request succeeded or not. They are usually in the range:

Expand Down