Skip to content

Commit 4c15256

Browse files
committed
implement apply access control to /validate endpoints
1 parent a0e0f9d commit 4c15256

17 files changed

+286
-148
lines changed

src/contractTest/java/uk/gov/hmcts/ccd/v2/external/controller/ContractTestCreateCaseOperation.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
import uk.gov.hmcts.ccd.domain.service.caselinking.CaseLinkService;
1818
import uk.gov.hmcts.ccd.domain.service.common.CaseDataService;
1919
import uk.gov.hmcts.ccd.domain.service.common.CasePostStateService;
20-
import uk.gov.hmcts.ccd.domain.service.common.CaseTypeService;
2120
import uk.gov.hmcts.ccd.domain.service.common.EventTriggerService;
2221
import uk.gov.hmcts.ccd.domain.service.createcase.DefaultCreateCaseOperation;
2322
import uk.gov.hmcts.ccd.domain.service.createcase.SubmitCaseTransaction;
2423
import uk.gov.hmcts.ccd.domain.service.processor.GlobalSearchProcessorService;
2524
import uk.gov.hmcts.ccd.domain.service.stdapi.CallbackInvoker;
2625
import uk.gov.hmcts.ccd.domain.service.supplementarydata.SupplementaryDataUpdateOperation;
2726
import uk.gov.hmcts.ccd.domain.service.validate.CaseDataIssueLogger;
27+
import uk.gov.hmcts.ccd.domain.service.validate.DefaultValidateCaseFieldsOperation;
2828
import uk.gov.hmcts.ccd.domain.service.validate.ValidateCaseFieldsOperation;
2929
import uk.gov.hmcts.ccd.domain.types.sanitiser.CaseSanitiser;
3030

