Skip to content

Commit b3c4a3e

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

17 files changed

+291
-133
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,127 @@
1+
package uk.gov.hmcts.ccd.domain.service.validate;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.google.common.collect.Sets;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.beans.factory.annotation.Qualifier;
7+
import org.springframework.stereotype.Service;
8+
import uk.gov.hmcts.ccd.config.JacksonUtils;
9+
import uk.gov.hmcts.ccd.data.casedetails.CachedCaseDetailsRepository;
10+
import uk.gov.hmcts.ccd.data.casedetails.CaseDetailsRepository;
11+
import uk.gov.hmcts.ccd.data.definition.CachedCaseDefinitionRepository;
12+
import uk.gov.hmcts.ccd.data.definition.CaseDefinitionRepository;
13+
import uk.gov.hmcts.ccd.domain.model.casedataaccesscontrol.AccessProfile;
14+
import uk.gov.hmcts.ccd.domain.model.definition.CaseDetails;
15+
import uk.gov.hmcts.ccd.domain.model.definition.CaseTypeDefinition;
16+
import uk.gov.hmcts.ccd.domain.model.draft.Draft;
17+
import uk.gov.hmcts.ccd.domain.model.std.CaseDataContent;
18+
import uk.gov.hmcts.ccd.domain.service.common.AccessControlService;
19+
import uk.gov.hmcts.ccd.domain.service.common.CaseAccessService;
20+
import uk.gov.hmcts.ccd.domain.service.createevent.MidEventCallback;
21+
import uk.gov.hmcts.ccd.endpoint.exceptions.ValidationException;
22+
23+
import java.util.Map;
24+
import java.util.Optional;
25+
import java.util.Set;
26+
27+
import static com.google.common.collect.Maps.newHashMap;
28+
import static uk.gov.hmcts.ccd.domain.service.common.AccessControlService.CAN_READ;
29+
30+
@Service
31+
@Slf4j
32+
@Qualifier(AuthorisedValidateCaseFieldsOperation.QUALIFIER)
33+
public class AuthorisedValidateCaseFieldsOperation implements ValidateCaseFieldsOperation {
34+
public static final String QUALIFIER = "authorised";
35+
36+
private final AccessControlService accessControlService;
37+
private final CaseDefinitionRepository caseDefinitionRepository;
38+
private final CaseAccessService caseAccessService;
39+
private final CaseDetailsRepository caseDetailsRepository;
40+
private final ValidateCaseFieldsOperation validateCaseFieldsOperation;
41+
private final MidEventCallback midEventCallback;
42+
43+
public AuthorisedValidateCaseFieldsOperation(AccessControlService accessControlService,
44+
@Qualifier(CachedCaseDefinitionRepository.QUALIFIER)
45+
CaseDefinitionRepository caseDefinitionRepository,
46+
CaseAccessService caseAccessService,
47+
@Qualifier(CachedCaseDetailsRepository.QUALIFIER)
48+
CaseDetailsRepository caseDetailsRepository,
49+
@Qualifier(DefaultValidateCaseFieldsOperation.QUALIFIER)
50+
ValidateCaseFieldsOperation validateCaseFieldsOperation,
51+
MidEventCallback midEventCallback) {
52+
this.accessControlService = accessControlService;
53+
this.caseDefinitionRepository = caseDefinitionRepository;
54+
this.caseAccessService = caseAccessService;
55+
this.caseDetailsRepository = caseDetailsRepository;
56+
this.validateCaseFieldsOperation = validateCaseFieldsOperation;
57+
this.midEventCallback = midEventCallback;
58+
}
59+
60+
@Override
61+
public Map<String, JsonNode> validateCaseDetails(OperationContext operationContext) {
62+
validateCaseFieldsOperation.validateCaseDetails(operationContext);
63+
64+
CaseDataContent content = operationContext.content();
65+
String caseTypeId = operationContext.caseTypeId();
66+
String pageId = operationContext.pageId();
67+
68+
final JsonNode data = midEventCallback.invoke(caseTypeId,
69+
content,
70+
pageId);
71+
72+
content.setData(JacksonUtils.convertValue(data));
73+
74+
verifyReadAccess(caseTypeId, content);
75+
76+
return content.getData();
77+
}
78+
79+
@Override
80+
public void validateData(Map<String, JsonNode> data, CaseTypeDefinition caseTypeDefinition,
81+
CaseDataContent content) {
82+
validateCaseFieldsOperation.validateData(data, caseTypeDefinition, content);
83+
}
84+
85+
private void verifyReadAccess(final String caseTypeId, CaseDataContent content) {
86+
Optional<CaseDetails> caseDetailsOptional = caseDetailsRepository.findByReference(
87+
content.getCaseReference());
88+
CaseDetails caseDetails = caseDetailsOptional.orElseThrow();
89+
90+
final CaseTypeDefinition caseTypeDefinition = getCaseType(caseTypeId);
91+
92+
Set<AccessProfile> caseAccessProfiles = getCaseRoles(caseDetails, caseTypeDefinition);
93+
94+
if (!accessControlService.canAccessCaseTypeWithCriteria(
95+
caseTypeDefinition,
96+
caseAccessProfiles,
97+
CAN_READ)) {
98+
content.setData(newHashMap());
99+
return;
100+
}
101+
102+
content.setData(JacksonUtils.convertValueInDataField(
103+
accessControlService.filterCaseFieldsByAccess(
104+
JacksonUtils.convertValueJsonNode(content.getData().get(JacksonUtils.DATA)),
105+
caseTypeDefinition.getCaseFieldDefinitions(),
106+
caseAccessProfiles,
107+
CAN_READ,
108+
false)));
109+
}
110+
111+
private CaseTypeDefinition getCaseType(String caseTypeId) {
112+
final CaseTypeDefinition caseTypeDefinition = caseDefinitionRepository.getCaseType(caseTypeId);
113+
if (caseTypeDefinition == null) {
114+
throw new ValidationException("Cannot find case type definition for " + caseTypeId);
115+
}
116+
return caseTypeDefinition;
117+
}
118+
119+
private Set<AccessProfile> getCaseRoles(CaseDetails caseDetails, CaseTypeDefinition caseTypeDefinition) {
120+
if (caseDetails == null || caseDetails.getId() == null || Draft.isDraft(caseDetails.getId())) {
121+
return Sets.union(caseAccessService.getCreationAccessProfiles(caseTypeDefinition.getId()),
122+
caseAccessService.getCaseCreationCaseRoles());
123+
} else {
124+
return caseAccessService.getAccessProfilesByCaseReference(caseDetails.getReferenceAsString());
125+
}
126+
}
127+
}

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,

0 commit comments

Comments
 (0)