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<>();