Skip to content

Commit 25a518a

Browse files
FLAGSAPI-1046 return 400 if we cannot retrieve job role code (#648)
* Change AcsService getUserRoleCodeAndId() to throw a BadRequestException if we are unable to retrieve the users job role code * Changed GetScrIdUAT to return 400 if unable to retrieve user role code - corrected path problem when building attachment resource url - corrected documentation to advise using combined auth-authentication * fixed stubFailedSdsService test function * FLAGSAPI-1046 reverted formatting changes * FLAGSAPI-1046 reverted most of the the auto formatting changes to simplify PR * Revert one more whitespace change * FLAGSAPI-1046 corrected test method name * FLAGSAPI-1046 reverted gitignore file * FLAGSAPI-1046 reverted change to ATTACHMENT_URL in GetScrService.java * FLAGSAPI-1046 simplified code by pre building an error string * FLAGSAPI-1046 fixed pipeline build python version error by specifying python 3.9 in run-tests yaml files * Fix editorconfig * Approved --------- Co-authored-by: Gareth Somerville <gareth.somerville2@nhs.net>
1 parent a7320cf commit 25a518a

File tree

8 files changed

+150
-100
lines changed

8 files changed

+150
-100
lines changed

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ end_of_line = lf
1111
[Makefile]
1212
indent_style = tab
1313

14-
[*.{xml,js,json,yaml}]
14+
[*.{xml,js,json,yaml,yml}]
1515
indent_size = 2
1616

1717
[*.postman_collection.json]

azure/templates/run-tests-int.yml

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ parameters:
55
default: false
66

77
steps:
8+
- task: UsePythonVersion@0
9+
inputs:
10+
versionSpec: "3.9"
11+
812
- task: s3-cache-action@1
913
inputs:
10-
key: 'poetry | $(SERVICE_NAME) | $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/poetry.lock'
11-
location: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/.venv'
14+
key: "poetry | $(SERVICE_NAME) | $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/poetry.lock"
15+
location: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/.venv"
1216
debug: true
13-
alias: 'Pytest'
17+
alias: "Pytest"
1418
displayName: cache pytest dependencies
1519

1620
- bash: |
@@ -20,44 +24,44 @@ steps:
2024
displayName: Setup pytests
2125
# Smoketests
2226
- ${{ if parameters.smoke_tests }}:
23-
- template: "azure/components/aws-assume-role.yml@common"
24-
parameters:
25-
role: "auto-ops"
26-
profile: "apm_ptl"
27-
- template: "azure/components/get-aws-secrets-and-ssm-params.yml@common"
28-
parameters:
29-
secret_file_ids:
30-
- ptl/app-credentials/jwt_testing/non-prod/JWT_TESTING_PRIVATE_KEY
31-
- ptl/app-credentials/jwt_testing/non-prod/ID_TOKEN_NHS_LOGIN_PRIVATE_KEY
32-
config_ids:
33-
- /ptl/azure-devops/summary-care-record/int/CLIENT_ID_INT
34-
secret_ids:
35-
- ptl/azure-devops/summary-care-record/int/CLIENT_SECRET_INT
36-
- bash: |
37-
wait
38-
sleep 350
39-
export RELEASE_RELEASEID=$(Build.BuildId)
40-
export SOURCE_COMMIT_ID=$(Build.SourceVersion)
41-
export APIGEE_ENVIRONMENT="$(ENVIRONMENT)"
42-
export SERVICE_BASE_PATH="$(SERVICE_BASE_PATH)"
43-
export STATUS_ENDPOINT_API_KEY="$(status-endpoint-api-key)"
44-
export APIGEE_PRODUCT="$(FULLY_QUALIFIED_SERVICE_NAME)"
45-
export OAUTH_PROXY="oauth2"
46-
export OAUTH_BASE_URI="https://$(ENVIRONMENT).api.service.nhs.uk"
47-
export APIGEE_API_TOKEN="$(secret.AccessToken)"
48-
export REDIRECT_URI="https://example.org/callback"
49-
export CLIENT_ID="$(CLIENT_ID_INT)"
50-
export CLIENT_SECRET="$(CLIENT_SECRET_INT)"
51-
export JWT_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_PRIVATE_KEY)"
52-
export ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(ID_TOKEN_NHS_LOGIN_PRIVATE_KEY)"
53-
export JWT_PRIVATE_KEY_APP_RESTRICTED_ABSOLUTE_PATH=""
54-
export AUTHENTICATE_URL=""
55-
make prod-smoketest
56-
workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)
57-
displayName: Run smoketests
58-
- task: PublishTestResults@2
59-
displayName: 'Publish smoketest results'
60-
condition: always()
61-
inputs:
62-
testResultsFiles: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/smoketest-report.xml'
63-
failTaskOnFailedTests: true
27+
- template: "azure/components/aws-assume-role.yml@common"
28+
parameters:
29+
role: "auto-ops"
30+
profile: "apm_ptl"
31+
- template: "azure/components/get-aws-secrets-and-ssm-params.yml@common"
32+
parameters:
33+
secret_file_ids:
34+
- ptl/app-credentials/jwt_testing/non-prod/JWT_TESTING_PRIVATE_KEY
35+
- ptl/app-credentials/jwt_testing/non-prod/ID_TOKEN_NHS_LOGIN_PRIVATE_KEY
36+
config_ids:
37+
- /ptl/azure-devops/summary-care-record/int/CLIENT_ID_INT
38+
secret_ids:
39+
- ptl/azure-devops/summary-care-record/int/CLIENT_SECRET_INT
40+
- bash: |
41+
wait
42+
sleep 350
43+
export RELEASE_RELEASEID=$(Build.BuildId)
44+
export SOURCE_COMMIT_ID=$(Build.SourceVersion)
45+
export APIGEE_ENVIRONMENT="$(ENVIRONMENT)"
46+
export SERVICE_BASE_PATH="$(SERVICE_BASE_PATH)"
47+
export STATUS_ENDPOINT_API_KEY="$(status-endpoint-api-key)"
48+
export APIGEE_PRODUCT="$(FULLY_QUALIFIED_SERVICE_NAME)"
49+
export OAUTH_PROXY="oauth2"
50+
export OAUTH_BASE_URI="https://$(ENVIRONMENT).api.service.nhs.uk"
51+
export APIGEE_API_TOKEN="$(secret.AccessToken)"
52+
export REDIRECT_URI="https://example.org/callback"
53+
export CLIENT_ID="$(CLIENT_ID_INT)"
54+
export CLIENT_SECRET="$(CLIENT_SECRET_INT)"
55+
export JWT_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_PRIVATE_KEY)"
56+
export ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(ID_TOKEN_NHS_LOGIN_PRIVATE_KEY)"
57+
export JWT_PRIVATE_KEY_APP_RESTRICTED_ABSOLUTE_PATH=""
58+
export AUTHENTICATE_URL=""
59+
make prod-smoketest
60+
workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)
61+
displayName: Run smoketests
62+
- task: PublishTestResults@2
63+
displayName: "Publish smoketest results"
64+
condition: always()
65+
inputs:
66+
testResultsFiles: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/smoketest-report.xml"
67+
failTaskOnFailedTests: true

