Skip to content

Commit 35b446e

Browse files
committed
[INJICERT-1135] Add credetial status to vc type and set credentialStatus from code (mosip#376)
* [INJICERT-1035] Add credetial status to vc type and set credentialStatus from code Signed-off-by: Piyush7034 <[email protected]> * Add enum for credential status purpose Signed-off-by: Piyush7034 <[email protected]> Signed-off-by: Vishwa <[email protected]> * [INJICERT-1135] Add list type for credential status Signed-off-by: Piyush7034 <[email protected]> --------- Signed-off-by: Piyush7034 <[email protected]>
1 parent 98215da commit 35b446e

File tree

16 files changed

+67
-34
lines changed

16 files changed

+67
-34
lines changed

certify-core/src/main/java/io/mosip/certify/core/constants/Constants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ public class Constants {
3535
public static final String INACTIVE = "inactive";
3636
public static final String DELIMITER = "::"; // delimiter is :: its not used by url or within any context of VC name and is distinct
3737
public static final String SIGNATURE_CRYPTO_SUITE = "SIGNATURE_CRYPTO_SUITE";
38+
public static final String VCT = "vct";
39+
public static final String CNF = "cnf";
40+
public static final String ISS = "iss";
41+
public static final String TYPE = "type";
3842
}

certify-core/src/main/java/io/mosip/certify/core/constants/VCDM2Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ public class VCDM2Constants {
99
public static final String URL = "https://www.w3.org/ns/credentials/v2";
1010
public static final String VALID_UNITL = "validUntil";
1111
public static final String VALID_FROM = "validFrom";
12+
public static final String CREDENTIAL_STATUS = "credentialStatus";
1213
}

certify-core/src/main/java/io/mosip/certify/core/dto/CredentialConfigurationDTO.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,6 @@ public class CredentialConfigurationDTO {
7373
private String sdJwtVct;
7474

7575
private List<Map<String, String>> pluginConfigurations;
76+
77+
private List<String> credentialStatusPurpose;
7678
}

certify-service/src/main/java/io/mosip/certify/entity/CredentialConfig.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,13 @@ public class CredentialConfig {
107107
@Column(name = "plugin_configurations", columnDefinition = "jsonb")
108108
private List<Map<String, String>> pluginConfigurations;
109109

110+
@Column(name = "credential_status_purpose", columnDefinition = "TEXT[]")
111+
private List<String> credentialStatusPurpose;
112+
110113
@NotNull
111114
@Column(name = "cr_dtimes")
112115
private LocalDateTime createdTimes;
113116

114117
@Column(name = "upd_dtimes")
115118
private LocalDateTime updatedTimes;
116-
117119
}

certify-service/src/main/java/io/mosip/certify/mapper/CredentialConfigMapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public interface CredentialConfigMapper {
1717
@Mapping(target = "updatedTimes", ignore = true)
1818
@Mapping(target = "context", source = "context", qualifiedByName = "listToCommaSeparatedString")
1919
@Mapping(target = "credentialType", source = "credentialType", qualifiedByName = "listToCommaSeparatedString")
20+
@Mapping(target = "credentialStatusPurpose", ignore = true)
2021
CredentialConfig toEntity(CredentialConfigurationDTO dto);
2122

2223
// Convert Entity to DTO
@@ -31,6 +32,7 @@ public interface CredentialConfigMapper {
3132
@Mapping(target = "updatedTimes", expression = "java(java.time.LocalDateTime.now())")
3233
@Mapping(target = "context", source = "context", qualifiedByName = "listToCommaSeparatedString")
3334
@Mapping(target = "credentialType", source = "credentialType", qualifiedByName = "listToCommaSeparatedString")
35+
@Mapping(target = "credentialStatusPurpose", ignore = true)
3436
void updateEntityFromDto(CredentialConfigurationDTO dto, @MappingTarget CredentialConfig entity);
3537

3638
@Named("listToCommaSeparatedString")

certify-service/src/main/java/io/mosip/certify/services/CertifyIssuanceServiceImpl.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.nimbusds.jwt.SignedJWT;
1717
import io.mosip.certify.api.util.AuditHelper;
1818
import io.mosip.certify.config.IndexedAttributesConfig;
19+
import io.mosip.certify.core.constants.VCDM2Constants;
1920
import io.mosip.certify.core.dto.*;
2021
import io.mosip.certify.core.spi.CredentialConfigurationService;
2122
import io.mosip.certify.entity.CredentialStatusTransaction;
@@ -142,12 +143,6 @@ public class CertifyIssuanceServiceImpl implements VCIssuanceService {
142143
@Autowired
143144
private IndexedAttributesConfig indexedAttributesConfig;
144145

145-
@Value("${mosip.certify.statuslist.enabled:false}")
146-
private boolean statusListEnabled;
147-
148-
@Value("${mosip.certify.statuslist.default-purpose:revocation}")
149-
private String defaultStatusPurpose;
150-
151146
@Value("${mosip.certify.domain.url}")
152147
private String domainUrl;
153148

@@ -264,8 +259,10 @@ private VCResult<?> getVerifiableCredential(CredentialRequest credentialRequest,
264259
String templateName = CredentialUtils.getTemplateName(vcRequestDto);
265260
templateParams.put(Constants.TEMPLATE_NAME, templateName);
266261
templateParams.put(Constants.DID_URL, didUrl);
267-
if (statusListEnabled) {
268-
addCredentialStatus(jsonObject);
262+
jsonObject.put(Constants.TYPE, credentialRequest.getCredential_definition().getType());
263+
List<String> credentialStatusPurposeList = vcFormatter.getCredentialStatusPurpose(templateName);
264+
if (credentialStatusPurposeList != null && !credentialStatusPurposeList.isEmpty()) {
265+
addCredentialStatus(jsonObject, credentialStatusPurposeList.getFirst());
269266
}
270267
if (!StringUtils.isEmpty(renderTemplateId)) {
271268
templateParams.put(Constants.RENDERING_TEMPLATE_ID, renderTemplateId);
@@ -274,6 +271,7 @@ private VCResult<?> getVerifiableCredential(CredentialRequest credentialRequest,
274271
Credential cred = credentialFactory.getCredential(credentialRequest.getFormat()).orElseThrow(()-> new CertifyException(ErrorConstants.UNSUPPORTED_VC_FORMAT));
275272
templateParams.putAll(jsonObject.toMap());
276273
String unsignedCredential=cred.createCredential(templateParams, templateName);
274+
jsonObject.remove(VCDM2Constants.CREDENTIAL_STATUS);
277275
return cred.addProof(unsignedCredential,"", vcFormatter.getProofAlgorithm(templateName), vcFormatter.getAppID(templateName), vcFormatter.getRefID(templateName),vcFormatter.getDidUrl(templateName), vcFormatter.getSignatureCryptoSuite(templateName));
278276
} catch(DataProviderExchangeException e) {
279277
throw new CertifyException(e.getErrorCode());
@@ -296,11 +294,11 @@ private VCResult<?> getVerifiableCredential(CredentialRequest credentialRequest,
296294
Credential cred = credentialFactory.getCredential(CredentialFormat.VC_SD_JWT.toString()).orElseThrow(()-> new CertifyException(ErrorConstants.UNSUPPORTED_VC_FORMAT));
297295
jsonObject.put("_holderId", holderId);
298296
templateParams.putAll(jsonObject.toMap());
299-
templateParams.put("_vct", vcRequestDto.getVct());
297+
templateParams.put(Constants.VCT, vcRequestDto.getVct());
300298
// This is with reference to the Representation of a Key ID for a Proof-of-Possession Key
301299
// Ref: https://datatracker.ietf.org/doc/html/rfc7800#section-3.4
302-
templateParams.put("_cnf", Map.of("kid", holderId));
303-
templateParams.put("_iss", certifyIssuer);
300+
templateParams.put(Constants.CNF, Map.of("kid", holderId));
301+
templateParams.put(Constants.ISS, certifyIssuer);
304302
String unsignedCredential=cred.createCredential(templateParams, templateName);
305303
return cred.addProof(unsignedCredential,"", vcFormatter.getProofAlgorithm(templateName), vcFormatter.getAppID(templateName), vcFormatter.getRefID(templateName),vcFormatter.getDidUrl(templateName), vcFormatter.getSignatureCryptoSuite(templateName));
306304
} catch(DataProviderExchangeException e) {
@@ -313,20 +311,20 @@ private VCResult<?> getVerifiableCredential(CredentialRequest credentialRequest,
313311
}
314312

315313
@Transactional
316-
private void addCredentialStatus(JSONObject jsonObject) {
314+
private void addCredentialStatus(JSONObject jsonObject, String statusPurpose) {
317315
try {
318316
log.info("Adding credential status forstatus list integration");
319317

320318
// Find or create a suitable status list
321-
StatusListCredential statusList = statusListCredentialService.findOrCreateStatusList(defaultStatusPurpose);
319+
StatusListCredential statusList = statusListCredentialService.findOrCreateStatusList(statusPurpose);
322320

323321
// Assign next available index using database approach
324322
long assignedIndex = statusListCredentialService.findNextAvailableIndex(statusList.getId());
325323

326324
// If the current list is full, create a new one
327325
if(assignedIndex == -1) {
328326
log.info("Current status list is full, creating a new one");
329-
statusList = statusListCredentialService.generateStatusListCredential(defaultStatusPurpose);
327+
statusList = statusListCredentialService.generateStatusListCredential(statusPurpose);
330328
assignedIndex = statusListCredentialService.findNextAvailableIndex(statusList.getId());
331329

332330
if(assignedIndex == -1) {
@@ -341,19 +339,19 @@ private void addCredentialStatus(JSONObject jsonObject) {
341339
String statusId = domainUrl + "/v1/certify/status-list/" + statusList.getId();
342340
credentialStatus.put("id", statusId + "#" + assignedIndex);
343341
credentialStatus.put("type", "BitstringStatusListEntry");
344-
credentialStatus.put("statusPurpose", defaultStatusPurpose);
342+
credentialStatus.put("statusPurpose", statusPurpose);
345343
credentialStatus.put("statusListIndex", String.valueOf(assignedIndex));
346344
credentialStatus.put("statusListCredential", statusId);
347345

348346
// Add credential status to the VC data
349-
jsonObject.put("credentialStatus", credentialStatus);
347+
jsonObject.put(VCDM2Constants.CREDENTIAL_STATUS, credentialStatus);
350348

351349
// Extract credential details for ledger storage
352350
String credentialType = extractCredentialType(jsonObject);
353351

354352
// Prepare status details for ledger
355353
Map<String, Object> statusDetails = new HashMap<>();
356-
statusDetails.put("status_purpose", defaultStatusPurpose);
354+
statusDetails.put("status_purpose", statusPurpose);
357355
statusDetails.put("status_value", false); // Initially not revoked
358356
statusDetails.put("status_list_credential_id", statusList.getId());
359357
statusDetails.put("status_list_index", assignedIndex);
@@ -372,8 +370,8 @@ private void addCredentialStatus(JSONObject jsonObject) {
372370

373371
private static String extractCredentialType(JSONObject jsonObject) {
374372
try {
375-
if(jsonObject.has("type")) {
376-
Object typeObj = jsonObject.get("type");
373+
if(jsonObject.has(Constants.TYPE)) {
374+
Object typeObj = jsonObject.get(Constants.TYPE);
377375
if(typeObj instanceof org.json.JSONArray) {
378376
org.json.JSONArray typeArray = (org.json.JSONArray) typeObj;
379377
List<String> types = new ArrayList<>();

certify-service/src/main/java/io/mosip/certify/services/CredentialConfigurationServiceImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.core.JsonProcessingException;
1111
import io.mosip.certify.core.constants.Constants;
1212
import io.mosip.certify.core.constants.ErrorConstants;
13+
import io.mosip.certify.core.constants.VCDM2Constants;
1314
import io.mosip.certify.core.constants.VCFormats;
1415
import io.mosip.certify.core.dto.*;
1516
import io.mosip.certify.core.exception.CertifyException;
@@ -59,6 +60,9 @@ public class CredentialConfigurationServiceImpl implements CredentialConfigurati
5960
@Value("#{${mosip.certify.credential-config.issuer.display}}")
6061
private List<Map<String, String>> issuerDisplay;
6162

63+
@Value("#{${mosip.certify.data-provider-plugin.credential-status.supported-purposes:{}}}")
64+
private List<String> credentialStatusSupportedPurposes;
65+
6266
private static final String CREDENTIAL_CONFIG_CACHE_NAME = "credentialConfig";
6367

6468
@Override
@@ -88,6 +92,8 @@ public CredentialConfigResponse addCredentialConfiguration(CredentialConfigurati
8892
" is not supported for the signature algorithm: " + credentialConfig.getSignatureAlgo());
8993
}
9094
}
95+
96+
credentialConfig.setCredentialStatusPurpose(credentialStatusSupportedPurposes);
9197
}
9298

9399
validateCredentialConfiguration(credentialConfig);

certify-service/src/main/java/io/mosip/certify/vcformatters/VCFormatter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,11 @@ public interface VCFormatter {
6363
* @return
6464
*/
6565
String getSignatureCryptoSuite(String templateName);
66+
67+
/**
68+
* returns the credential status purpose used for adding credentialStatus to the VC.
69+
* @param templateName
70+
* @return
71+
*/
72+
List<String> getCredentialStatusPurpose(String templateName);
6673
}

certify-service/src/main/java/io/mosip/certify/vcformatters/VelocityTemplatingEngineImpl.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ public String getSignatureCryptoSuite(String templateName) {
190190
return getCachedCredentialConfig(templateName).getSignatureCryptoSuite(); // NEW
191191
}
192192

193+
@Override
194+
public List<String> getCredentialStatusPurpose(String templateName) {
195+
return getCachedCredentialConfig(templateName).getCredentialStatusPurpose();
196+
}
197+
193198
/**
194199
* performs the templating
195200
* NOTE: the defaultSettings map should have the "templateName" key set to
@@ -349,20 +354,20 @@ public String format(Map<String, Object> templateInput) {
349354
}
350355
VelocityContext context = new VelocityContext(finalTemplate);
351356
engine.evaluate(context, writer, /*logTag */ templateName, vcTemplateString); // use vcTemplateString
357+
JSONObject jsonObject = new JSONObject(writer.toString());
352358
if (StringUtils.isNotEmpty(idPrefix)) {
353-
JSONObject j = new JSONObject(writer.toString());
354-
j.put(VCDMConstants.ID, idPrefix + UUID.randomUUID());
355-
return j.toString();
359+
jsonObject.put(VCDMConstants.ID, idPrefix + UUID.randomUUID());
356360
}
357-
if( templateInput.containsKey("_vct") && templateInput.containsKey("_cnf")
358-
&& templateInput.containsKey("_iss")) {
359-
JSONObject j = new JSONObject(writer.toString());
360-
j.put("vct", templateInput.get("_vct"));
361-
j.put("cnf", templateInput.get("_cnf"));
362-
j.put("iss", templateInput.get("_iss"));
363-
return j.toString();
361+
if(templateInput.containsKey(VCDM2Constants.CREDENTIAL_STATUS) && templateName.contains(VCDM2Constants.URL)) {
362+
jsonObject.put(VCDM2Constants.CREDENTIAL_STATUS, templateInput.get(VCDM2Constants.CREDENTIAL_STATUS));
363+
}
364+
if( templateInput.containsKey(VCT) && templateInput.containsKey(CNF)
365+
&& templateInput.containsKey(ISS)) {
366+
jsonObject.put(VCT, templateInput.get(VCT));
367+
jsonObject.put(CNF, templateInput.get(CNF));
368+
jsonObject.put(ISS, templateInput.get(ISS));
364369
}
365370

366-
return writer.toString();
371+
return jsonObject.toString();
367372
}
368373
}

certify-service/src/main/resources/application-local.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mosip.certify.authorization.url=http://localhost:8088
2020
mosip.certify.discovery.issuer-id=${mosip.certify.domain.url}${server.servlet.path}
2121
mosip.certify.data-provider-plugin.issuer.vc-sign-algo=Ed25519Signature2020
2222
mosip.certify.plugin-mode=DataProvider
23-
#mosip.certify.data-provider-plugin.data-integrity.crypto-suite=ecdsa-rdfc-2019
23+
mosip.certify.data-provider-plugin.credential-status.supported-purposes={'revocation','suspension'}
2424

2525
##--------------change this later---------------------------------
2626
mosip.certify.supported.jwt-proof-alg={'RS256','PS256','ES256'}
@@ -226,7 +226,7 @@ mosip.certify.mock.authenticator.get-identity-url=http://localhost:8082/v1/mock-
226226

227227
# details of VC issuer's public key & controller for DataProvider plugin
228228
mosip.certify.data-provider-plugin.issuer-public-key-uri=https://vharsh.github.io/DID/mock-rsa.json
229-
mosip.certify.data-provider-plugin.issuer-uri=did:web:jainhitesh9998.github.io:tempfiles:vc-local-ed25519
229+
mosip.certify.data-provider-plugin.did-url=did:web:jainhitesh9998.github.io:tempfiles:vc-local-ed25519
230230

231231
## ---------------------------------------- Cache configuration --------------------------------------------------------
232232

@@ -241,7 +241,7 @@ mosip.certify.cache.security.algorithm-name=AES/ECB/PKCS5Padding
241241
#spring.data.redis.password=redis
242242

243243
spring.cache.type=simple
244-
mosip.certify.cache.names=userinfo,vcissuance,templatecache
244+
mosip.certify.cache.names=userinfo,vcissuance,templatecache,certificatedatacache
245245
spring.cache.cache-names=${mosip.certify.cache.names}
246246
management.health.redis.enabled=false
247247

0 commit comments

Comments
 (0)