Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ES-1911] Added Schema validation for identitityData #291

Merged
merged 31 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bc5de6c
[ES-1689] added test case (#259)
pvsaidurga Oct 3, 2024
dd988f2
moved tomcat and prometheus configuration to bootstrap.properties
ase-101 Oct 3, 2024
29193ac
Updated Readme and pom version
ase-101 Oct 4, 2024
6714713
added schema validation for IdentityData
Nov 25, 2024
5ea5041
modified schema validation now only one schema required to validate b…
Nov 29, 2024
97faef9
review changes and modified testcases
Dec 3, 2024
0efb497
review changes
kaifk468 Dec 5, 2024
2f3b96d
review changes now the error code will multiple errors
kaifk468 Dec 10, 2024
993d8f3
Added JsonIgnoreProperties for kyc auth and exchange requests (#269)
Piyush7034 Oct 4, 2024
cfc99a9
[ES-1689] (#271)
pvsaidurga Oct 8, 2024
4c13490
Release 0.10.x (#275)
ckm007 Oct 15, 2024
2fc5baf
[ES-1859] Added a new error code in the i18n.
gk-4VII Oct 24, 2024
22e3a74
[MOSIP-35892] Updated helm charts to add range
Rakshithb1 Oct 18, 2024
724d0d6
[ES-1842] i18n translation changes.
gk-4VII Nov 5, 2024
f521362
[ES-1899] Added log for testing. (#284)
gk-4VII Nov 5, 2024
2f1fce9
[MOSIP-37447] updated install.sh script for mosipid check
bhumi46 Nov 19, 2024
203cab3
[MOSIP-37447] updated install.sh script for mosipid check
bhumi46 Nov 19, 2024
9669d30
[ES-1860] Updated package.json and package-lock.json files .
gk-4VII Nov 25, 2024
2f36c80
[MODIFIED] redesign userprofile for mobile screen (#295)
zesu22 Dec 2, 2024
f5582e9
[MODIFIED] initial rendering, slider in sidenavbar in mobile view (#296)
zesu22 Dec 3, 2024
408d35a
conflict resolve
kaifk468 Dec 15, 2024
06cd25b
remvoed @IdData validator
kaifk468 Dec 15, 2024
717bfda
added schema validation for IdentityData
Nov 25, 2024
98b7be1
modified schema validation now only one schema required to validate b…
Nov 29, 2024
0ca3a29
Release 0.10.x (#275)
ckm007 Oct 15, 2024
c8a3212
[ES-1966] merge code from release to develop (#290)
zesu22 Dec 3, 2024
f72ff8f
added schema validation for IdentityData
Nov 25, 2024
4e94a88
modified schema validation now only one schema required to validate b…
Nov 29, 2024
d95b7ec
Release 0.10.x (#275)
ckm007 Oct 15, 2024
ca064d4
[ES-1966] merge code from release to develop (#290)
zesu22 Dec 3, 2024
c16fe34
merge conflict resolved
kaifk468 Dec 16, 2024
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
35 changes: 35 additions & 0 deletions mock-identity-system/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,41 @@
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.5.1</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.1</version>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,28 @@
*/
package io.mosip.esignet.mock.identitysystem.controller;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Valid;

import io.mosip.esignet.mock.identitysystem.dto.*;
import io.mosip.esignet.mock.identitysystem.dto.Error;
import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;
import io.mosip.kernel.core.exception.ErrorResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import io.mosip.esignet.mock.identitysystem.exception.MockIdentityException;
import io.mosip.esignet.mock.identitysystem.service.IdentityService;
import io.mosip.esignet.mock.identitysystem.util.HelperUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;


@RestController
Expand All @@ -29,7 +39,7 @@ public class IdentityController {
@PostMapping(value = "identity", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseWrapper<IdentityStatus> createIdentity
(@Valid @RequestBody RequestWrapper<CreateIdentity> requestWrapper) throws MockIdentityException {
(@RequestBody @Valid RequestWrapper<CreateIdentity> requestWrapper) throws MockIdentityException {

ResponseWrapper response = new ResponseWrapper<IdentityStatus>();
IdentityStatus identityStatus = new IdentityStatus();
Expand All @@ -43,7 +53,7 @@ public class IdentityController {
@PutMapping(value = "identity", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseWrapper<IdentityStatus> updateIdentity
(@Valid @RequestBody RequestWrapper<UpdateIdentity> requestWrapper) throws MockIdentityException {
(@RequestBody @Valid RequestWrapper<UpdateIdentity> requestWrapper) throws MockIdentityException {

ResponseWrapper response = new ResponseWrapper<IdentityStatus>();
IdentityStatus identityStatus = new IdentityStatus();
Expand Down Expand Up @@ -74,4 +84,25 @@ public ResponseWrapper<VerifiedClaimStatus> createVerifiedClaim(@Valid @RequestB
return response;

}

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity handleMethodArgumentNotValidException(ConstraintViolationException ex) {
List<Error> errors = new ArrayList<>();
if(ex != null) {
Set<ConstraintViolation<?>> violations = ((ConstraintViolationException) ex).getConstraintViolations();
for(ConstraintViolation<?> cv : violations) {
errors.add(new Error(cv.getMessage(), cv.getPropertyPath().toString() + ": " + cv.getMessage()));
}
return new ResponseEntity<ResponseWrapper>(getResponseWrapper(errors), HttpStatus.OK);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errors);
}

private ResponseWrapper getResponseWrapper(List<Error> errors) {
ResponseWrapper responseWrapper = new ResponseWrapper<>();
responseWrapper.setResponseTime(HelperUtil.getCurrentUTCDateTime());
responseWrapper.setErrors(errors);
return responseWrapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/
package io.mosip.esignet.mock.identitysystem.dto;

import io.mosip.esignet.mock.identitysystem.validator.IdData;
import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;

@IdData(action = "CREATE")
@IdentitySchema(action = "CREATE")
public class CreateIdentity extends IdentityData {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,13 @@

import java.util.List;

import javax.validation.constraints.NotBlank;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.mosip.esignet.mock.identitysystem.util.ErrorConstants;
import io.mosip.esignet.mock.identitysystem.validator.IdData;
import lombok.Data;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class IdentityData {

@NotBlank(message = ErrorConstants.INVALID_INDIVIDUAL_ID)

String individualId;

String pin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/
package io.mosip.esignet.mock.identitysystem.dto;

import io.mosip.esignet.mock.identitysystem.validator.IdData;
import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;

@IdData(action = "UPDATE")
@IdentitySchema(action = "UPDATE")
public class UpdateIdentity extends IdentityData {
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ public class ErrorConstants {
public static final String INVALID_TRUST_FRAMEWORK = "invalid_trust_framework";
public static final String INVALID_VERIFIED_DATE = "invalid_verified_date";
public static final String CLAIM_ALREADY_EXISTS="Claim already exists";
public static final String INVALID_IDENTITY_DATA= "invalid_identity_data";
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.mosip.esignet.mock.identitysystem.validator;


import io.mosip.esignet.mock.identitysystem.util.ErrorConstants;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE_USE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdentitySchemaValidator.class)
public @interface IdentitySchema {

String message() default ErrorConstants.INVALID_IDENTITY_DATA;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};

String action();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package io.mosip.esignet.mock.identitysystem.validator;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import io.mosip.esignet.mock.identitysystem.dto.IdentityData;
import io.mosip.esignet.mock.identitysystem.dto.RequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jose4j.lang.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import java.util.stream.Collectors;

@Component
@Slf4j
public class IdentitySchemaValidator implements ConstraintValidator<IdentitySchema, Object> {

@Value("${mosip.mock.ida.identity.schema.url}")
private String identitySchemaUrl;

@Value("#{${mosip.mock.ida.update-identity.non-mandatory.fields}}")
private Set<String> nonMandatoryFieldsOnUpdate;

private String action;

private volatile JsonSchema schema;

@Autowired
ObjectMapper objectMapper;

@Autowired
ResourceLoader resourceLoader;


@Override
public void initialize(IdentitySchema constraintAnnotation) {
this.action = constraintAnnotation.action();
}

@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {

if (!(object instanceof IdentityData)) {
return false;
}
IdentityData identityData=(IdentityData) object;
JsonNode identityJsonNode = objectMapper.valueToTree(identityData);
Set<ValidationMessage> validationErrors = validateIdentityData(identityJsonNode);

// Handle validation errors
if (!validationErrors.isEmpty()) {
addValidationErrorCode(validationErrors,context);
return false;
}
return true;
}

private Set<ValidationMessage> validateIdentityData(JsonNode identityJsonNode) {
Set<ValidationMessage> errors = getSchema().validate(identityJsonNode);
// If not a create operation, filter out specific errors
if (action.equals("UPDATE")) {
// Ignore validation errors with code 1029 (null value) and for exempted fields when validating updateIdentity
errors = errors.stream()
.filter(error -> !error.getCode().equals("1029") ||
!nonMandatoryFieldsOnUpdate.contains(error.
getInstanceLocation().getName(0)))
.collect(Collectors.toSet());
}
return errors;
}

private void addValidationErrorCode(Set<ValidationMessage> errors, ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
errors.forEach(error->context.
buildConstraintViolationWithTemplate("invalid_"+error.getInstanceLocation().getName(0).toLowerCase())
.addConstraintViolation());
}

private JsonSchema getSchema() {
if(schema !=null ) return schema;
synchronized (this) {
if (schema == null) {
InputStream schemaResponse = getResource(identitySchemaUrl);
JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
schema = jsonSchemaFactory.getSchema(schemaResponse);
}
}
return schema;
}

private InputStream getResource(String url) {
try{
Resource resource = resourceLoader.getResource(url);
return resource.getInputStream();
}catch (IOException e){
log.error("Failed to parse data: {}", url, e);
}
throw new RuntimeException("invalid_configuration");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,10 @@ spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
mosip.esignet.mock.authenticator.ida.otp-channels=email,phone

mosip.mock.identity.create.required.fields=individualId,fullName,givenName,familyName,gender,dateOfBirth,email,phone,streetAddress,locality,region,postalCode,country
mosip.mock.identity.update.required.fields=individualId

mosip.esignet.mock.supported-fields=individualId,pin,givenName,familyName,gender,dateOfBirth,email,phone,streetAddress,locality,region,postalCode,country
mosip.mock.ida.kba.default.field-language=eng
mosip.mock.ida.kyc.psut.field=psut


#Related to health check of hsm
mosip.kernel.keymgr.hsm.health.check.enabled=false
Expand Down
Loading
Loading