azure/templates/run-tests-prod.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
steps:
2+
- task: UsePythonVersion@0
3+
inputs:
4+
versionSpec: "3.9"
5+
26
- task: s3-cache-action@1
37
inputs:
4-
key: 'poetry | $(SERVICE_NAME) | $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/poetry.lock'
5-
location: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/.venv'
8+
key: "poetry | $(SERVICE_NAME) | $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/poetry.lock"
9+
location: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/.venv"
610
debug: true
7-
alias: 'Pytest'
11+
alias: "Pytest"
812
displayName: cache pytest dependencies
913

1014
- bash: |
@@ -41,8 +45,8 @@ steps:
4145
workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)
4246
displayName: Run smoketests
4347
- task: PublishTestResults@2
44-
displayName: 'Publish smoketest results'
48+
displayName: "Publish smoketest results"
4549
condition: always()
4650
inputs:
47-
testResultsFiles: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/smoketest-report.xml'
51+
testResultsFiles: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/smoketest-report.xml"
4852
failTaskOnFailedTests: true

azure/templates/run-tests.yml

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ parameters:
55
default: false
66

77
steps:
8+
- task: UsePythonVersion@0
9+
inputs:
10+
versionSpec: "3.9"
11+
812
- task: s3-cache-action@1
913
inputs:
10-
key: 'poetry | $(SERVICE_NAME) | $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/poetry.lock'
11-
location: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/.venv'
14+
key: "poetry | $(SERVICE_NAME) | $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/poetry.lock"
15+
location: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/.venv"
1216
debug: true
13-
alias: 'Pytest'
17+
alias: "Pytest"
1418
displayName: cache pytest dependencies
1519

