Skip to content

Commit

Permalink
fix: add test and validation
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafasalfiti committed Mar 12, 2024
1 parent 64fdcd8 commit b1d7b2c
Show file tree
Hide file tree
Showing 10 changed files with 922 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class StringPool {
public static final String ALLOWED_VEHICLE_BRANDS = "allowedVehicleBrands";
public static final String VERIFIABLE_CREDENTIALS = "verifiableCredentials";
public static final String VP = "vp";
public static final String VC = "vc";
public static final String VALID = "valid";
public static final String VALIDATE_AUDIENCE = "validateAudience";
public static final String VALIDATE_EXPIRY_DATE = "validateExpiryDate";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public CredentialsResponse issueCredential(Map<String, Object> data, boolean asJ
Validate.isFalse(callerBpn.equals(issuerWallet.getBpn())).launch(new ForbiddenException(BASE_WALLET_BPN_IS_NOT_MATCHING_WITH_REQUEST_BPN_FROM_TOKEN));

// get Key
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdentifierAsBytes(issuerWallet.getId());
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdAsBytes(issuerWallet.getId());

// check if the expiryDate is set
Date expiryDate = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

package org.eclipse.tractusx.managedidentitywallets.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jwt.SignedJWT;
import com.smartsensesolutions.java.commons.FilterRequest;
import com.smartsensesolutions.java.commons.base.repository.BaseRepository;
import com.smartsensesolutions.java.commons.base.service.BaseService;
Expand All @@ -29,6 +31,8 @@
import com.smartsensesolutions.java.commons.sort.Sort;
import com.smartsensesolutions.java.commons.sort.SortType;
import com.smartsensesolutions.java.commons.specification.SpecificationUtil;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.StringEscapeUtils;
Expand All @@ -40,6 +44,7 @@
import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet;
import org.eclipse.tractusx.managedidentitywallets.dao.repository.HoldersCredentialRepository;
import org.eclipse.tractusx.managedidentitywallets.dao.repository.IssuersCredentialRepository;
import org.eclipse.tractusx.managedidentitywallets.dto.CredentialVerificationRequest;
import org.eclipse.tractusx.managedidentitywallets.dto.CredentialsResponse;
import org.eclipse.tractusx.managedidentitywallets.dto.IssueDismantlerCredentialRequest;
import org.eclipse.tractusx.managedidentitywallets.dto.IssueFrameworkCredentialRequest;
Expand All @@ -52,11 +57,15 @@
import org.eclipse.tractusx.ssi.lib.did.resolver.DidResolver;
import org.eclipse.tractusx.ssi.lib.did.web.DidWebResolver;
import org.eclipse.tractusx.ssi.lib.did.web.util.DidWebParser;
import org.eclipse.tractusx.ssi.lib.exception.proof.JwtExpiredException;
import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtValidator;
import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtVerifier;
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.VerifiableCredentialSubject;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialType;
import org.eclipse.tractusx.ssi.lib.proof.LinkedDataProofValidation;
import org.eclipse.tractusx.ssi.lib.serialization.SerializeUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
Expand All @@ -66,7 +75,9 @@
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.http.HttpClient;
import java.text.ParseException;
import java.time.Instant;
import java.util.*;

Expand All @@ -75,6 +86,7 @@
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class IssuersCredentialService extends BaseService<IssuersCredential, Long> {

/**
Expand All @@ -93,26 +105,7 @@ public class IssuersCredentialService extends BaseService<IssuersCredential, Lon

private final CommonService commonService;

/**
* Instantiates a new Issuers credential service.
*
* @param issuersCredentialRepository the issuers credential repository
* @param miwSettings the miw settings
* @param credentialSpecificationUtil the credential specification util
* @param walletKeyService the wallet key service
* @param holdersCredentialRepository the holders credential repository
* @param commonService the common service
*/
public IssuersCredentialService(IssuersCredentialRepository issuersCredentialRepository, MIWSettings miwSettings,
SpecificationUtil<IssuersCredential> credentialSpecificationUtil,
WalletKeyService walletKeyService, HoldersCredentialRepository holdersCredentialRepository, CommonService commonService) {
this.issuersCredentialRepository = issuersCredentialRepository;
this.miwSettings = miwSettings;
this.credentialSpecificationUtil = credentialSpecificationUtil;
this.walletKeyService = walletKeyService;
this.holdersCredentialRepository = holdersCredentialRepository;
this.commonService = commonService;
}
private final ObjectMapper objectMapper;


@Override
Expand Down Expand Up @@ -190,7 +183,7 @@ public PageImpl<VerifiableCredential> getCredentials(String credentialId, String
*/
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED)
public VerifiableCredential issueBpnCredential(Wallet baseWallet, Wallet holderWallet, boolean authority) {
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdentifierAsBytes(baseWallet.getId());
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdAsBytes(baseWallet.getId());
List<String> types = List.of(VerifiableCredentialType.VERIFIABLE_CREDENTIAL, MIWVerifiableCredentialType.BPN_CREDENTIAL);
VerifiableCredentialSubject verifiableCredentialSubject = new VerifiableCredentialSubject(Map.of(StringPool.TYPE, MIWVerifiableCredentialType.BPN_CREDENTIAL,
StringPool.ID, holderWallet.getDid(),
Expand Down Expand Up @@ -233,7 +226,7 @@ public CredentialsResponse issueFrameworkCredential(IssueFrameworkCredentialRequ

validateAccess(callerBPN, baseWallet);
// get Key
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdentifierAsBytes(baseWallet.getId());
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdAsBytes(baseWallet.getId());

//if base wallet issue credentials to itself
boolean isSelfIssued = isSelfIssued(holderWallet.getBpn());
Expand Down Expand Up @@ -293,7 +286,7 @@ public CredentialsResponse issueDismantlerCredential(IssueDismantlerCredentialRe
//check duplicate
isCredentialExit(holderWallet.getDid(), MIWVerifiableCredentialType.DISMANTLER_CREDENTIAL);

byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdentifierAsBytes(issuerWallet.getId());
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdAsBytes(issuerWallet.getId());

//if base wallet issue credentials to itself
boolean isSelfIssued = isSelfIssued(request.getBpn());
Expand Down Expand Up @@ -352,7 +345,7 @@ public CredentialsResponse issueMembershipCredential(IssueMembershipCredentialRe

validateAccess(callerBPN, issuerWallet);

byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdentifierAsBytes(issuerWallet.getId());
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdAsBytes(issuerWallet.getId());
List<String> types = List.of(VerifiableCredentialType.VERIFIABLE_CREDENTIAL, VerifiableCredentialType.MEMBERSHIP_CREDENTIAL);

//if base wallet issue credentials to itself
Expand Down Expand Up @@ -417,7 +410,7 @@ public CredentialsResponse issueCredentialUsingBaseWallet(String holderDid, Map<
validateAccess(callerBpn, issuerWallet);

// get issuer Key
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdentifierAsBytes(issuerWallet.getId());
byte[] privateKeyBytes = walletKeyService.getPrivateKeyByWalletIdAsBytes(issuerWallet.getId());

boolean isSelfIssued = isSelfIssued(holderWallet.getBpn());

Expand Down Expand Up @@ -449,31 +442,105 @@ public CredentialsResponse issueCredentialUsingBaseWallet(String holderDid, Map<

return cr;
}


private JWTVerificationResult verifyVCAsJWT(String jwt, DidResolver didResolver, boolean withCredentialsValidation, boolean withCredentialExpiryDate) throws IOException, ParseException {
SignedJWT signedJWT = SignedJWT.parse(jwt);
Map<String, Object> claims = objectMapper.readValue(signedJWT.getPayload().toBytes(), Map.class);
String vcClaim = objectMapper.writeValueAsString(claims.get("vc"));
Map<String, Object> map = SerializeUtil.fromJson(vcClaim);
VerifiableCredential verifiableCredential = new VerifiableCredential(map);

//took this approach to avoid issues in sonarQube
return new JWTVerificationResult(validateSignature(withCredentialsValidation , signedJWT, didResolver) && validateJWTExpiryDate(withCredentialExpiryDate, signedJWT), verifiableCredential);

}

private record JWTVerificationResult(boolean valid, VerifiableCredential verifiableCredential) {

}

private boolean validateSignature(boolean withValidateSignature, SignedJWT signedJWT, DidResolver didResolver) {
if(!withValidateSignature) {
return true;
}
//validate jwt signature
try {
SignedJwtVerifier jwtVerifier = new SignedJwtVerifier(didResolver);
return jwtVerifier.verify(signedJWT);
} catch (Exception e) {
log.error("Can not verify signature of jwt", e);
return false;
}
}
private boolean validateJWTExpiryDate(boolean withExpiryDate , SignedJWT signedJWT) {
if(!withExpiryDate) {
return true;
}
try {
SignedJwtValidator jwtValidator = new SignedJwtValidator();
jwtValidator.validateDate(signedJWT);
return true;
} catch (Exception e) {
if (!(e instanceof JwtExpiredException)) {
log.error("Can not validate jwt expiry date ", e);
}
return false;
}
}

/**
* Credentials validation map.
*
* @param verificationRequest the verifiable credential
* @param withCredentialExpiryDate the with credential expiry date
* @return the map
*/
public Map<String, Object> credentialsValidation(CredentialVerificationRequest verificationRequest, boolean withCredentialExpiryDate) {
return credentialsValidation(verificationRequest, true, withCredentialExpiryDate);
}

/**
* Credentials validation map.
*
* @param data the data
* @param withCredentialExpiryDate the with credential expiry date
* @return the map
*/
@SneakyThrows
public Map<String, Object> credentialsValidation(Map<String, Object> data, boolean withCredentialExpiryDate) {
VerifiableCredential verifiableCredential = new VerifiableCredential(data);
public Map<String, Object> credentialsValidation(CredentialVerificationRequest verificationRequest, boolean withCredentialsValidation , boolean withCredentialExpiryDate) {
HttpClient httpClient = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();

DidResolver didResolver = new DidWebResolver(HttpClient.newHttpClient(), new DidWebParser(), miwSettings.enforceHttps());
DidResolver didResolver = new DidWebResolver(httpClient, new DidWebParser(), miwSettings.enforceHttps());
Map<String, Object> response = new TreeMap<>();
boolean valid;
VerifiableCredential verifiableCredential;
boolean dateValidation = true;

if (verificationRequest.containsKey(StringPool.VC_JWT_KEY)) {
JWTVerificationResult result = verifyVCAsJWT((String) verificationRequest.get(StringPool.VC_JWT_KEY), didResolver, withCredentialsValidation, withCredentialExpiryDate);
verifiableCredential = result.verifiableCredential;
valid = result.valid;
} else {

LinkedDataProofValidation proofValidation = LinkedDataProofValidation.newInstance(didResolver);
verifiableCredential = new VerifiableCredential(verificationRequest);
LinkedDataProofValidation proofValidation = LinkedDataProofValidation.newInstance(didResolver);

boolean valid = proofValidation.verify(verifiableCredential);

Map<String, Object> response = new TreeMap<>();
if (withCredentialsValidation) {
valid = proofValidation.verify(verifiableCredential);
} else {
valid = true;
}

//check expiry
boolean dateValidation = CommonService.validateExpiry(withCredentialExpiryDate, verifiableCredential, response);
dateValidation = CommonService.validateExpiry(withCredentialExpiryDate, verifiableCredential,
response);
}

response.put(StringPool.VALID, valid && dateValidation);
response.put("vc", verifiableCredential);
response.put(StringPool.VC, verificationRequest);

return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ protected SpecificationUtil<WalletKey> getSpecificationUtil() {
* @return the byte [ ]
*/
@SneakyThrows
public byte[] getPrivateKeyByWalletIdentifierAsBytes(long walletId) {
public byte[] getPrivateKeyByWalletIdAsBytes(long walletId) {
return getPrivateKeyByWalletId(walletId).asByte();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -171,7 +172,7 @@ public static String vcAsJwt(Wallet issuerWallet, Wallet holderWallet, Verifiabl
x25519PrivateKey privateKey = walletKeyService.getPrivateKeyByWalletId(issuerWallet.getId());
// JWT Factory

SignedJWT vcJWT = vcFactory.createVCJwt(issuerDid, holderDid, Date.from(vc.getExpirationDate()), vc,
SignedJWT vcJWT = vcFactory.createVCJwt(issuerDid, holderDid, vc,
privateKey,
walletKeyService.getWalletKeyIdByWalletId(issuerWallet.getId()));

Expand Down
Loading

0 comments on commit b1d7b2c

Please sign in to comment.