Skip to content

Commit

Permalink
feat: summery VC flow after holder delete summary VC
Browse files Browse the repository at this point in the history
  • Loading branch information
nitin-vavdiya committed Jun 9, 2023
1 parent b74c41c commit 33135c1
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class StringPool {
public static final String VALIDATE_EXPIRY_DATE = "validateExpiryDate";
public static final String DID_DOCUMENT = "didDocument";
public static final String VEHICLE_DISMANTLE = "vehicleDismantle";
public static final String CREATED_AT = "createdAt";

private StringPool() {
throw new IllegalStateException("Constant class");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public interface HoldersCredentialRepository extends BaseRepository<HoldersCrede
*/
List<HoldersCredential> getByHolderDidAndType(String holderDid, String type);

List<HoldersCredential> getByHolderDidAndIssuerDidAndType(String holderDid, String issuerDid, String type);
List<HoldersCredential> getByHolderDidAndIssuerDidAndTypeAndStored(String holderDid, String issuerDid, String type, boolean stored);

/**
* Exists by holder did and type boolean.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.eclipse.tractusx.managedidentitywallets.dto.IssueMembershipCredentialRequest;
import org.eclipse.tractusx.managedidentitywallets.exception.BadDataException;
import org.eclipse.tractusx.managedidentitywallets.exception.DuplicateCredentialProblem;
import org.eclipse.tractusx.managedidentitywallets.exception.DuplicateSummaryCredentialProblem;
import org.eclipse.tractusx.managedidentitywallets.exception.ForbiddenException;
import org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils;
import org.eclipse.tractusx.managedidentitywallets.utils.Validate;
Expand Down Expand Up @@ -470,23 +469,19 @@ private boolean isSelfIssued(String holderBpn) {
*/
private void updateSummeryCredentials(DidDocument issuerDidDocument, byte[] issuerPrivateKey, String issuerDid, String holderBpn, String holderDid, String type) {

//get summery VC of holder
List<HoldersCredential> vcs = holdersCredentialRepository.getByHolderDidAndIssuerDidAndType(holderDid, issuerDid, MIWVerifiableCredentialType.SUMMARY_CREDENTIAL);
//get last issued summary vc to holder to update items
Page<IssuersCredential> filter = getLastIssuedSummaryCredential(issuerDid, holderDid);
List<String> items;
if (CollectionUtils.isEmpty(vcs)) {
log.debug("No summery VC found for did ->{}", holderDid);
items = List.of(type);
} else {
Validate.isTrue(vcs.size() > 1).launch(new DuplicateSummaryCredentialProblem("Something is not right, there should be only one summery VC of holder at a time"));
HoldersCredential summeryCredential = vcs.get(0);
if (!filter.getContent().isEmpty()) {
IssuersCredential issuersCredential = filter.getContent().get(0);

//check if summery VC has subject
Validate.isTrue(summeryCredential.getData().getCredentialSubject().isEmpty()).launch(new BadDataException("VC subject not found in existing su,,ery VC"));
Validate.isTrue(issuersCredential.getData().getCredentialSubject().isEmpty()).launch(new BadDataException("VC subject not found in existing su,,ery VC"));

//Check if we have only one subject in summery VC
Validate.isTrue(summeryCredential.getData().getCredentialSubject().size() > 1).launch(new BadDataException("VC subjects can more then 1 in case of summery VC"));
Validate.isTrue(issuersCredential.getData().getCredentialSubject().size() > 1).launch(new BadDataException("VC subjects can more then 1 in case of summery VC"));

VerifiableCredentialSubject subject = summeryCredential.getData().getCredentialSubject().get(0);
VerifiableCredentialSubject subject = issuersCredential.getData().getCredentialSubject().get(0);
if (subject.containsKey(StringPool.ITEMS)) {
items = (List<String>) subject.get(StringPool.ITEMS);
if (!items.contains(type)) {
Expand All @@ -495,7 +490,17 @@ private void updateSummeryCredentials(DidDocument issuerDidDocument, byte[] issu
} else {
items = List.of(type);
}
//delete old summery VC from holder table
} else {
items = List.of(type);
}
log.debug("Issuing summary VC with items ->{}", items);

//get summery VC of holder
List<HoldersCredential> vcs = holdersCredentialRepository.getByHolderDidAndIssuerDidAndTypeAndStored(holderDid, issuerDid, MIWVerifiableCredentialType.SUMMARY_CREDENTIAL, false); //deleted only not stored VC
if (CollectionUtils.isEmpty(vcs)) {
log.debug("No summery VC found for did ->{}, checking in issuer", holderDid);
} else {
//delete old summery VC from holder table, delete only not stored VC
holdersCredentialRepository.deleteAll(vcs);
}

Expand Down Expand Up @@ -525,4 +530,22 @@ private void updateSummeryCredentials(DidDocument issuerDidDocument, byte[] issu

log.info("Summery VC updated for holder did -> {}", holderDid);
}

private Page<IssuersCredential> getLastIssuedSummaryCredential(String issuerDid, String holderDid) {
FilterRequest filterRequest = new FilterRequest();

//we need latest one record
filterRequest.setPage(0);
filterRequest.setSize(1);
Sort sort = new Sort();
sort.setColumn(StringPool.CREATED_AT);
sort.setSortType(SortType.valueOf("desc".toUpperCase()));
filterRequest.setSort(sort);

filterRequest.appendCriteria(StringPool.HOLDER_DID, Operator.EQUALS, holderDid);
filterRequest.appendCriteria(StringPool.ISSUER_DID, Operator.EQUALS, issuerDid);
filterRequest.appendCriteria(StringPool.TYPE, Operator.EQUALS, MIWVerifiableCredentialType.SUMMARY_CREDENTIAL);

return filter(filterRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {ManagedIdentityWalletsApplication.class})
Expand Down Expand Up @@ -96,19 +97,100 @@ void issueMembershipCredentialTest403() {
}

@Test
void issueMembershipCredentialToBaseWalletTest409() throws JsonProcessingException {
void testIssueSummeryVCAfterDeleteSummaryVCFromHolderWallet() throws JsonProcessingException {
String bpn = UUID.randomUUID().toString();
String did = "did:web:localhost:" + bpn;

// create wallet, in background bpn and summary credential generated
TestUtils.getWalletFromString(TestUtils.createWallet(bpn, bpn, restTemplate).getBody());
Wallet wallet = TestUtils.getWalletFromString(TestUtils.createWallet(bpn, bpn, restTemplate).getBody());

List<HoldersCredential> byHolderDid = holdersCredentialRepository.getByHolderDid(did);

// create manually 2nd summary credential
issueSummaryCredentialinDB(did);
//delete all VC
holdersCredentialRepository.deleteAll(byHolderDid);

// get 409 status as 2 summary credential found in holder table
//issue membership
ResponseEntity<String> response = TestUtils.issueMembershipVC(restTemplate, bpn, miwSettings.authorityWalletBpn());
Assertions.assertEquals(HttpStatus.CONFLICT.value(), response.getStatusCode().value());
Assertions.assertEquals(response.getStatusCode().value(), HttpStatus.CREATED.value());

//check summary VC in holder wallet
List<HoldersCredential> summaryVcs = holdersCredentialRepository.getByHolderDidAndIssuerDidAndTypeAndStored(did, miwSettings.authorityWalletDid(), MIWVerifiableCredentialType.SUMMARY_CREDENTIAL, false);
Assertions.assertFalse(summaryVcs.isEmpty());

//check items, it should be 2
List<String> items = (List<String>) summaryVcs.get(0).getData().getCredentialSubject().get(0).get(StringPool.ITEMS);

Assertions.assertTrue(items.contains(MIWVerifiableCredentialType.MEMBERSHIP_CREDENTIAL_CX));
Assertions.assertTrue(items.contains(MIWVerifiableCredentialType.BPN_CREDENTIAL_CX));
}

@Test
void testStoredSummaryVCTest() throws JsonProcessingException {
String bpn = UUID.randomUUID().toString();
String did = "did:web:localhost:" + bpn;

// create wallet, in background bpn and summary credential generated
Wallet wallet = TestUtils.getWalletFromString(TestUtils.createWallet(bpn, bpn, restTemplate).getBody());


String vc = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "urn:uuid:12345678-1234-1234-1234-123456789abc",
"type": [
"VerifiableCredential",
"SummaryCredential"
],
"issuer": "did:web:localhost:BPNL000000000000",
"issuanceDate": "2023-06-02T12:00:00Z",
"expirationDate": "2022-06-16T18:56:59Z",
"credentialSubject": [{
"id": "did:web:localhost:BPNL000000000000",
"holderIdentifier": "BPN of holder",
"type": "Summary-List",
"name": "CX-Credentials",
"items": [
"cx-active-member",
"cx-dismantler",
"cx-pcf",
"cx-sustainability",
"cx-quality",
"cx-traceability",
"cx-behavior-twin",
"cx-bpn"
],
"contract-templates": "https://public.catena-x.org/contracts/"
},{
"name":"test name"
}],
"proof": {
"type": "Ed25519Signature2018",
"created": "2023-06-02T12:00:00Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:web:example.com#key-1",
"jws": "eyJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2MjM1NzA3NDEsImV4cCI6MTYyMzU3NDM0MSwianRpIjoiMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5YWJjIiwicHJvb2YiOnsiaWQiOiJkaWQ6d2ViOmV4YW1wbGUuY29tIiwibmFtZSI6IkJlaXNwaWVsLU9yZ2FuaXNhdGlvbiJ9fQ.SignedExampleSignature"
}
}
""";
HttpHeaders headers = AuthenticationUtils.getValidUserHttpHeaders(bpn);

Map<String, Objects> map = objectMapper.readValue(vc.replace("##did", did), Map.class);
HttpEntity<Map> entity = new HttpEntity<>(map, headers);

ResponseEntity<Map> response = restTemplate.exchange(RestURI.API_WALLETS_IDENTIFIER_CREDENTIALS, HttpMethod.POST, entity, Map.class, bpn);
Assertions.assertEquals(HttpStatus.CREATED.value(), response.getStatusCode().value());

//issue membership
ResponseEntity<String> response1 = TestUtils.issueMembershipVC(restTemplate, bpn, miwSettings.authorityWalletBpn());
Assertions.assertEquals(HttpStatus.CREATED.value(), response1.getStatusCode().value());

//stored VC should not be deleted
List<HoldersCredential> summaryCredential = holdersCredentialRepository.getByHolderDidAndIssuerDidAndTypeAndStored(wallet.getDid(), "did:web:localhost:BPNL000000000000", "SummaryCredential", true);
Assertions.assertFalse(summaryCredential.isEmpty());

}

@Test
Expand All @@ -120,7 +202,7 @@ void issueMembershipCredentialToBaseWalletTest400() throws JsonProcessingExcepti
Wallet wallet = TestUtils.getWalletFromString(TestUtils.createWallet(bpn, bpn, restTemplate).getBody());

//add 2 subject in VC for testing
List<HoldersCredential> vcs = holdersCredentialRepository.getByHolderDidAndType(wallet.getDid(), MIWVerifiableCredentialType.SUMMARY_CREDENTIAL);
List<IssuersCredential> vcs = issuersCredentialRepository.getByIssuerDidAndHolderDidAndType(miwSettings.authorityWalletDid(), wallet.getDid(), MIWVerifiableCredentialType.SUMMARY_CREDENTIAL);

String vc = """
{
Expand Down Expand Up @@ -167,15 +249,15 @@ void issueMembershipCredentialToBaseWalletTest400() throws JsonProcessingExcepti
VerifiableCredential verifiableCredential = new VerifiableCredential(new ObjectMapper().readValue(vc, Map.class));
vcs.get(0).setData(verifiableCredential);

holdersCredentialRepository.save(vcs.get(0));
issuersCredentialRepository.save(vcs.get(0));

//Check if we do not have items in subject
ResponseEntity<String> response = TestUtils.issueMembershipVC(restTemplate, bpn, miwSettings.authorityWalletBpn());
Assertions.assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCode().value());

vcs.get(0).getData().getCredentialSubject().remove(1);
vcs.get(0).getData().getCredentialSubject().get(0).remove(StringPool.ITEMS);
holdersCredentialRepository.save(vcs.get(0));
issuersCredentialRepository.save(vcs.get(0));
}


Expand Down Expand Up @@ -292,51 +374,4 @@ private void validateTypes(VerifiableCredential verifiableCredential, String hol
Assertions.assertTrue(verifiableCredential.getTypes().contains(MIWVerifiableCredentialType.MEMBERSHIP_CREDENTIAL_CX));
Assertions.assertEquals(verifiableCredential.getCredentialSubject().get(0).get(StringPool.HOLDER_IDENTIFIER), holderBpn);
}

private void issueSummaryCredentialinDB(String did) throws JsonProcessingException {
String vc = """
{
"id": "http://example.edu/credentials/3732",
"@context":
[
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"type":
[
"SummaryCredential", "VerifiableCredential"
],
"issuer": "did:example:76e12ec712ebc6f1c221ebfeb1f",
"issuanceDate": "2019-06-16T18:56:59Z",
"expirationDate": "2019-06-17T18:56:59Z",
"credentialSubject":
[
{
"id": "##did",
"college": "Test-University"
}
],
"proof":
{
"type": "Ed25519Signature2018",
"created": "2021-11-17T22:20:27Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:example:76e12ec712ebc6f1c221ebfeb1f#key-1",
"jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFZERTQSJ9..JNerzfrK46Mq4XxYZEnY9xOK80xsEaWCLAHuZsFie1-NTJD17wWWENn_DAlA_OwxGF5dhxUJ05P6Dm8lcmF5Cg"
}
}
""";
VerifiableCredential verifiableCredential = new VerifiableCredential(new ObjectMapper().readValue(vc, Map.class));
HoldersCredential holdersCredential = HoldersCredential.builder()
.credentialId(verifiableCredential.getId().toString())
.data(new VerifiableCredential(verifiableCredential))
.holderDid(did)
.type(MIWVerifiableCredentialType.SUMMARY_CREDENTIAL)
.selfIssued(false)
.stored(false)
.issuerDid(miwSettings.authorityWalletDid())
.build();
holdersCredentialRepository.save(holdersCredential);
}

}

0 comments on commit 33135c1

Please sign in to comment.