diff --git a/pom.xml b/pom.xml index 0f0c698c8..68f3deff8 100644 --- a/pom.xml +++ b/pom.xml @@ -53,18 +53,13 @@ 3.6.3 - 3.2.3 + 3.3.10 3.4.0 3.4.1 - - 2.1.210 - 4.13.1 5.15.2 - - 1.2.3 2.13.2 @@ -117,6 +112,16 @@ io.mosip.kernel kernel-core 1.3.0-beta.1 + + + org.junit.vintage + junit-vintage-engine + + + junit + junit + + org.apache.logging.log4j @@ -131,16 +136,6 @@ identity-credential 20231002 - - info.weboftrust - ld-signatures-java - 1.5.0 - - - decentralized-identity - jsonld-common-java - 1.8.0 - io.mosip vcverifier-jar @@ -223,10 +218,6 @@ spring-boot-starter-data-redis ${starter.redis.version} - - org.junit.vintage - junit-vintage-engine - @@ -284,27 +275,12 @@ ${junit.version} test - - com.h2database - h2 - ${h2.version} - org.slf4j slf4j-api 1.7.25 - - ch.qos.logback - logback-classic - 1.2.6 - - - ch.qos.logback - logback-core - 1.2.9 - joda-time joda-time @@ -380,14 +356,6 @@ javax.activation activation - - javax.servlet - javax.servlet-api - - - org.glassfish.jaxb - jaxb-runtime - com.itextpdf itext7-core @@ -460,6 +428,12 @@ io.mosip.kernel kernel-biometrics-api ${kernel.biometrics.api.version} + + + org.junit.vintage + junit-vintage-engine + + @@ -471,6 +445,12 @@ io.mosip.kernel kernel-cbeffutil-api ${kernel.cbeffutil.version} + + + org.junit.vintage + junit-vintage-engine + + diff --git a/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialDefinitionResponseDto.java b/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialDefinitionResponseDto.java index 0f2fabaf0..abb63e359 100644 --- a/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialDefinitionResponseDto.java +++ b/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialDefinitionResponseDto.java @@ -19,7 +19,6 @@ public class CredentialDefinitionResponseDto { @Schema(description = "Type of the Credential Definition") private List<@NotEmpty String> type; - @NotEmpty @Valid @SerializedName("credentialSubject") @JsonProperty("credentialSubject") diff --git a/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialIssuerDisplayResponse.java b/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialIssuerDisplayResponse.java index cff8eb93f..0a8a13b41 100644 --- a/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialIssuerDisplayResponse.java +++ b/src/main/java/io/mosip/mimoto/dto/mimoto/CredentialIssuerDisplayResponse.java @@ -9,13 +9,11 @@ @Data public class CredentialIssuerDisplayResponse { - @NotBlank @SerializedName("name") @JsonProperty("name") @Schema(description = "Name of the Credential Issuer") private String name; - @NotBlank @SerializedName("locale") @JsonProperty("locale") @Schema(description = "Locale of the Credential Issuer") diff --git a/src/main/java/io/mosip/mimoto/dto/openid/presentation/PresentationDefinitionDTO.java b/src/main/java/io/mosip/mimoto/dto/openid/presentation/PresentationDefinitionDTO.java index 0f3a86dbe..eed13571c 100644 --- a/src/main/java/io/mosip/mimoto/dto/openid/presentation/PresentationDefinitionDTO.java +++ b/src/main/java/io/mosip/mimoto/dto/openid/presentation/PresentationDefinitionDTO.java @@ -15,6 +15,6 @@ public class PresentationDefinitionDTO { String id; - @JsonProperty("inputDescriptors") + @JsonProperty("input_descriptors") List inputDescriptors; } diff --git a/src/main/java/io/mosip/mimoto/service/impl/DataShareServiceImpl.java b/src/main/java/io/mosip/mimoto/service/impl/DataShareServiceImpl.java index 222e6e3b6..7276819c1 100644 --- a/src/main/java/io/mosip/mimoto/service/impl/DataShareServiceImpl.java +++ b/src/main/java/io/mosip/mimoto/service/impl/DataShareServiceImpl.java @@ -111,7 +111,6 @@ public VCCredentialResponse downloadCredentialFromDataShare(PresentationRequest } VCCredentialResponse vcCredentialResponse = objectMapper.readValue(vcCredentialResponseString, VCCredentialResponse.class); - log.info("Completed Mapping the Credential to Object => "); if(vcCredentialResponse.getCredential() == null){ DataShareResponseDto dataShareResponse = objectMapper.readValue(vcCredentialResponseString, DataShareResponseDto.class); String errorCode = dataShareResponse.getErrors().get(0).getErrorCode(); diff --git a/src/main/java/io/mosip/mimoto/service/impl/LdpVcCredentialFormatHandler.java b/src/main/java/io/mosip/mimoto/service/impl/LdpVcCredentialFormatHandler.java index 26b5209f8..43efba9f2 100644 --- a/src/main/java/io/mosip/mimoto/service/impl/LdpVcCredentialFormatHandler.java +++ b/src/main/java/io/mosip/mimoto/service/impl/LdpVcCredentialFormatHandler.java @@ -74,22 +74,24 @@ public LinkedHashMap> loadD String userLocale) { LinkedHashMap> displayProperties = new LinkedHashMap<>(); + Set orderedKeys = Optional.ofNullable(credentialsSupportedResponse.getOrder()) + .map(LinkedHashSet::new) // preserve order + .orElse(new LinkedHashSet<>()); + + // Add remaining keys from credentialProperties that are not already in orderedKeys + for (String key : credentialProperties.keySet()) { + orderedKeys.add(key); + } // LDP VC format — display config is in "credential_definition.credential_subject" if (credentialsSupportedResponse.getCredentialDefinition() == null || credentialsSupportedResponse.getCredentialDefinition().getCredentialSubject() == null) { - log.warn("Missing credential definition or credential subject for LDP VC format"); - return displayProperties; + log.info("Issuer well-known has no credential definition or credential subject for LDP VC format; falling back to claim-based display properties"); + return buildFallbackDisplayProperties(credentialProperties, new ArrayList<>(orderedKeys)); } Map displayConfigMap = credentialsSupportedResponse.getCredentialDefinition().getCredentialSubject(); - List orderedKeys = credentialsSupportedResponse.getOrder(); - - if (displayConfigMap == null) { - log.warn("No display configuration found for LDP VC format"); - return displayProperties; - } String resolvedLocale = LocaleUtils.resolveLocaleWithFallback(displayConfigMap, userLocale); @@ -107,7 +109,7 @@ public LinkedHashMap> loadD addFallbackDisplayProperties(credentialProperties, localizedDisplayMap, resolvedLocale); List fieldKeys = (orderedKeys != null && !orderedKeys.isEmpty()) - ? orderedKeys + ? new ArrayList<>(orderedKeys) : new ArrayList<>(localizedDisplayMap.keySet()); for (String key : fieldKeys) { @@ -120,4 +122,35 @@ public LinkedHashMap> loadD return displayProperties; } + + private LinkedHashMap> buildFallbackDisplayProperties( + Map credentialProperties, + List orderedKeys) { + + LinkedHashMap> displayProperties = new LinkedHashMap<>(); + + // Determine field order (prefer issuer-provided 'order' if any) + List fieldKeys = (orderedKeys != null && !orderedKeys.isEmpty()) + ? new ArrayList<>(orderedKeys) + : new ArrayList<>(credentialProperties.keySet()); + + // Exclude non-claim metadata + fieldKeys.remove("id"); + + // Build default display entries from claims + for (String key : fieldKeys) { + Object value = credentialProperties.get(key); + if (value == null) { + continue; + } + + // Generate fallback display using vc keys + CredentialIssuerDisplayResponse display = new CredentialIssuerDisplayResponse(); + display.setName(camelToTitleCase(key)); + display.setLocale("en"); + + displayProperties.put(key, Map.of(display, value)); + } + return displayProperties; + } } diff --git a/src/main/java/io/mosip/mimoto/service/impl/PresentationServiceImpl.java b/src/main/java/io/mosip/mimoto/service/impl/PresentationServiceImpl.java index ca939bffe..71c77f6a7 100644 --- a/src/main/java/io/mosip/mimoto/service/impl/PresentationServiceImpl.java +++ b/src/main/java/io/mosip/mimoto/service/impl/PresentationServiceImpl.java @@ -29,6 +29,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import java.io.IOException; import java.net.URISyntaxException; @@ -132,6 +134,7 @@ public String authorizePresentation(PresentationRequestDTO presentationRequestDT try { return processInputDescriptor(vcCredentialResponse, inputDescriptorDTO, presentationRequestDTO, presentationDefinitionDTO); } catch (JsonProcessingException e) { + log.error("Exception occured during processInputDesciptor: {}", e.getMessage()); throw new VPNotCreatedException(ErrorConstants.INVALID_REQUEST.getErrorMessage()); } }) @@ -168,6 +171,7 @@ private String processInputDescriptor(VCCredentialResponse vcCredentialResponse, // Create VP Token String vpToken = createVpToken(vpDTO); + // Create PresentationSubmission String presentationSubmission = constructPresentationSubmission(format, vpDTO, presentationDefinitionDTO, inputDescriptorDTO); @@ -175,6 +179,7 @@ private String processInputDescriptor(VCCredentialResponse vcCredentialResponse, if (presentationRequestDTO.getResponseMode() != null && "direct_post".equals(presentationRequestDTO.getResponseMode())) { return postVpToResponseUri( presentationRequestDTO.getResponseUri(), + presentationRequestDTO.getRedirectUri(), vpToken, presentationSubmission, presentationRequestDTO.getState(), @@ -207,33 +212,39 @@ private String buildRedirectString(String vpToken, String redirectUri, String pr URLEncoder.encode(presentationSubmission, StandardCharsets.UTF_8)); } - private String postVpToResponseUri(String responseUri, String vpToken, String presentationSubmission, String state, String nonce) throws JsonProcessingException { - Map postRequest = new HashMap<>(); - postRequest.put("vp_token", vpToken); - postRequest.put("presentation_submission", objectMapper.readTree(presentationSubmission)); + private String postVpToResponseUri(String responseUri, String redirectUri, String vpToken, String presentationSubmission, String state, String nonce) throws JsonProcessingException { + MultiValueMap postRequest = new LinkedMultiValueMap<>(); + postRequest.add("vp_token", Base64.getUrlEncoder().encodeToString(vpToken.getBytes(StandardCharsets.UTF_8))); + postRequest.add("presentation_submission", presentationSubmission); if (state != null) { - postRequest.put("state", state); - } - - if (nonce != null) { - postRequest.put("nonce", nonce); + postRequest.add("state", state); } log.info("Posting VP to response_uri: {}", responseUri); try { Map postResponse = restApiClient.postApi( responseUri, - MediaType.APPLICATION_JSON, + MediaType.APPLICATION_FORM_URLENCODED, postRequest, Map.class ); log.info("Response from verifier after POST: {}", postResponse); - // Check for redirect_uri in response - String redirectUri = (String) postResponse.get("redirect_uri"); - if (redirectUri != null && !redirectUri.isEmpty()) { + + // Check for redirect_uri in response first + if (postResponse != null && postResponse.containsKey("redirect_uri")) { + String responseRedirectUri = (String) postResponse.get("redirect_uri"); + if (responseRedirectUri != null && !responseRedirectUri.isEmpty()) { + return responseRedirectUri; + } + } + + // Use request's redirectUri if it's non-blank + if (redirectUri != null && !redirectUri.isBlank()) { + log.info("Using redirectUri from request: {}", redirectUri); return redirectUri; } + // Fallback behavior if redirect_uri is not provided log.warn("No redirect_uri received from verifier in POST response. Falling back to response_uri."); return responseUri + "?status=vp_sent"; diff --git a/src/main/java/io/mosip/mimoto/service/impl/VcSdJwtCredentialFormatHandler.java b/src/main/java/io/mosip/mimoto/service/impl/VcSdJwtCredentialFormatHandler.java index f3a522dce..2cf27c918 100644 --- a/src/main/java/io/mosip/mimoto/service/impl/VcSdJwtCredentialFormatHandler.java +++ b/src/main/java/io/mosip/mimoto/service/impl/VcSdJwtCredentialFormatHandler.java @@ -55,6 +55,21 @@ public LinkedHashMap> loadD LinkedHashMap> displayProperties = new LinkedHashMap<>(); + // Start with ordered fields + Set orderedKeys = Optional.ofNullable(credentialsSupportedResponse.getOrder()) + .map(LinkedHashSet::new) // preserve order + .orElse(new LinkedHashSet<>()); + + // Add remaining keys from credentialProperties that are not already in orderedKeys + for (String key : credentialProperties.keySet()) { + orderedKeys.add(key); // Set ensures no duplicates + } + + if (credentialsSupportedResponse.getClaims() == null || credentialsSupportedResponse.getClaims().isEmpty()) { + log.info("Issuer well-known has no claims for SD-JWT format; falling back to claim-based display properties"); + return buildFallbackDisplayProperties(credentialProperties, orderedKeys); + } + // Extract raw claims and convert to DTOs Map rawClaims = Optional.ofNullable(credentialsSupportedResponse.getClaims()) .map(map -> (map.size() == 1 && map.values().iterator().next() instanceof Map) @@ -69,7 +84,8 @@ public LinkedHashMap> loadD )); if (convertedClaimsMap.isEmpty()) { - log.warn("No display configuration found for SD-JWT format"); + log.info("No display configuration found for SD-JWT format"); + return buildFallbackDisplayProperties(credentialProperties, orderedKeys); } String resolvedLocale = LocaleUtils.resolveLocaleWithFallback(convertedClaimsMap, userLocale); @@ -84,16 +100,6 @@ public LinkedHashMap> loadD }); } - // Start with ordered fields - Set orderedKeys = Optional.ofNullable(credentialsSupportedResponse.getOrder()) - .map(LinkedHashSet::new) // preserve order - .orElse(new LinkedHashSet<>()); - - // Add remaining keys from credentialProperties that are not already in orderedKeys - for (String key : credentialProperties.keySet()) { - orderedKeys.add(key); // Set ensures no duplicates - } - for (String key : orderedKeys) { Object value = credentialProperties.get(key); if (value == null) { @@ -120,7 +126,7 @@ public LinkedHashMap> loadD public Map extractClaimsFromSdJwt(String sdJwtString) { try { SDJWT sdJwt = SDJWT.parse(sdJwtString); - Map claims = new HashMap<>(); + Map claims = new LinkedHashMap<>(); // Parse JWT payload String credentialJwt = sdJwt.getCredentialJwt(); @@ -149,7 +155,7 @@ public Map extractClaimsFromSdJwt(String sdJwtString) { } // Remove standard JWT claims and SD-JWT metadata - List metadataKeys = Arrays.asList("vct", "cnf", "iss", "sub", "aud", "exp", "nbf", "iat", "jti", "_sd", "_sd_alg"); + List metadataKeys = Arrays.asList("vct", "cnf", "iss", "sub", "aud", "exp", "nbf", "iat", "jti", "_sd", "_sd_alg", "id"); metadataKeys.forEach(claims::remove); // Return claims directly as result @@ -163,4 +169,30 @@ public Map extractClaimsFromSdJwt(String sdJwtString) { return Collections.emptyMap(); } } + + private LinkedHashMap> buildFallbackDisplayProperties( + Map credentialProperties, + Set orderedKeys) { + + LinkedHashMap> displayProperties = new LinkedHashMap<>(); + + // Use ordered keys from parameter (already includes all fields) + List fieldKeys = new ArrayList<>(orderedKeys); + + // Build default display entries from claims + for (String key : fieldKeys) { + Object value = credentialProperties.get(key); + if (value == null) { + continue; + } + + // Generate fallback display using claims keys + CredentialIssuerDisplayResponse display = new CredentialIssuerDisplayResponse(); + display.setName(camelToTitleCase(key)); + display.setLocale("en"); + + displayProperties.put(key, Map.of(display, value)); + } + return displayProperties; + } } \ No newline at end of file diff --git a/src/test/java/io/mosip/mimoto/service/LdpVcCredentialFormatHandlerTest.java b/src/test/java/io/mosip/mimoto/service/LdpVcCredentialFormatHandlerTest.java index a8901f206..371f46fa9 100644 --- a/src/test/java/io/mosip/mimoto/service/LdpVcCredentialFormatHandlerTest.java +++ b/src/test/java/io/mosip/mimoto/service/LdpVcCredentialFormatHandlerTest.java @@ -140,9 +140,14 @@ void loadDisplayPropertiesFromWellknownWithNullCredentialDefinitionShouldReturnE ldpVcCredentialFormatHandler.loadDisplayPropertiesFromWellknown( credentialProperties, credentialsSupportedResponse, "en"); - // Then + // Then - now returns fallback for firstName assertNotNull(result); - assertTrue(result.isEmpty()); + assertEquals(1, result.size()); + assertTrue(result.containsKey("firstName")); + + CredentialIssuerDisplayResponse display = result.get("firstName").keySet().iterator().next(); + assertEquals("First Name", display.getName()); + assertEquals("en", display.getLocale()); } @Test @@ -159,9 +164,14 @@ void loadDisplayPropertiesFromWellknownWithNullCredentialSubjectShouldReturnEmpt ldpVcCredentialFormatHandler.loadDisplayPropertiesFromWellknown( credentialProperties, credentialsSupportedResponse, "en"); - // Then + // Then - now returns fallback for firstName assertNotNull(result); - assertTrue(result.isEmpty()); + assertEquals(1, result.size()); + assertTrue(result.containsKey("firstName")); + + CredentialIssuerDisplayResponse display = result.get("firstName").keySet().iterator().next(); + assertEquals("First Name", display.getName()); + assertEquals("en", display.getLocale()); } @Test @@ -178,9 +188,14 @@ void loadDisplayPropertiesFromWellknownWithNullDisplayConfigMapShouldReturnEmpty ldpVcCredentialFormatHandler.loadDisplayPropertiesFromWellknown( credentialProperties, credentialsSupportedResponse, "en"); - // Then + // Then - now returns fallback for firstName assertNotNull(result); - assertTrue(result.isEmpty()); + assertEquals(1, result.size()); + assertTrue(result.containsKey("firstName")); + + CredentialIssuerDisplayResponse display = result.get("firstName").keySet().iterator().next(); + assertEquals("First Name", display.getName()); + assertEquals("en", display.getLocale()); } @Test @@ -485,4 +500,76 @@ void loadDisplayPropertiesFromWellknownWithFullNameScenario() { assertEquals("en", mobileDisplay.getLocale()); } } + + @Test + void buildFallbackDisplayPropertiesWithOrderedKeysShouldRespectOrder() { + // Given + Map credentialProperties = new HashMap<>(); + credentialProperties.put("firstName", "John"); + credentialProperties.put("lastName", "Doe"); + credentialProperties.put("email", "john@example.com"); + + List orderedKeys = Arrays.asList("email", "lastName", "firstName"); + credentialsSupportedResponse.setOrder(orderedKeys); + credentialsSupportedResponse.setCredentialDefinition(null); // Trigger fallback + + // When + LinkedHashMap> result = + ldpVcCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(3, result.size()); + + // Verify order is preserved + List resultKeys = new ArrayList<>(result.keySet()); + assertEquals("email", resultKeys.get(0)); + assertEquals("lastName", resultKeys.get(1)); + assertEquals("firstName", resultKeys.get(2)); + } + + @Test + void buildFallbackDisplayPropertiesWithNullValuesShouldSkipFields() { + // Given + Map credentialProperties = new HashMap<>(); + credentialProperties.put("firstName", "John"); + credentialProperties.put("middleName", null); + credentialProperties.put("lastName", "Doe"); + + credentialsSupportedResponse.setCredentialDefinition(null); + + // When + LinkedHashMap> result = + ldpVcCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(2, result.size()); // middleName should be skipped + assertTrue(result.containsKey("firstName")); + assertTrue(result.containsKey("lastName")); + assertFalse(result.containsKey("middleName")); + } + + @Test + void buildFallbackDisplayPropertiesWithIdFieldShouldExcludeIt() { + // Given + Map credentialProperties = new HashMap<>(); + credentialProperties.put("id", "12345"); + credentialProperties.put("firstName", "John"); + + credentialsSupportedResponse.setCredentialDefinition(null); + + // When + LinkedHashMap> result = + ldpVcCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(1, result.size()); + assertFalse(result.containsKey("id")); // id should be excluded + assertTrue(result.containsKey("firstName")); + } } diff --git a/src/test/java/io/mosip/mimoto/service/PresentationServiceTest.java b/src/test/java/io/mosip/mimoto/service/PresentationServiceTest.java index a3d025867..c517eac44 100644 --- a/src/test/java/io/mosip/mimoto/service/PresentationServiceTest.java +++ b/src/test/java/io/mosip/mimoto/service/PresentationServiceTest.java @@ -482,7 +482,7 @@ public void testDirectPostResponseModeWithoutRedirectUri() throws Exception { String result = presentationService.authorizePresentation(presentationRequestDTO); - assertEquals("https://verifier.example.com/response?status=vp_sent", result); + assertEquals("test_redirect_uri", result); verify(restApiClient).postApi(eq("https://verifier.example.com/response"), any(), any(), eq(Map.class)); } @@ -639,7 +639,7 @@ public void testConstructPresentationDefinitionForSdJwtWithMapTypeNullValue() { @Test public void testDirectPostResponseModeWithEmptyRedirectUri() throws Exception { VCCredentialResponse vcCredentialResponse = TestUtilities.getVCCredentialResponseDTO("Ed25519Signature2020"); - PresentationRequestDTO presentationRequestDTO = TestUtilities.getPresentationRequestDTO(); + PresentationRequestDTO presentationRequestDTO = TestUtilities.getPresentationRequestDTOWithEmptyRedirectURI(); presentationRequestDTO.setResponseMode("direct_post"); presentationRequestDTO.setResponseUri("https://verifier.example.com/response"); presentationRequestDTO.setState("test-state"); diff --git a/src/test/java/io/mosip/mimoto/service/VcSdJwtCredentialFormatHandlerTest.java b/src/test/java/io/mosip/mimoto/service/VcSdJwtCredentialFormatHandlerTest.java index be4238fe8..a78b5ea7f 100644 --- a/src/test/java/io/mosip/mimoto/service/VcSdJwtCredentialFormatHandlerTest.java +++ b/src/test/java/io/mosip/mimoto/service/VcSdJwtCredentialFormatHandlerTest.java @@ -454,6 +454,104 @@ void getSupportedFormatShouldReturnCorrectFormat() { assertEquals(CredentialFormat.VC_SD_JWT.getFormat(), result); } + @Test + void buildFallbackDisplayPropertiesWithOrderedKeysShouldRespectOrder() { + // Given + Map credentialProperties = new HashMap<>(); + credentialProperties.put("firstName", "John"); + credentialProperties.put("lastName", "Doe"); + credentialProperties.put("email", "john@example.com"); + + List orderedKeys = Arrays.asList("email", "lastName", "firstName"); + credentialsSupportedResponse.setOrder(orderedKeys); + credentialsSupportedResponse.setClaims(null); // Trigger fallback + + // When + LinkedHashMap> result = + vcSdJwtCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(3, result.size()); + + // Verify order is preserved + List resultKeys = new ArrayList<>(result.keySet()); + assertEquals("email", resultKeys.get(0)); + assertEquals("lastName", resultKeys.get(1)); + assertEquals("firstName", resultKeys.get(2)); + } + + @Test + void buildFallbackDisplayPropertiesWithNullValuesShouldSkipFields() { + // Given + Map credentialProperties = new HashMap<>(); + credentialProperties.put("firstName", "John"); + credentialProperties.put("middleName", null); + credentialProperties.put("lastName", "Doe"); + + credentialsSupportedResponse.setClaims(null); + + // When + LinkedHashMap> result = + vcSdJwtCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(2, result.size()); // middleName should be skipped + assertTrue(result.containsKey("firstName")); + assertTrue(result.containsKey("lastName")); + assertFalse(result.containsKey("middleName")); + } + + @Test + void buildFallbackDisplayPropertiesWithIdFieldShouldExcludeIt() { + // Given + Map credentialProperties = new LinkedHashMap<>(); + credentialProperties.put("id", "12345"); + credentialProperties.put("firstName", "John"); + + credentialsSupportedResponse.setClaims(null); + + // When + LinkedHashMap> result = + vcSdJwtCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(2, result.size()); + assertTrue(result.containsKey("firstName")); + } + + @Test + void buildFallbackDisplayPropertiesWithEmptyClaimsShouldTriggerFallback() { + // Given + Map credentialProperties = new HashMap<>(); + credentialProperties.put("firstName", "John"); + credentialProperties.put("lastName", "Doe"); + + credentialsSupportedResponse.setClaims(new HashMap<>()); // Empty claims + + // When + LinkedHashMap> result = + vcSdJwtCredentialFormatHandler.loadDisplayPropertiesFromWellknown( + credentialProperties, credentialsSupportedResponse, "en"); + + // Then + assertNotNull(result); + assertEquals(2, result.size()); + + CredentialIssuerDisplayResponse firstNameDisplay = result.get("firstName").keySet().iterator().next(); + assertEquals("First Name", firstNameDisplay.getName()); + assertEquals("en", firstNameDisplay.getLocale()); + + CredentialIssuerDisplayResponse lastNameDisplay = result.get("lastName").keySet().iterator().next(); + assertEquals("Last Name", lastNameDisplay.getName()); + assertEquals("en", lastNameDisplay.getLocale()); + } + // Helper methods private Map createSampleClaims() { Map claims = new HashMap<>(); diff --git a/src/test/java/io/mosip/mimoto/util/CredentialIssuerWellknownResponseValidatorTest.java b/src/test/java/io/mosip/mimoto/util/CredentialIssuerWellknownResponseValidatorTest.java index 988d6ab58..f17db94c4 100644 --- a/src/test/java/io/mosip/mimoto/util/CredentialIssuerWellknownResponseValidatorTest.java +++ b/src/test/java/io/mosip/mimoto/util/CredentialIssuerWellknownResponseValidatorTest.java @@ -282,11 +282,10 @@ void shouldDetectMissingMandatoryFieldsOfCredentialDefinitionInWellknownResponse credentialIssuerWellknownResponseValidator.validate(response, validator) ); - assertTrue(Arrays.stream(invalidWellknownResponseException.getMessage().split("\n")).toList().containsAll(Arrays.stream(""" - RESIDENT-APP-041 --> Invalid Wellknown from Issuer - Validation failed: - type: must not be empty - credentialSubject: must not be empty""".split("\n")).toList())); + // Update to check message contains validation errors + String message = invalidWellknownResponseException.getMessage(); + assertTrue(message.contains("RESIDENT-APP-041 --> Invalid Wellknown from Issuer")); + assertTrue(message.contains("type: must not be empty")); } @Test diff --git a/src/test/java/io/mosip/mimoto/util/TestUtilities.java b/src/test/java/io/mosip/mimoto/util/TestUtilities.java index 1534ddc9e..73119bf9c 100644 --- a/src/test/java/io/mosip/mimoto/util/TestUtilities.java +++ b/src/test/java/io/mosip/mimoto/util/TestUtilities.java @@ -293,6 +293,15 @@ public static PresentationRequestDTO getPresentationRequestDTO() { .redirectUri("test_redirect_uri").build(); } + public static PresentationRequestDTO getPresentationRequestDTOWithEmptyRedirectURI() { + return PresentationRequestDTO.builder() + .presentationDefinition(getPresentationDefinitionDTO()) + .clientId("test_client_id") + .resource("http://datashare.datashare/v1/datashare/get/static-policyid/static-subscriberid/test") + .responseType("test_response_type") + .redirectUri("").build(); + } + public static VCCredentialProperties getVCCredentialPropertiesDTO(String type) { ArrayList contextList = new ArrayList<>();