io.mosip.certify.sunbirdrc.integration.service.SunbirdRCVCIssuancePlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sunbird-rc-certify-integration-impl Show documentation
Show all versions of sunbird-rc-certify-integration-impl Show documentation
Sunbird-RC plugin implementation that is used for the integration with certify
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package io.mosip.certify.sunbirdrc.integration.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import foundation.identity.jsonld.JsonLDObject;
import io.mosip.certify.api.dto.VCRequestDto;
import io.mosip.certify.api.dto.VCResult;
import io.mosip.certify.api.exception.VCIExchangeException;
import io.mosip.certify.api.spi.VCIssuancePlugin;
import io.mosip.certify.api.util.ErrorConstants;
import io.mosip.certify.sunbirdrc.integration.dto.RegistrySearchRequestDto;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.URLResourceLoader;
import org.apache.velocity.tools.generic.DateTool;
import org.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ConditionalOnProperty(value = "mosip.certify.integration.vci-plugin", havingValue = "SunbirdRCVCIssuancePlugin")
@Component
@Slf4j
public class SunbirdRCVCIssuancePlugin implements VCIssuancePlugin {
private static final String CREDENTIAL_TYPE_PROPERTY_PREFIX ="mosip.certify.vciplugin.sunbird-rc.credential-type";
private static final String LINKED_DATA_PROOF_VC_FORMAT ="ldp_vc";
private static final String TEMPLATE_URL = "template-url";
private static final String REGISTRY_GET_URL = "registry-get-url";
private static final String REGISTRY_SEARCH_URL= "registry-search-url";
private static final String CRED_SCHEMA_ID = "cred-schema-id";
private static final String CRED_SCHEMA_VESRION = "cred-schema-version";
private static final String STATIC_VALUE_MAP_ISSUER_ID = "static-value-map.issuerId";
private static final String CREDENTIAL_OBJECT_KEY = "credential";
private final String FILTER_EQUALS_OPERATOR = "eq";
private final String PSUT_TOKEN="psut";
@Autowired
Environment env;
@Autowired
ObjectMapper mapper;
@Autowired
private RestTemplate restTemplate;
@Value("${mosip.certify.vciplugin.sunbird-rc.issue-credential-url}")
String issueCredentialUrl;
@Value("${mosip.certify.vciplugin.sunbird-rc.enable-psut-based-registry-search:false}")
private boolean enablePSUTBasedRegistrySearch;
@Value("#{'${mosip.certify.vciplugin.sunbird-rc.supported-credential-types}'.split(',')}")
List supportedCredentialTypes;
private final Map credentialTypeTemplates = new HashMap<>();
private final Map> credentialTypeConfigMap = new HashMap<>();
private VelocityEngine vEngine;
@PostConstruct
public void initialize() throws VCIExchangeException {
vEngine = new VelocityEngine();
URLResourceLoader urlResourceLoader = new URLResourceLoader() {
@Override
public InputStream getResourceStream(String name) throws ResourceNotFoundException {
try {
URL url = new URL(name);
URLConnection connection = url.openConnection();
return connection.getInputStream();
} catch (IOException e) {
throw new ResourceNotFoundException("Unable to find resource '" + name + "'");
}
}
};
vEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "url");
vEngine.setProperty("url.resource.loader.instance", urlResourceLoader);
vEngine.init();
//Validate all the supported VC
for (String credentialType : supportedCredentialTypes) {
validateAndCachePropertiesForCredentialType(credentialType.trim());
}
}
@Override
public VCResult getVerifiableCredentialWithLinkedDataProof(VCRequestDto vcRequestDto, String holderId, Map identityDetails) throws VCIExchangeException {
if (vcRequestDto == null || vcRequestDto.getType() == null) {
throw new VCIExchangeException(ErrorConstants.VCI_EXCHANGE_FAILED);
}
List types = vcRequestDto.getType();
if (types.isEmpty() || !types.get(0).equals("VerifiableCredential")) {
log.error("Invalid request: first item in type is not VerifiableCredential");
throw new VCIExchangeException(ErrorConstants.VCI_EXCHANGE_FAILED);
}
types.remove(0);
String requestedCredentialType = String.join("-", types);
//Check if the key is in the supported-credential-types
if (!supportedCredentialTypes.contains(requestedCredentialType)) {
log.error("Credential type is not supported");
throw new VCIExchangeException(ErrorConstants.VCI_EXCHANGE_FAILED);
}
//Validate context of vcrequestdto with template
List contextList=vcRequestDto.getContext();
for(String supportedType:supportedCredentialTypes){
Template template= credentialTypeTemplates.get(supportedType);
validateContextUrl(template,contextList);
}
String registrySearchField = (identityDetails.containsKey("sub")) ? (String) identityDetails.get("sub") : null;
if (registrySearchField == null) {
log.error("Invalid request: registrySearchField is null");
throw new VCIExchangeException(ErrorConstants.VCI_EXCHANGE_FAILED);
}
Map responseRegistryMap;
if(enablePSUTBasedRegistrySearch){
String registrySearchUrl=credentialTypeConfigMap.get(requestedCredentialType).get(REGISTRY_SEARCH_URL);
responseRegistryMap= fetchRegistryObjectByPSUT(registrySearchUrl,registrySearchField);
}else {
String registryUrl=credentialTypeConfigMap.get(requestedCredentialType).get(REGISTRY_GET_URL);
responseRegistryMap =fetchRegistryObject(registryUrl+ registrySearchField);
}
Map credentialRequestMap = createCredentialIssueRequest(requestedCredentialType, responseRegistryMap,vcRequestDto,holderId);
Map vcResponseMap =sendCredentialIssueRequest(credentialRequestMap);
VCResult vcResult = new VCResult();
JsonLDObject vcJsonLdObject = JsonLDObject.fromJsonObject((Map)vcResponseMap.get(CREDENTIAL_OBJECT_KEY));
vcResult.setCredential(vcJsonLdObject);
vcResult.setFormat(LINKED_DATA_PROOF_VC_FORMAT);
return vcResult;
}
@Override
public VCResult getVerifiableCredential(VCRequestDto vcRequestDto, String holderId, Map identityDetails) throws VCIExchangeException {
throw new VCIExchangeException(ErrorConstants.NOT_IMPLEMENTED);
}
private Map fetchRegistryObject(String entityUrl) throws VCIExchangeException {
RequestEntity requestEntity = RequestEntity
.get(UriComponentsBuilder.fromUriString(entityUrl).build().toUri()).build();
ResponseEntity