1620
- bash: |
@@ -20,44 +24,44 @@ steps:
2024
displayName: Setup pytests
2125
# Smoketests.
2226
- ${{ if parameters.smoke_tests }}:
23-
- template: "azure/components/aws-assume-role.yml@common"
24-
parameters:
25-
role: "auto-ops"
26-
profile: "apm_ptl"
27-
- template: "azure/components/get-aws-secrets-and-ssm-params.yml@common"
28-
parameters:
29-
secret_file_ids:
30-
- ptl/app-credentials/jwt_testing/non-prod/JWT_TESTING_PRIVATE_KEY
31-
- ptl/app-credentials/jwt_testing/non-prod/ID_TOKEN_NHS_LOGIN_PRIVATE_KEY
32-
- ptl/azure-devops/summary-care-record/JWT_TESTING_APP_RESTRICTED_PRIVATE_KEY
33-
config_ids:
34-
- /ptl/azure-devops/env-internal-dev/test-app/internal-testing-internal-dev/CLIENT_ID
35-
- /ptl/azure-devops/env-internal-dev/test-app/internal-testing-internal-dev/CLIENT_SECRET
36-
- bash: |
37-
wait
38-
sleep 350
39-
export RELEASE_RELEASEID=$(Build.BuildId)
40-
export SOURCE_COMMIT_ID=$(Build.SourceVersion)
41-
export APIGEE_ENVIRONMENT="$(ENVIRONMENT)"
42-
export SERVICE_BASE_PATH="$(SERVICE_BASE_PATH)"
43-
export STATUS_ENDPOINT_API_KEY="$(status-endpoint-api-key)"
44-
export APIGEE_PRODUCT="$(FULLY_QUALIFIED_SERVICE_NAME)"
45-
export OAUTH_PROXY="oauth2-mock"
46-
export OAUTH_BASE_URI="https://$(ENVIRONMENT).api.service.nhs.uk"
47-
export APIGEE_API_TOKEN="$(secret.AccessToken)"
48-
export REDIRECT_URI="https://example.org/callback"
49-
export CLIENT_ID="$(CLIENT_ID)"
50-
export CLIENT_SECRET="$(CLIENT_SECRET)"
51-
export JWT_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_PRIVATE_KEY)"
52-
export JWT_PRIVATE_KEY_APP_RESTRICTED_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_APP_RESTRICTED_PRIVATE_KEY)"
53-
export ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(ID_TOKEN_NHS_LOGIN_PRIVATE_KEY)"
54-
export AUTHENTICATE_URL="https://nhsd-apim-testing-internal-dev.herokuapp.com/"
55-
make smoketest
56-
workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)
57-
displayName: Run smoketests
58-
- task: PublishTestResults@2
59-
displayName: 'Publish smoketest results'
60-
condition: always()
61-
inputs:
62-
testResultsFiles: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/smoketest-report.xml'
63-
failTaskOnFailedTests: true
27+
- template: "azure/components/aws-assume-role.yml@common"
28+
parameters:
29+
role: "auto-ops"
30+
profile: "apm_ptl"
31+
- template: "azure/components/get-aws-secrets-and-ssm-params.yml@common"
32+
parameters:
33+
secret_file_ids:
34+
- ptl/app-credentials/jwt_testing/non-prod/JWT_TESTING_PRIVATE_KEY
35+
- ptl/app-credentials/jwt_testing/non-prod/ID_TOKEN_NHS_LOGIN_PRIVATE_KEY
36+
- ptl/azure-devops/summary-care-record/JWT_TESTING_APP_RESTRICTED_PRIVATE_KEY
37+
config_ids:
38+
- /ptl/azure-devops/env-internal-dev/test-app/internal-testing-internal-dev/CLIENT_ID
39+
- /ptl/azure-devops/env-internal-dev/test-app/internal-testing-internal-dev/CLIENT_SECRET
40+
- bash: |
41+
wait
42+
sleep 350
43+
export RELEASE_RELEASEID=$(Build.BuildId)
44+
export SOURCE_COMMIT_ID=$(Build.SourceVersion)
45+
export APIGEE_ENVIRONMENT="$(ENVIRONMENT)"
46+
export SERVICE_BASE_PATH="$(SERVICE_BASE_PATH)"
47+
export STATUS_ENDPOINT_API_KEY="$(status-endpoint-api-key)"
48+
export APIGEE_PRODUCT="$(FULLY_QUALIFIED_SERVICE_NAME)"
49+
export OAUTH_PROXY="oauth2-mock"
50+
export OAUTH_BASE_URI="https://$(ENVIRONMENT).api.service.nhs.uk"
51+
export APIGEE_API_TOKEN="$(secret.AccessToken)"
52+
export REDIRECT_URI="https://example.org/callback"
53+
export CLIENT_ID="$(CLIENT_ID)"
54+
export CLIENT_SECRET="$(CLIENT_SECRET)"
55+
export JWT_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_PRIVATE_KEY)"
56+
export JWT_PRIVATE_KEY_APP_RESTRICTED_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(JWT_TESTING_APP_RESTRICTED_PRIVATE_KEY)"
57+
export ID_TOKEN_NHS_LOGIN_PRIVATE_KEY_ABSOLUTE_PATH="$(Pipeline.Workspace)/secrets/$(ID_TOKEN_NHS_LOGIN_PRIVATE_KEY)"
58+
export AUTHENTICATE_URL="https://nhsd-apim-testing-internal-dev.herokuapp.com/"
59+
make smoketest
60+
workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)
61+
displayName: Run smoketests
62+
- task: PublishTestResults@2
63+
displayName: "Publish smoketest results"
64+
condition: always()
65+
inputs:
66+
testResultsFiles: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/smoketest-report.xml"
67+
failTaskOnFailedTests: true

