Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
Expand All @@ -20,6 +21,9 @@ public class ValidationService {
@Autowired
private CbServerProperties cbServerProperties;

@Autowired
private MasterDataService masterDataService;

public boolean validateSearchRequest(ApiResponse apiResponse, Map<String, Object> requestBody) {

try {
Expand Down Expand Up @@ -212,4 +216,22 @@ public boolean upsertInstituteValidation(ApiResponse apiResponse, Map<String, Ob
}
return true;
}

public boolean isValidDegree(String authToken, String degree) {
ApiResponse res = masterDataService.getDegreesList(authToken);
Map<String, Object> result = res.getResult();
Map<String, Object> degreesMap = (Map<String, Object>) result.get(Constants.DEGREES_LIST);

List<String> degrees = (List<String>) degreesMap.get(Constants.DEGREES);
return degrees.contains(degree);
}

public boolean isValidInstitution(String authToken, String institution) {
ApiResponse res = masterDataService.getInstitutionsList(authToken);
Map<String, Object> result = res.getResult();
Map<String, Object> instMap = (Map<String, Object>) result.get(Constants.INSTITUTION_LIST);

List<String> institutions = (List<String>) instMap.get(Constants.INSTITUTIONS);
return institutions.contains(institution);
}
}
293 changes: 290 additions & 3 deletions src/main/java/com/igot/cb/profile/service/ProfileServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import java.util.stream.Stream;

import com.igot.cb.common.OutboundRequestHandlerServiceImpl;
import com.igot.cb.extendedprofile.service.ExtendedProfileService;
import com.igot.cb.masterdata.service.ValidationService;
import com.igot.cb.util.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
Expand Down Expand Up @@ -71,6 +73,12 @@ public class ProfileServiceImpl implements ProfileService {
@Autowired
OutboundRequestHandlerServiceImpl outboundRequestHandlerService;

@Autowired
ValidationService validationService;

@Autowired
ExtendedProfileService extendedProfileService;

// -------------------- Service METHODS --------------------

@Override
Expand All @@ -91,7 +99,13 @@ public ApiResponse saveExtendedProfile(Map<String, Object> request, String userT
return response;
}

String errMsg = validateUserExtendedProfileRequest(requestData);
String payloadError = performInputSanitizationCheck(requestData);
if (StringUtils.isNotBlank(payloadError)) {
ProjectUtil.errorResponse(response, payloadError, HttpStatus.BAD_REQUEST);
return response;
}

String errMsg = validateUserExtendedProfileRequest(requestData, userToken);
if (StringUtils.isNotBlank(errMsg)) {
ProjectUtil.errorResponse(response, errMsg, HttpStatus.BAD_REQUEST);
return response;
Expand Down Expand Up @@ -522,7 +536,7 @@ private void updateExtendedProfileAllCache(String userId, String contextType,
}
}

private String validateUserExtendedProfileRequest(Map<String, Object> requestData) {
private String validateUserExtendedProfileRequest(Map<String, Object> requestData, String userToken) {
if (requestData == null)
return "Request data is missing.";
List<String> errList = new ArrayList<>();
Expand All @@ -532,7 +546,12 @@ private String validateUserExtendedProfileRequest(Map<String, Object> requestDat
errList, false);
validateFieldsForList(requestData, Constants.SERVICE_HISTORY, serverConfig.getServiceHistoryMandatoryFields(),
errList, true);
return errList.isEmpty() ? "" : "Failed Due To Missing or Invalid Params - " + String.join(", ", errList) + ".";
validateMasterDataFields(requestData, userToken, errList);
validateServiceHistoryMasterData(requestData, userToken, errList);
if (!errList.isEmpty()) {
return "Failed Due To Missing or Invalid Params - " + String.join(", ", errList) + ".";
}
return "";
}

private void validateFieldsForList(Map<String, Object> requestData, String listKey, String mandatoryFields,
Expand Down Expand Up @@ -1490,4 +1509,272 @@ private List<Map<String, Object>> transformOrgCustomFieldsForES(List<Map<String,
}
return result;
}

public String performInputSanitizationCheck(Object input) {

Set<String> urlFields = Optional.ofNullable(serverConfig.getUrlFields())
.orElse(Set.of("uploadedDocumentUrl","url"));

Set<String> dateFields = Optional.ofNullable(serverConfig.getDateFields())
.orElse(Set.of("issuedDate","startDate","endDate"));

String textRegex = Optional.ofNullable(serverConfig.getAllowedTextRegex())
.orElse("^[a-zA-Z0-9 .,@()&/\\-]{1,250}$");

String urlRegex = Optional.ofNullable(serverConfig.getAllowedUrlRegex())
.orElse("^(https?://).+$");

String dateRegex = Optional.ofNullable(serverConfig.getAllowedDateRegex())
.orElse("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$");

return performInputSanitizationCheckRecursive(
input, urlFields, dateFields, textRegex, urlRegex, dateRegex);
}
private String performInputSanitizationCheckRecursive(
Object input,
Set<String> urlFields,
Set<String> dateFields,
String textRegex,
String urlRegex,
String dateRegex) {

if (input == null) return "";

if (input instanceof Map<?, ?> map) {
for (Map.Entry<?, ?> entry : map.entrySet()) {

String key = entry.getKey().toString();
Object value = entry.getValue();

if (value instanceof String str && !str.isBlank()) {

String regex;
if (urlFields.contains(key)) {
regex = urlRegex;
}
else if (dateFields.contains(key)) {
regex = dateRegex;
}
else {
regex = textRegex;
}

if (!str.matches(regex)) {
return "Request contains invalid characters";
}
}

String error = performInputSanitizationCheckRecursive(
value, urlFields, dateFields, textRegex, urlRegex, dateRegex);

if (!error.isEmpty()) return error;
}
}

if (input instanceof List<?> list) {
for (Object item : list) {
String error = performInputSanitizationCheckRecursive(
item, urlFields, dateFields, textRegex, urlRegex, dateRegex);

if (!error.isEmpty()) return error;
}
}

return "";
}

public String validateInputPayload(Object input) {

if (input == null) return "";

if (input instanceof Map<?, ?> map) {
for (Map.Entry<?, ?> entry : map.entrySet()) {

String key = entry.getKey().toString();
Object value = entry.getValue();

if (value instanceof String str) {
String regex;
if (serverConfig.getUrlFields().contains(key)) {
regex = serverConfig.getAllowedUrlRegex();
}
else if (serverConfig.getDateFields().contains(key)) {
regex = serverConfig.getAllowedDateRegex();
}
else {
regex = serverConfig.getAllowedTextRegex();
}

if (!str.isBlank() && !str.matches(regex)) {
return "Request contains invalid characters";
}
}

String error = validateInputPayload(value);
if (!error.isEmpty()) return error;
}
}

if (input instanceof List<?> list) {
for (Object item : list) {
String error = validateInputPayload(item);
if (!error.isEmpty()) return error;
}
}

return "";
}

public void validateMasterDataFields(Map<String, Object> requestData, String userToken, List<String> errList) {

List<Map<String, Object>> eduList =
(List<Map<String, Object>>) requestData.get(Constants.EDUCATIONAL_QUALIFICATIONS);

if (eduList == null) return;

for (Map<String, Object> edu : eduList) {

if (StringUtils.isNotBlank((String) edu.get("degree")) &&
!validationService.isValidDegree(userToken, (String) edu.get("degree"))) {
errList.add("Invalid degree value");
}

if (StringUtils.isNotBlank((String) edu.get("institutionName")) &&
!validationService.isValidInstitution(userToken, (String) edu.get("institutionName"))) {
errList.add("Invalid institution value");
}
}
}

public void validateServiceHistoryMasterData(Map<String, Object> requestData,
String userToken,
List<String> errList) {

List<Map<String, Object>> serviceList =
(List<Map<String, Object>>) requestData.get(Constants.SERVICE_HISTORY);

if (serviceList == null) return;

for (Map<String, Object> service : serviceList) {

if (StringUtils.isNotBlank((String) service.get(Constants.ORG_NAME)) &&
!validateUsingSearchApi(
serverConfig.getLearnerServiceHost(),
serverConfig.getOrgSearchUrl(),
serverConfig.getOrgSearchTemplate(),
Constants.ORG_NAME,
(String) service.get(Constants.ORG_NAME))) {
errList.add("Invalid organisation value");
}

if (StringUtils.isNotBlank((String) service.get(Constants.DESIGNATION)) &&
!validateUsingSearchApi(
serverConfig.getCbPoresServiceHost(),
serverConfig.getDesignationSearchApi(),
serverConfig.getDesignationSearchTemplate(),
Constants.DESIGNATION,
(String) service.get(Constants.DESIGNATION))) {
errList.add("Invalid designation value");
}

if (StringUtils.isNotBlank((String) service.get(Constants.ORG_STATE)) &&
!isValidState((String) service.get(Constants.ORG_STATE), userToken)) {
errList.add("Invalid state value");
}

if (StringUtils.isNotBlank((String) service.get(Constants.ORG_DISTRICT)) &&
!isValidDistrict((String) service.get(Constants.ORG_STATE), (String) service.get(Constants.ORG_DISTRICT), userToken)) {
errList.add("Invalid district value");
}
}
}

public boolean validateUsingSearchApi(String host,
String apiPath,
String template,
String fieldName,
String value) {

try {
String url = host + apiPath;

String requestBodyString = String.format(template, value);
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> requestBody =
mapper.readValue(requestBodyString, Map.class);

Map<String, String> headers = new HashMap<>();

Map<String, Object> response =
outboundRequestHandlerService.fetchResultUsingPost(url, requestBody, headers);

if (response == null || !response.containsKey(Constants.RESULT))
return false;

Map result = (Map) response.get(Constants.RESULT);

if (result.containsKey(Constants.RESPONSE)) {
Map resp = (Map) result.get(Constants.RESPONSE);
List<Map> content = (List<Map>) resp.get(Constants.CONTENT);

if (content != null && !content.isEmpty()) {
return content.stream().anyMatch(item ->
value.equalsIgnoreCase((String) item.get(fieldName))
);
}
}

if (result.containsKey(Constants.RESULT)) {
Map nestedResult = (Map) result.get(Constants.RESULT);
List<Map> data = (List<Map>) nestedResult.get(Constants.DATA);

if (data != null && !data.isEmpty()) {
return data.stream().anyMatch(item ->
value.equalsIgnoreCase((String) item.get(fieldName))
);
}
}

return false;

} catch (Exception e) {
return false;
}
}

public boolean isValidState(String stateName, String userToken) {

ApiResponse response = extendedProfileService.getStatesList(userToken);

List<Map<String, Object>> states =
(List<Map<String, Object>>) response.getResult().get(Constants.STATES_LIST);

if (states == null || states.isEmpty())
return false;

return states.stream().anyMatch(state ->
stateName.equalsIgnoreCase((String) state.get(Constants.STATE_NAME))
);
}
public boolean isValidDistrict(String stateName, String districtName, String userToken) {

Map<String, Object> req = Map.of(Constants.CONTEXT_NAME, stateName);

ApiResponse response = extendedProfileService.getDistrictsList(userToken, req);

List<Map<String, Object>> districtsByState =
(List<Map<String, Object>>) response.getResult().get(Constants.DISTRICTS_LIST);

if (districtsByState == null || districtsByState.isEmpty())
return false;

List<String> districts =
(List<String>) districtsByState.get(0).get(Constants.DISTRICTS);

return districts.stream().anyMatch(d ->
districtName.equalsIgnoreCase(d)
);
}


}
Loading