@@ -46,8 +46,9 @@ public ContractTestCreateCaseOperation(@Qualifier(DefaultUserRepository.QUALIFIE
4646
EventTokenService eventTokenService,
4747
CaseDataService caseDataService,
4848
SubmitCaseTransaction submitCaseTransaction,
49-
CaseSanitiser caseSanitiser, CaseTypeService caseTypeService,
49+
CaseSanitiser caseSanitiser,
5050
CallbackInvoker callbackInvoker,
51+
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
5152
ValidateCaseFieldsOperation validateCaseFieldsOperation,
5253
CasePostStateService casePostStateService,
5354
@Qualifier(DefaultDraftGateway.QUALIFIER) DraftGateway draftGateway,
@@ -59,7 +60,7 @@ public ContractTestCreateCaseOperation(@Qualifier(DefaultUserRepository.QUALIFIE
5960
SupplementaryDataUpdateRequestValidator supplementaryDataValidator,
6061
CaseLinkService caseLinkService) {
6162
super(userRepository, caseDefinitionRepository, eventTriggerService, eventTokenService, caseDataService,
62-
submitCaseTransaction, caseSanitiser, caseTypeService, callbackInvoker, validateCaseFieldsOperation,
63+
submitCaseTransaction, caseSanitiser, callbackInvoker, validateCaseFieldsOperation,
6364
casePostStateService, draftGateway, caseDataIssueLogger, globalSearchProcessorService,
6465
supplementaryDataUpdateOperation, supplementaryDataValidator, caseLinkService);
6566
this.contractTestSecurityUtils = contractTestSecurityUtils;

src/main/java/uk/gov/hmcts/ccd/config/JacksonUtils.java

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
public final class JacksonUtils {
2929

30+
public static final String DATA = "data";
31+
3032
private JacksonUtils() {
3133
}
3234

@@ -198,4 +200,12 @@ private static String getValue(@NonNull JsonNode jsonNode) {
198200
}
199201
return returnValue;
200202
}
203+
204+
public static Map<String, JsonNode> convertValueInDataField(Object from) {
205+
Map<String, JsonNode> map = MAPPER.convertValue(from, new TypeReference<HashMap<String, JsonNode>>() {});
206+
207+
Map<String, JsonNode> dataNode = new HashMap<>();
208+
dataNode.put(DATA, MAPPER.valueToTree(map));
209+
return dataNode;
210+
}
201211
}

src/main/java/uk/gov/hmcts/ccd/domain/service/createcase/DefaultCreateCaseOperation.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929
import uk.gov.hmcts.ccd.domain.service.caselinking.CaseLinkService;
3030
import uk.gov.hmcts.ccd.domain.service.common.CaseDataService;
3131
import uk.gov.hmcts.ccd.domain.service.common.CasePostStateService;
32-
import uk.gov.hmcts.ccd.domain.service.common.CaseTypeService;
3332
import uk.gov.hmcts.ccd.domain.service.common.EventTriggerService;
3433
import uk.gov.hmcts.ccd.domain.service.processor.GlobalSearchProcessorService;
3534
import uk.gov.hmcts.ccd.domain.service.stdapi.CallbackInvoker;
3635
import uk.gov.hmcts.ccd.domain.service.supplementarydata.SupplementaryDataUpdateOperation;
3736
import uk.gov.hmcts.ccd.domain.service.validate.CaseDataIssueLogger;
37+
import uk.gov.hmcts.ccd.domain.service.validate.DefaultValidateCaseFieldsOperation;
38+
import uk.gov.hmcts.ccd.domain.service.validate.OperationContext;
3839
import uk.gov.hmcts.ccd.domain.service.validate.ValidateCaseFieldsOperation;
3940
import uk.gov.hmcts.ccd.domain.types.sanitiser.CaseSanitiser;
4041
import uk.gov.hmcts.ccd.endpoint.exceptions.CallbackException;
@@ -57,7 +58,6 @@ public class DefaultCreateCaseOperation implements CreateCaseOperation {
5758
private final CaseDataService caseDataService;
5859
private final SubmitCaseTransaction submitCaseTransaction;
5960
private final CaseSanitiser caseSanitiser;
60-
private final CaseTypeService caseTypeService;
6161
private final CallbackInvoker callbackInvoker;
6262
private final ValidateCaseFieldsOperation validateCaseFieldsOperation;
6363
private final DraftGateway draftGateway;
@@ -77,8 +77,8 @@ public DefaultCreateCaseOperation(@Qualifier(CachedUserRepository.QUALIFIER) fin
7777
final CaseDataService caseDataService,
7878
final SubmitCaseTransaction submitCaseTransaction,
7979
final CaseSanitiser caseSanitiser,
80-
final CaseTypeService caseTypeService,
8180
final CallbackInvoker callbackInvoker,
81+
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
8282
final ValidateCaseFieldsOperation validateCaseFieldsOperation,
8383
final CasePostStateService casePostStateService,
8484
@Qualifier(CachedDraftGateway.QUALIFIER) final DraftGateway draftGateway,
@@ -94,7 +94,6 @@ public DefaultCreateCaseOperation(@Qualifier(CachedUserRepository.QUALIFIER) fin
9494
this.eventTokenService = eventTokenService;
9595
this.submitCaseTransaction = submitCaseTransaction;
9696
this.caseSanitiser = caseSanitiser;
97-
this.caseTypeService = caseTypeService;
9897
this.caseDataService = caseDataService;
9998
this.callbackInvoker = callbackInvoker;
10099
this.validateCaseFieldsOperation = validateCaseFieldsOperation;
@@ -140,7 +139,7 @@ public CaseDetails createCaseDetails(final String caseTypeId,
140139
caseTypeDefinition.getJurisdictionDefinition(),
141140
caseTypeDefinition);
142141

143-
validateCaseFieldsOperation.validateCaseDetails(caseTypeId, caseDataContent);
142+
validateCaseFieldsOperation.validateCaseDetails(new OperationContext(caseTypeId, caseDataContent));
144143

145144
final CaseDetails newCaseDetails = new CaseDetails();
146145

src/main/java/uk/gov/hmcts/ccd/domain/service/createevent/CreateCaseEventService.java

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import uk.gov.hmcts.ccd.domain.service.stdapi.AboutToSubmitCallbackResponse;
4444
import uk.gov.hmcts.ccd.domain.service.stdapi.CallbackInvoker;
4545
import uk.gov.hmcts.ccd.domain.service.validate.CaseDataIssueLogger;
46+
import uk.gov.hmcts.ccd.domain.service.validate.DefaultValidateCaseFieldsOperation;
4647
import uk.gov.hmcts.ccd.domain.service.validate.ValidateCaseFieldsOperation;
4748
import uk.gov.hmcts.ccd.domain.types.sanitiser.CaseSanitiser;
4849
import uk.gov.hmcts.ccd.endpoint.exceptions.BadRequestException;
@@ -113,6 +114,7 @@ public CreateCaseEventService(@Qualifier(CachedUserRepository.QUALIFIER) final U
113114
final CallbackInvoker callbackInvoker,
114115
final UIDService uidService,
115116
final SecurityClassificationServiceImpl securityClassificationService,
117+
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
116118
final ValidateCaseFieldsOperation validateCaseFieldsOperation,
117119
final UserAuthorisation userAuthorisation,
118120
final FieldProcessorService fieldProcessorService,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package uk.gov.hmcts.ccd.domain.service.validate;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.beans.factory.annotation.Qualifier;
6+
import org.springframework.stereotype.Service;
7+
import uk.gov.hmcts.ccd.config.JacksonUtils;
8+
import uk.gov.hmcts.ccd.data.definition.CachedCaseDefinitionRepository;
9+
import uk.gov.hmcts.ccd.data.definition.CaseDefinitionRepository;
10+
import uk.gov.hmcts.ccd.domain.model.casedataaccesscontrol.AccessProfile;
11+
import uk.gov.hmcts.ccd.domain.model.definition.CaseTypeDefinition;
12+
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
13+
import uk.gov.hmcts.ccd.domain.service.common.AccessControlService;
14+
import uk.gov.hmcts.ccd.domain.service.common.CaseAccessService;
15+
import uk.gov.hmcts.ccd.domain.service.createevent.MidEventCallback;
16+
import uk.gov.hmcts.ccd.endpoint.exceptions.ValidationException;
17+
18+
import java.util.Map;
19+
import java.util.Set;
20+
21+
import static com.google.common.collect.Maps.newHashMap;
22+
import static uk.gov.hmcts.ccd.domain.service.common.AccessControlService.CAN_READ;
23+
24+
@Service
25+
@Slf4j
26+
@Qualifier(AuthorisedValidateCaseFieldsOperation.QUALIFIER)
27+
public class AuthorisedValidateCaseFieldsOperation implements ValidateCaseFieldsOperation {
28+
public static final String QUALIFIER = "authorised";
29+
30+
private final AccessControlService accessControlService;
31+
private final CaseDefinitionRepository caseDefinitionRepository;
32+
private final CaseAccessService caseAccessService;
33+
private final ValidateCaseFieldsOperation validateCaseFieldsOperation;
34+
private final MidEventCallback midEventCallback;
35+
36+
public AuthorisedValidateCaseFieldsOperation(AccessControlService accessControlService,
37+
@Qualifier(CachedCaseDefinitionRepository.QUALIFIER)
38+
CaseDefinitionRepository caseDefinitionRepository,
39+
CaseAccessService caseAccessService,
40+
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
41+
ValidateCaseFieldsOperation validateCaseFieldsOperation,
42+
MidEventCallback midEventCallback) {
43+
this.accessControlService = accessControlService;
44+
this.caseDefinitionRepository = caseDefinitionRepository;
45+
this.caseAccessService = caseAccessService;
46+
this.validateCaseFieldsOperation = validateCaseFieldsOperation;
47+
this.midEventCallback = midEventCallback;
48+
}
49+
50+
@Override
51+
public Map<String, JsonNode> validateCaseDetails(OperationContext operationContext) {
52+
validateCaseFieldsOperation.validateCaseDetails(operationContext);
53+
54+
CaseDataContent content = operationContext.content();
55+
String caseTypeId = operationContext.caseTypeId();
56+
String pageId = operationContext.pageId();
57+
58+
final JsonNode data = midEventCallback.invoke(caseTypeId,
59+
content,
60+
pageId);
61+
62+
content.setData(JacksonUtils.convertValue(data));
63+
64+
verifyReadAccess(caseTypeId, content);
65+
66+
return content.getData();
67+
}
68+
69+
@Override
70+
public void validateData(Map<String, JsonNode> data, CaseTypeDefinition caseTypeDefinition,
71+
CaseDataContent content) {
72+
validateCaseFieldsOperation.validateData(data, caseTypeDefinition, content);
73+
}
74+
75+
private void verifyReadAccess(final String caseTypeId, CaseDataContent content) {
76+
final CaseTypeDefinition caseTypeDefinition = getCaseDefinitionType(caseTypeId);
77+
78+
Set<AccessProfile> caseAccessProfiles =
79+
caseAccessService.getAccessProfilesByCaseReference(content.getCaseReference());
80+
81+
if (!accessControlService.canAccessCaseTypeWithCriteria(
82+
caseTypeDefinition,
83+
caseAccessProfiles,
84+
CAN_READ)) {
85+
content.setData(newHashMap());
86+
return;
87+
}
88+
89+
content.setData(JacksonUtils.convertValueInDataField(
90+
accessControlService.filterCaseFieldsByAccess(
91+
JacksonUtils.convertValueJsonNode(content.getData().get(JacksonUtils.DATA)),
92+
caseTypeDefinition.getCaseFieldDefinitions(),
93+
caseAccessProfiles,
94+
CAN_READ,
95+
false)));
96+
}
97+
98+
private CaseTypeDefinition getCaseDefinitionType(String caseTypeId) {
99+
final CaseTypeDefinition caseTypeDefinition = caseDefinitionRepository.getCaseType(caseTypeId);
100+
if (caseTypeDefinition == null) {
101+
throw new ValidationException("Cannot find case type definition for " + caseTypeId);
102+
}
103+
return caseTypeDefinition;
104+
}
105+
}

src/main/java/uk/gov/hmcts/ccd/domain/service/validate/DefaultValidateCaseFieldsOperation.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
import java.util.Map;
1717

1818
@Service
19+
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
1920
public class DefaultValidateCaseFieldsOperation implements ValidateCaseFieldsOperation {
21+
public static final String QUALIFIER = "default";
2022

2123
private final CaseDefinitionRepository caseDefinitionRepository;
2224
private final CaseTypeService caseTypeService;
@@ -35,10 +37,12 @@ public class DefaultValidateCaseFieldsOperation implements ValidateCaseFieldsOpe
3537
}
3638

3739
@Override
38-
public final Map<String, JsonNode> validateCaseDetails(String caseTypeId, CaseDataContent content) {
40+
public final Map<String, JsonNode> validateCaseDetails(OperationContext operationContext) {
41+
CaseDataContent content = operationContext.content();
3942
if (content == null || content.getEvent() == null || content.getEventId() == null) {
4043
throw new ValidationException("Cannot validate case field because of event is not specified");
4144
}
45+
String caseTypeId = operationContext.caseTypeId();
4246
final CaseTypeDefinition caseTypeDefinition = caseDefinitionRepository.getCaseType(caseTypeId);
4347
if (caseTypeDefinition == null) {
4448
throw new ValidationException("Cannot find case type definition for " + caseTypeId);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package uk.gov.hmcts.ccd.domain.service.validate;
2+
3+
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
4+
5+
public record OperationContext(String caseTypeId, CaseDataContent content, String pageId) {
6+
public OperationContext(String caseTypeId, CaseDataContent content) {
7+
this(caseTypeId, content, null);
8+
}
9+
}

src/main/java/uk/gov/hmcts/ccd/domain/service/validate/ValidateCaseFieldsOperation.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
88

99
public interface ValidateCaseFieldsOperation {
10-
Map<String, JsonNode> validateCaseDetails(String caseTypeId,
11-
final CaseDataContent content);
10+
11+
Map<String, JsonNode> validateCaseDetails(OperationContext validationContext);
1212

1313
void validateData(final Map<String, JsonNode> data,
1414
final CaseTypeDefinition caseTypeDefinition,

src/main/java/uk/gov/hmcts/ccd/endpoint/std/CaseDetailsEndpoint.java

+6-10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import uk.gov.hmcts.ccd.appinsights.AppInsights;
2323
import uk.gov.hmcts.ccd.auditlog.AuditOperationType;
2424
import uk.gov.hmcts.ccd.auditlog.LogAudit;
25+
import uk.gov.hmcts.ccd.config.JacksonUtils;
2526
import uk.gov.hmcts.ccd.data.casedetails.SecurityClassification;
2627
import uk.gov.hmcts.ccd.data.casedetails.search.FieldMapSanitizeOperation;
2728
import uk.gov.hmcts.ccd.data.casedetails.search.MetaData;
@@ -32,7 +33,6 @@
3233
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
3334
import uk.gov.hmcts.ccd.domain.service.createcase.CreateCaseOperation;
3435
import uk.gov.hmcts.ccd.domain.service.createevent.CreateEventOperation;
35-
import uk.gov.hmcts.ccd.domain.service.createevent.MidEventCallback;
3636
import uk.gov.hmcts.ccd.domain.service.getcase.CaseNotFoundException;
3737
import uk.gov.hmcts.ccd.domain.service.getcase.CreatorGetCaseOperation;
3838
import uk.gov.hmcts.ccd.domain.service.getcase.GetCaseOperation;
@@ -41,6 +41,8 @@
4141
import uk.gov.hmcts.ccd.domain.service.search.SearchOperation;
4242
import uk.gov.hmcts.ccd.domain.service.startevent.StartEventOperation;
4343
import uk.gov.hmcts.ccd.domain.service.stdapi.DocumentsOperation;
44+
import uk.gov.hmcts.ccd.domain.service.validate.AuthorisedValidateCaseFieldsOperation;
45+
import uk.gov.hmcts.ccd.domain.service.validate.OperationContext;
4446
import uk.gov.hmcts.ccd.domain.service.validate.ValidateCaseFieldsOperation;
4547
import uk.gov.hmcts.ccd.endpoint.exceptions.ApiException;
4648
import uk.gov.hmcts.ccd.endpoint.exceptions.BadRequestException;
@@ -82,7 +84,6 @@ public class CaseDetailsEndpoint {
8284
private final AppInsights appInsights;
8385
private final FieldMapSanitizeOperation fieldMapSanitizeOperation;
8486
private final ValidateCaseFieldsOperation validateCaseFieldsOperation;
85-
private final MidEventCallback midEventCallback;
8687

8788
@Autowired
8889
public CaseDetailsEndpoint(@Qualifier(CreatorGetCaseOperation.QUALIFIER) final GetCaseOperation getCaseOperation,
@@ -91,10 +92,10 @@ public CaseDetailsEndpoint(@Qualifier(CreatorGetCaseOperation.QUALIFIER) final G
9192
@Qualifier("authorised") final StartEventOperation startEventOperation,
9293
@Qualifier(AuthorisedSearchOperation.QUALIFIER) final SearchOperation searchOperation,
9394
final FieldMapSanitizeOperation fieldMapSanitizeOperation,
95+
@Qualifier(AuthorisedValidateCaseFieldsOperation.QUALIFIER)
9496
final ValidateCaseFieldsOperation validateCaseFieldsOperation,
9597
final DocumentsOperation documentsOperation,
9698
final PaginatedSearchMetaDataOperation paginatedSearchMetaDataOperation,
97-
final MidEventCallback midEventCallback,
9899
final AppInsights appinsights) {
99100
this.getCaseOperation = getCaseOperation;
100101
this.createCaseOperation = createCaseOperation;
@@ -105,7 +106,6 @@ public CaseDetailsEndpoint(@Qualifier(CreatorGetCaseOperation.QUALIFIER) final G
105106
this.documentsOperation = documentsOperation;
106107
this.validateCaseFieldsOperation = validateCaseFieldsOperation;
107108
this.paginatedSearchMetaDataOperation = paginatedSearchMetaDataOperation;
108-
this.midEventCallback = midEventCallback;
109109
this.appInsights = appinsights;
110110
}
111111

@@ -333,12 +333,8 @@ public JsonNode validateCaseDetails(
333333
@RequestParam(required = false) final String pageId,
334334
@RequestBody final CaseDataContent content) {
335335

336-
validateCaseFieldsOperation.validateCaseDetails(caseTypeId,
337-
content);
338-
339-
return midEventCallback.invoke(caseTypeId,
340-
content,
341-
pageId);
336+
validateCaseFieldsOperation.validateCaseDetails(new OperationContext(caseTypeId, content, pageId));
337+
return JacksonUtils.convertValueJsonNode(content.getData());
342338
}
343339

344340
@PostMapping(value = "/caseworkers/{uid}/jurisdictions/{jid}/case-types/{ctid}/cases/{cid}/events")

0 commit comments

Comments
 (0)