docker/service/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,16 @@ dependencies {
5050
testImplementation "io.rest-assured:json-path:4.4.0"
5151
testImplementation "io.rest-assured:xml-path:4.4.0"
5252
testImplementation "com.github.tomakehurst:wiremock-jre8-standalone:2.31.0"
53+
testImplementation(platform('org.junit:junit-bom:5.13.0'))
54+
testImplementation('org.junit.jupiter:junit-jupiter')
55+
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
5356
}
5457

5558
test {
5659
useJUnitPlatform()
60+
testLogging {
61+
events "passed", "skipped", "failed"
62+
}
5763
}
5864

5965
sourceSets {

docker/service/src/integration-test/java/uk/nhs/adaptors/scr/uat/SetAcsUAT.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,20 @@ public void testSetAcsPermissionBadRequest(TestData testData) throws Exception {
121121
.andExpect(content().json(testData.getFhirResponse()));
122122
}
123123

124+
@ParameterizedTest(name = "[{index}] - {0}")
125+
@ArgumentsSource(SetAcsBadRequest.class)
126+
public void testSetAcsPermissionNoRoleCodeBadRequest(TestData testData) throws Exception {
127+
// FLAGSAPI-1046 should return Bad Request if no role code is returned from SDS
128+
// or Identity Service
129+
stubFailedIdentityService();
130+
stubFailedSdsService();
131+
stubSpineAcsEndpoint(acsErrorResponse);
132+
133+
performRequest(testData.getFhirRequest())
134+
.andExpect(status().isBadRequest())
135+
.andExpect(content().json(testData.getFhirResponse()));
136+
}
137+
124138
private ResultActions performRequest(String request) throws Exception {
125139
return mockMvc.perform(post(ACS_ENDPOINT)
126140
.contentType(APPLICATION_FHIR_JSON)
@@ -154,6 +168,17 @@ private void stubSdsService(Resource response) throws IOException {
154168
.withBody(readString(response.getFile().toPath(), UTF_8))));
155169
}
156170

171+
private void stubFailedSdsService() {
172+
wireMockServer.stubFor(
173+
WireMock.get(WireMock.urlPathEqualTo(PRACTITIONER_ROLE_ENDPOINT))
174+
.withQueryParam(USER_ID_QUERY_PARAM,
175+
containing(NHSD_SESSION_URID))
176+
.willReturn(aResponse()
177+
.withStatus(OK.value())
178+
.withHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
179+
.withBody("")));
180+
}
181+
157182
private void stubIdentityService(Resource response) throws IOException {
158183
wireMockServer.stubFor(
159184
WireMock.get(USER_INFO_ENDPOINT)

docker/service/src/main/java/uk/nhs/adaptors/scr/services/AcsService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,21 @@ private Pair<String, String> getUserRoleCodeAndId(String authorisation, String n
9090

9191
}
9292

93+
String errorMessage = String.format("Unable to determine Job Role Code for "
94+
+ "the given RoleID via the SDS Service: %s", nhsdSessionUrid);
95+
96+
// if we haven't retrieved a role code from openID we try the SDS service
9397
try {
94-
return Pair.of(sdsService.getUserRoleCode(nhsdSessionUrid), nhsdIdentity);
98+
var roleCode = sdsService.getUserRoleCode(nhsdSessionUrid);
99+
if (roleCode != null && !roleCode.isEmpty()) {
100+
return Pair.of(roleCode, nhsdIdentity);
101+
}
95102
} catch (BadRequestException | URISyntaxException e) {
96-
throw new BadRequestException(String.format("Unable to determine SDS Job Role Code for "
97-
+ "the given RoleID: %s", nhsdSessionUrid));
103+
LOGGER.info(errorMessage);
104+
throw new BadRequestException(errorMessage);
98105
}
106+
LOGGER.info(errorMessage);
107+
throw new BadRequestException(errorMessage);
99108
}
100109

101110
private String prepareAcsRequest(ParametersParameterComponent parameter, RequestData requestData, String sdsJobRoleCode,

specification/summary-care-record.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,8 @@ info:
8888
- a health or care staff providing direct care to patients
8989
- strongly authenticated, using either an [NHS smartcard or a modern alternative](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/nhs-smartcards-for-developers) available via [NHS Care Identity Service 2 (NHS CIS2)](https://digital.nhs.uk/services/nhs-identity)
9090
91-
The API uses OAuth 2.0 to authorise the calling system. It supports the following security patterns:
92-
91+
The API uses OAuth 2.0 to authorise the calling system. It only supports CIS2 combined authentication and authorisation (see link below). Do not use separate authentication and authorisation:
9392
- [user-restricted RESTful API - using NHS CIS2 - combined authentication and authorisation](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/user-restricted-restful-apis-nhs-cis2-combined-authentication-and-authorisation)
94-
- [user-restricted RESTful API - using NHS CIS2 - separate authentication and authorisation](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/user-restricted-restful-apis-nhs-cis2-separate-authentication-and-authorisation)
9593
9694
For more details, see [user-restricted APIs](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation#user-restricted-apis).
9795

0 commit comments

Comments
 (0)