Skip to content

Commit

Permalink
feat: credentials validation api wip
Browse files Browse the repository at this point in the history
  • Loading branch information
thackerronak committed Jun 1, 2023
1 parent b375317 commit 0515ef6
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,14 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers(new AntPathRequestMatcher("/docs/api-docs/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/ui/swagger-ui/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/actuator/health/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher(RestURI.DID_RESOLVE, GET.name())).permitAll() //Get did document
.requestMatchers(new AntPathRequestMatcher(RestURI.DID_DOCUMENTS, GET.name())).permitAll() //Get did document
.requestMatchers(new AntPathRequestMatcher(RestURI.WALLETS, POST.name())).hasRole(ApplicationConstant.ROLE_ADD_WALLETS) //Create wallet
.requestMatchers(new AntPathRequestMatcher(RestURI.WALLETS, GET.name())).hasAnyRole(ApplicationConstant.ROLE_VIEW_WALLETS) //Get all wallet
.requestMatchers(new AntPathRequestMatcher(RestURI.API_WALLETS_IDENTIFIER, GET.name())).hasAnyRole(ApplicationConstant.ROLE_VIEW_WALLET, ApplicationConstant.ROLE_VIEW_WALLETS) //get wallet by BPN
.requestMatchers(new AntPathRequestMatcher(RestURI.API_WALLETS_IDENTIFIER_CREDENTIALS, POST.name())).hasAnyRole(ApplicationConstant.ROLE_UPDATE_WALLETS, ApplicationConstant.ROLE_UPDATE_WALLET) //Store credential
.requestMatchers(new AntPathRequestMatcher(RestURI.CREDENTIALS, GET.name())).hasAnyRole(ApplicationConstant.ROLE_VIEW_WALLET, ApplicationConstant.ROLE_VIEW_WALLETS) //get credentials
.requestMatchers(new AntPathRequestMatcher(RestURI.CREDENTIALS_VALIDATION, POST.name())).hasAnyRole(ApplicationConstant.ROLE_VIEW_WALLET, ApplicationConstant.ROLE_VIEW_WALLETS) //validate credentials
.requestMatchers(new AntPathRequestMatcher(RestURI.CREDENTIALS_ISSUER_MEMBERSHIP, POST.name())).hasAnyRole(ApplicationConstant.ROLE_UPDATE_WALLETS, ApplicationConstant.ROLE_UPDATE_WALLET) //issue Membership Credential
.requestMatchers(new AntPathRequestMatcher(RestURI.CREDENTIALS_ISSUER_DISMANTLER, POST.name())).hasAnyRole(ApplicationConstant.ROLE_UPDATE_WALLETS, ApplicationConstant.ROLE_UPDATE_WALLET) //issue dismantler Credential
.requestMatchers(new AntPathRequestMatcher(RestURI.API_CREDENTIALS_ISSUER_FRAMEWORK, POST.name())).hasAnyRole(ApplicationConstant.ROLE_UPDATE_WALLETS, ApplicationConstant.ROLE_UPDATE_WALLET) //issue dismantler Credential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ private RestURI() {
* The constant DID_DOCUMENTS.
*/
public static final String DID_DOCUMENTS = "/api/didDocuments/{identifier}";
public static final String DID_RESOLVE = "/{bpn}/did.json";
/**
* The constant WALLETS_BY_BPN.
*/
Expand All @@ -52,6 +53,7 @@ private RestURI() {
* The constant CREDENTIALS.
*/
public static final String CREDENTIALS = "/api/credentials";
public static final String CREDENTIALS_VALIDATION = "/api/credentials/validation";
/**
* The constant CREDENTIALS_ISSUER_MEMBERSHIP.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
package org.eclipse.tractusx.managedidentitywallets.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -38,6 +40,7 @@

import java.security.Principal;
import java.util.List;
import java.util.Map;

/**
* The type Credential controller.
Expand Down Expand Up @@ -108,4 +111,38 @@ public ResponseEntity<VerifiableCredential> issueDismantlerCredential(@Valid @Re
public ResponseEntity<VerifiableCredential> issueFrameworkCredential(@Valid @RequestBody IssueFrameworkCredentialRequest request, Principal principal) {
return ResponseEntity.status(HttpStatus.CREATED).body(service.issueFrameworkCredential(request, getBPNFromToken(principal)));
}

@Operation(summary = "Validate Verifiable Credentials", description = "Permission: **view_wallets** OR **view_wallet** \n\n Validate Verifiable Credentials")
@PostMapping(path = RestURI.CREDENTIALS_VALIDATION, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)

@io.swagger.v3.oas.annotations.parameters.RequestBody(content = {
@Content(examples = @ExampleObject("""
{
"id": "http://example.edu/credentials/333",
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"type": [
"University-Degree-Credential, VerifiableCredential"
],
"issuer": "did:example:76e12ec712ebc6f1c221ebfeb1f",
"issuanceDate": "2019-06-16T18:56:59Z",
"expirationDate": "2019-06-17T18:56:59Z",
"credentialSubject": {
"college": "Test-University"
},
"proof": {
"type": "Ed25519Signature2018",
"created": "2021-11-17T22:20:27Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:example:76e12ec712ebc6f1c221ebfeb1f#keys-1",
"jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFZERTQSJ9..JNerzfrK46Mq4XxYZEnY9xOK80xsEaWCLAHuZsFie1-NTJD17wWWENn_DAlA_OwxGF5dhxUJ05P6Dm8lcmF5Cg"
}
}
"""))
})
public ResponseEntity<Map<String, Object>> createPresentation(@RequestBody Map<String, Object> data) {
return ResponseEntity.status(HttpStatus.OK).body(service.credentialsValidation(data));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,10 @@ public class DidDocumentController {
public ResponseEntity<DidDocument> getDidDocument(@PathVariable(name = "identifier") String identifier) {
return ResponseEntity.status(HttpStatus.OK).body(service.getDidDocument(identifier));
}

@Operation(description = "Resolve the DID document for a given BPN", summary = "Resolve DID Document")
@GetMapping(path = RestURI.DID_RESOLVE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<DidDocument> getDidResolve(@PathVariable(name = "bpn") String bpn) {
return ResponseEntity.status(HttpStatus.OK).body(service.getDidDocument(bpn));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,21 @@
import org.eclipse.tractusx.managedidentitywallets.exception.ForbiddenException;
import org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils;
import org.eclipse.tractusx.managedidentitywallets.utils.Validate;
import org.eclipse.tractusx.ssi.lib.did.web.DidWebDocumentResolver;
import org.eclipse.tractusx.ssi.lib.did.web.util.DidWebParser;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialType;
import org.eclipse.tractusx.ssi.lib.proof.LinkedDataProofValidation;
import org.eclipse.tractusx.ssi.lib.resolver.DidDocumentResolverRegistryImpl;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.net.http.HttpClient;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -150,7 +156,7 @@ public VerifiableCredential issueFrameworkCredential(IssueFrameworkCredentialReq
"value", request.getValue(),
"contract-template", request.getContractTemplate(),
"contract-version", request.getContractVersion());
Credential credential = CommonUtils.getCredential(subject, MIWVerifiableCredentialType.USE_CASE_FRAMEWORK_CONDITION_CX, miwSettings.authorityWalletDid(), privateKeyBytes, holderWallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());
Credential credential = CommonUtils.getCredential(subject, MIWVerifiableCredentialType.USE_CASE_FRAMEWORK_CONDITION_CX, baseWallet.getDidDocument(), privateKeyBytes, holderWallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());

//Store Credential
credential = create(credential);
Expand Down Expand Up @@ -187,7 +193,7 @@ public VerifiableCredential issueDismantlerCredential(IssueDismantlerCredentialR
"holderIdentifier", holderWallet.getBpn(),
"activityType", request.getActivityType(),
"allowedVehicleBrands", request.getAllowedVehicleBrands());
Credential credential = CommonUtils.getCredential(subject, MIWVerifiableCredentialType.DISMANTLER_CREDENTIAL_CX, miwSettings.authorityWalletDid(), privateKeyBytes, holderWallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());
Credential credential = CommonUtils.getCredential(subject, MIWVerifiableCredentialType.DISMANTLER_CREDENTIAL_CX, baseWallet.getDidDocument(), privateKeyBytes, holderWallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());

//Store Credential
credential = create(credential);
Expand Down Expand Up @@ -226,7 +232,7 @@ public VerifiableCredential issueMembershipCredential(IssueMembershipCredentialR
"holderIdentifier", holderWallet.getBpn(),
"memberOf", baseWallet.getName(),
"status", "Active",
"startTime", Instant.now().toString()), MIWVerifiableCredentialType.MEMBERSHIP_CREDENTIAL_CX, miwSettings.authorityWalletDid(), privateKeyBytes, holderWallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());
"startTime", Instant.now().toString()), MIWVerifiableCredentialType.MEMBERSHIP_CREDENTIAL_CX, baseWallet.getDidDocument(), privateKeyBytes, holderWallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());

//Store Credential
credential = create(credential);
Expand All @@ -236,10 +242,27 @@ public VerifiableCredential issueMembershipCredential(IssueMembershipCredentialR
}




private void isCredentialExit(String holderDid, String credentialType) {
Validate.isTrue(credentialRepository.existsByHolderDidAndType(holderDid, credentialType)).launch(new DuplicateCredentialProblem("Credential of type " + credentialType + " is already exists "));
}

public Map<String, Object> credentialsValidation(Map<String, Object> data) {
VerifiableCredential verifiableCredential = new VerifiableCredential(data);
// DID Resolver Constracture params
DidWebParser didParser = new DidWebParser();
var httpClient = HttpClient.newHttpClient();
var enforceHttps = true;

var didDocumentResolverRegistry = new DidDocumentResolverRegistryImpl();
didDocumentResolverRegistry.register(
new DidWebDocumentResolver(httpClient, didParser, enforceHttps));

LinkedDataProofValidation proofValidation = LinkedDataProofValidation.newInstance(didDocumentResolverRegistry);
Boolean valid = proofValidation.checkProof(verifiableCredential); // TODO getting InvalidKeyException
Map<String, Object> response = new HashMap<>();
response.put("valid", valid);
response.put("vp", verifiableCredential);

return response;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public Wallet createWallet(CreateWalletRequest request) {

Credential credential = CommonUtils.getCredential(Map.of("type", MIWVerifiableCredentialType.BPN_CREDENTIAL,
"id", wallet.getDid(),
"bpn", wallet.getBpn()), MIWVerifiableCredentialType.BPN_CREDENTIAL_CX, miwSettings.authorityWalletDid(), privateKeyBytes, wallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());
"bpn", wallet.getBpn()), MIWVerifiableCredentialType.BPN_CREDENTIAL_CX, baseWallet.getDidDocument(), privateKeyBytes, wallet.getDid(), miwSettings.vcContexts(), miwSettings.vcExpiryDate());

//Store Credential
credentialRepository.save(credential);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
import org.eclipse.tractusx.managedidentitywallets.constant.ApplicationConstant;
import org.eclipse.tractusx.managedidentitywallets.dao.entity.Credential;
import org.eclipse.tractusx.ssi.lib.model.Ed25519Signature2020;
import org.eclipse.tractusx.ssi.lib.model.did.DidDocument;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialBuilder;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialSubject;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialType;
import org.eclipse.tractusx.ssi.lib.proof.LinkedDataProofGenerator;
import org.eclipse.tractusx.ssi.lib.proof.hash.LinkedDataHasher;
import org.eclipse.tractusx.ssi.lib.proof.transform.LinkedDataTransformer;
import org.eclipse.tractusx.ssi.lib.proof.verify.LinkedDataSigner;

import java.net.URI;
import java.time.Instant;
Expand Down Expand Up @@ -66,12 +70,12 @@ public static String getIdentifierType(String identifier) {
*
* @param subject the subject
* @param type the type
* @param issuerDid the issuer did
* @param issuerDoc the issuer doc
* @param privateKeyBytes the private key bytes
* @param holderDid the holder did
* @return the credential
*/
public static Credential getCredential(Map<String, Object> subject, String type, String issuerDid, byte[] privateKeyBytes, String holderDid, List<String> contexts, Date expiryDate) {
public static Credential getCredential(Map<String, Object> subject, String type, DidDocument issuerDoc, byte[] privateKeyBytes, String holderDid, List<String> contexts, Date expiryDate) {
//VC Subject
VerifiableCredentialSubject verifiableCredentialSubject =
new VerifiableCredentialSubject(subject);
Expand All @@ -80,34 +84,40 @@ public static Credential getCredential(Map<String, Object> subject, String type,
List<String> verifiableCredentialType = List.of(VerifiableCredentialType.VERIFIABLE_CREDENTIAL, type);

// Create VC
VerifiableCredential verifiableCredential = createVerifiableCredential(issuerDid, verifiableCredentialType, verifiableCredentialSubject, privateKeyBytes, contexts, expiryDate);
VerifiableCredential verifiableCredential = createVerifiableCredential(issuerDoc, verifiableCredentialType,
verifiableCredentialSubject, privateKeyBytes, contexts, expiryDate);

// Create Credential
return Credential.builder()
.holderDid(holderDid)
.issuerDid(issuerDid)
.issuerDid(issuerDoc.getId().toString())
.type(type)
.data(verifiableCredential)
.build();
}


private static VerifiableCredential createVerifiableCredential(String issuerDid, List<String> verifiableCredentialType, VerifiableCredentialSubject verifiableCredentialSubject, byte[] privateKey, List<String> contexts, Date expiryDate) {
private static VerifiableCredential createVerifiableCredential(DidDocument issuerDoc, List<String> verifiableCredentialType,
VerifiableCredentialSubject verifiableCredentialSubject,
byte[] privateKey, List<String> contexts, Date expiryDate) {
//VC Builder
VerifiableCredentialBuilder builder =
new VerifiableCredentialBuilder()
.context(contexts)
.id(URI.create(UUID.randomUUID().toString()))
.type(verifiableCredentialType)
.issuer(URI.create(issuerDid))
.issuer(issuerDoc.getId())
.expirationDate(expiryDate.toInstant())
.issuanceDate(Instant.now())
.credentialSubject(verifiableCredentialSubject);


//Ed25519 Proof Builder
LinkedDataProofGenerator generator = LinkedDataProofGenerator.create();
Ed25519Signature2020 proof = generator.createEd25519Signature2020(builder.build(), URI.create(issuerDid), privateKey);
LinkedDataProofGenerator generator = new LinkedDataProofGenerator(
new LinkedDataHasher(), new LinkedDataTransformer(), new LinkedDataSigner());
URI verificationMethod = issuerDoc.getVerificationMethods().get(0).getId();
Ed25519Signature2020 proof = generator.createEd25519Signature2020(builder.build(), verificationMethod,
privateKey);

//Adding Proof to VC
builder.proof(proof);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,35 @@ void getDidDocumentWithBpn200() {
Assertions.assertNotNull(response.getBody());
}

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

createWallet(bpn, did);
ResponseEntity<String> response = restTemplate.getForEntity(RestURI.DID_DOCUMENTS, String.class, did);
Assertions.assertEquals(HttpStatus.OK.value(), response.getStatusCode().value());
Assertions.assertNotNull(response.getBody());
}

@Test
void getDidResolveInvalidBpn404() {
ResponseEntity<String> response = restTemplate.getForEntity(RestURI.DID_RESOLVE, String.class, UUID.randomUUID().toString());
Assertions.assertEquals(HttpStatus.NOT_FOUND.value(), response.getStatusCode().value());
}

@Test
void getDidResolveWithBpn200() {

String bpn = UUID.randomUUID().toString();
String did = "did:web:localhost:" + bpn;

createWallet(bpn, did);
ResponseEntity<String> response = restTemplate.getForEntity(RestURI.DID_RESOLVE, String.class, bpn);
Assertions.assertEquals(HttpStatus.OK.value(), response.getStatusCode().value());
Assertions.assertNotNull(response.getBody());
}

private Wallet createWallet(String bpn, String did) {
String didDocument = """
{
Expand All @@ -101,16 +130,4 @@ private Wallet createWallet(String bpn, String did) {
.build();
return walletRepository.save(wallet);
}

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

createWallet(bpn, did);
ResponseEntity<String> response = restTemplate.getForEntity(RestURI.DID_DOCUMENTS, String.class, did);
Assertions.assertEquals(HttpStatus.OK.value(), response.getStatusCode().value());
Assertions.assertNotNull(response.getBody());
}

}

0 comments on commit 0515ef6

Please sign in to comment.