Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/did document fields + add service entry for token endpoint #298

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ dependencies {
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:${openApiVersion}"
implementation group: 'com.smartsensesolutions', name: 'commons-dao', version: '0.0.5'
implementation 'org.liquibase:liquibase-core'
implementation 'org.eclipse.tractusx.ssi:cx-ssi-lib:0.0.18'
implementation 'org.eclipse.tractusx.ssi:cx-ssi-lib:0.0.19'

//Added explicitly to mitigate CVE 2022-1471
implementation group: 'org.yaml', name: 'snakeyaml', version: '2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.eclipse.tractusx.managedidentitywallets.exception.*;
import org.eclipse.tractusx.ssi.lib.exception.NoVerificationKeyFoundExcpetion;
import org.eclipse.tractusx.ssi.lib.exception.proof.NoVerificationKeyFoundException;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
Expand Down Expand Up @@ -205,8 +205,8 @@ ProblemDetail handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismat
* @param exception the exception
* @return the problem detail
*/
@ExceptionHandler(NoVerificationKeyFoundExcpetion.class)
ProblemDetail handleNoVerificationKeyFoundException(NoVerificationKeyFoundExcpetion exception) {
@ExceptionHandler({ NoVerificationKeyFoundException.class} )
ProblemDetail handleNoVerificationKeyFoundException(NoVerificationKeyFoundException exception) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, ExceptionUtils.getMessage(exception));
problemDetail.setTitle(ExceptionUtils.getMessage(exception));
problemDetail.setProperty(TIMESTAMP, System.currentTimeMillis());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@

package org.eclipse.tractusx.managedidentitywallets.constant;

import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialType;

/**
* The type Miw verifiable credential type.
*/
public class MIWVerifiableCredentialType extends VerifiableCredentialType {
public class MIWVerifiableCredentialType {

/** The constant MEMBERSHIP_CREDENTIAL. */
public static final String MEMBERSHIP_CREDENTIAL = "MembershipCredential";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have constant in SSI lib VerifiableCredentialType.MEMBERSHIP_CREDENTIAL


public static final String DISMANTLER_CREDENTIAL = "DismantlerCredential";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,7 @@ private StringPool() {

public static final String PRIVATE_KEY = "PRIVATE KEY";
public static final String PUBLIC_KEY = "PUBLIC KEY";
public static final String VERIFICATION_METHOD_TYPE = "JsonWebKey2020";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have a constant in SSI lib for JsonWebKey2020 : JWKVerificationMethod.DEFAULT_TYPE

public static final String ASSERTION_METHOD = "assertionMethod";
public static final String HTTPS_SCHEME = "https://";
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,12 @@ public interface WalletKeyRepository extends BaseRepository<WalletKey, Long> {
WalletKey findFirstByWallet_Bpn(String bpn);

WalletKey findFirstByWallet_Did(String did);

/**
* Gets by wallet id.
* @param id the id
* @return WalletKey
*/
WalletKey getByWalletId(Long id);

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.StringEscapeUtils;
import org.eclipse.tractusx.managedidentitywallets.constant.StringPool;
import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet;
import org.eclipse.tractusx.managedidentitywallets.dao.repository.WalletRepository;
import org.eclipse.tractusx.managedidentitywallets.exception.WalletNotFoundProblem;
import org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils;
import org.eclipse.tractusx.managedidentitywallets.utils.Validate;
import org.eclipse.tractusx.ssi.lib.exception.DidParseException;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
import org.springframework.stereotype.Service;

Expand All @@ -55,12 +53,7 @@ public Wallet getWalletByIdentifier(String identifier) {
if (CommonUtils.getIdentifierType(identifier).equals(StringPool.BPN)) {
wallet = walletRepository.getByBpn(identifier);
} else {
try {
wallet = walletRepository.getByDid(identifier);
} catch (DidParseException e) {
log.error("Error while parsing did {}", StringEscapeUtils.escapeJava(identifier), e);
throw new WalletNotFoundProblem("Error while parsing did " + identifier);
}
wallet = walletRepository.getByDid(identifier);
}
Validate.isNull(wallet).launch(new WalletNotFoundProblem("Wallet not found for identifier " + identifier));
return wallet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
import lombok.Getter;
import org.eclipse.tractusx.managedidentitywallets.config.MIWSettings;
import org.eclipse.tractusx.ssi.lib.did.resolver.CompositeDidResolver;
import org.eclipse.tractusx.ssi.lib.did.resolver.DidDocumentResolverRegistry;
import org.eclipse.tractusx.ssi.lib.did.resolver.DidDocumentResolverRegistryImpl;
import org.eclipse.tractusx.ssi.lib.did.web.DidWebDocumentResolver;
import org.eclipse.tractusx.ssi.lib.did.web.DidWebResolver;
import org.eclipse.tractusx.ssi.lib.did.web.util.DidWebParser;
import org.springframework.stereotype.Service;
Expand All @@ -39,7 +36,7 @@ public class DidDocumentResolverService {
final static HttpClient httpClient = HttpClient.newHttpClient();

@Getter
private final DidDocumentResolverRegistry didDocumentResolverRegistry;
private final DidWebResolver didDocumentResolverRegistry;

@Getter
private final CompositeDidResolver compositeDidResolver;
Expand All @@ -49,9 +46,8 @@ public DidDocumentResolverService(MIWSettings miwSettings) {
final boolean enforceHttps = miwSettings.enforceHttps();
final DidWebParser didParser = new DidWebParser();

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

compositeDidResolver = new CompositeDidResolver(
new DidWebResolver(httpClient, didParser, enforceHttps)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.eclipse.tractusx.managedidentitywallets.config.MIWSettings;
import org.eclipse.tractusx.managedidentitywallets.constant.SupportedAlgorithms;
import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet;
Expand All @@ -50,15 +49,14 @@
import org.eclipse.tractusx.managedidentitywallets.utils.EncryptionUtils;
import org.eclipse.tractusx.ssi.lib.model.did.Did;
import org.eclipse.tractusx.ssi.lib.model.did.DidDocument;
import org.eclipse.tractusx.ssi.lib.model.did.DidDocumentBuilder;
import org.eclipse.tractusx.ssi.lib.model.did.DidMethod;
import org.eclipse.tractusx.ssi.lib.model.did.DidMethodIdentifier;
import org.eclipse.tractusx.ssi.lib.model.did.JWKVerificationMethod;
import org.eclipse.tractusx.ssi.lib.model.did.VerificationMethod;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentation;
import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentationBuilder;
import org.eclipse.tractusx.ssi.lib.serialization.jsonLd.JsonLdSerializer;
import org.eclipse.tractusx.ssi.lib.serialization.jsonld.JsonLdSerializer;
import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedVerifiablePresentation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand All @@ -77,19 +75,17 @@
import java.util.UUID;
import java.util.stream.Collectors;

import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.ASSERTION_METHOD;
import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.COLON_SEPARATOR;
import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.PRIVATE_KEY;
import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.PUBLIC_KEY;
import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.REFERENCE_KEY;
import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.VAULT_ACCESS_TOKEN;
import static org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils.getJwkVerificationMethod;
import static org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils.getKeyString;
import static org.eclipse.tractusx.ssi.lib.model.did.JWKVerificationMethod.JWK_CURVE;
import static org.eclipse.tractusx.ssi.lib.model.did.JWKVerificationMethod.JWK_KEK_TYPE;
import static org.eclipse.tractusx.ssi.lib.model.did.JWKVerificationMethod.JWK_X;
import static org.eclipse.tractusx.ssi.lib.model.did.JWKVerificationMethod.PUBLIC_KEY_JWK;
import static org.eclipse.tractusx.ssi.lib.model.did.VerificationMethod.CONTROLLER;
import static org.eclipse.tractusx.ssi.lib.model.did.VerificationMethod.ID;
import static org.eclipse.tractusx.ssi.lib.model.did.VerificationMethod.TYPE;


@Service
Expand All @@ -103,14 +99,12 @@ public class JwtPresentationES256KService {
private WalletRepository walletRepository;
private EncryptionUtils encryptionUtils;
private WalletKeyService walletKeyService;
private MIWSettings miwSettings;

@Autowired
public JwtPresentationES256KService(WalletRepository walletRepository, EncryptionUtils encryptionUtils, WalletKeyService walletKeyService, MIWSettings miwSettings) {
this.walletRepository = walletRepository;
this.encryptionUtils = encryptionUtils;
this.walletKeyService = walletKeyService;
this.miwSettings = miwSettings;
}

public JwtPresentationES256KService(Did agentDid, JsonLdSerializer jsonLdSerializer) {
Expand Down Expand Up @@ -142,11 +136,12 @@ public Wallet storeWalletKeyES256K(Wallet wallet, String keyId) {

Did did = getDidFromDidString(wallet.getDid());

JWKVerificationMethod jwkVerificationMethod = getJwkVerificationMethod(ecKey, did);
Map<String, String> publicKeyJwk = Map.of(JWK_KEK_TYPE, ecKey.getKeyType().toString(), JWK_CURVE,
ecKey.getCurve().getName(), JWK_X, ecKey.getX().toString(), JWK_Y, ecKey.getY().toString());
JWKVerificationMethod jwkVerificationMethod = getJwkVerificationMethod(publicKeyJwk, did, keyId);

DidDocument didDocument = wallet.getDidDocument();
List<VerificationMethod> verificationMethods = didDocument.getVerificationMethods();
verificationMethods.add(jwkVerificationMethod);
DidDocument updatedDidDocument = buildDidDocument(wallet.getBpn(), did, verificationMethods);
DidDocument updatedDidDocument = updateDidDocument(didDocument, jwkVerificationMethod);

wallet = walletRepository.getByDid(wallet.getDid());
wallet.setDidDocument(updatedDidDocument);
Expand Down Expand Up @@ -177,33 +172,17 @@ private Did getDidFromDidString(String didString) {
return new Did(didMethod, methodIdentifier, null);
}

private JWKVerificationMethod getJwkVerificationMethod(ECKey ecKey, Did did) {
Map<String, Object> verificationMethodJson = new HashMap<>();
Map<String, String> publicKeyJwk = Map.of(JWK_KEK_TYPE, ecKey.getKeyType().toString(), JWK_CURVE,
ecKey.getCurve().getName(), JWK_X, ecKey.getX().toString(), JWK_Y, ecKey.getY().toString());
verificationMethodJson.put(ID, URI.create(did + "#" + ecKey.getKeyID()));
verificationMethodJson.put(TYPE, JWKVerificationMethod.DEFAULT_TYPE);
verificationMethodJson.put(CONTROLLER, did.toUri());
verificationMethodJson.put(PUBLIC_KEY_JWK, publicKeyJwk);
return new JWKVerificationMethod(verificationMethodJson);
}
public DidDocument updateDidDocument(DidDocument didDocument, VerificationMethod jwkVerificationMethod) {
List<URI> assertionMethod = (List<URI>)didDocument.get(ASSERTION_METHOD);
List<URI> updatedAssertionMethod = new ArrayList<>(assertionMethod);
updatedAssertionMethod.add(jwkVerificationMethod.getId());
didDocument.put(ASSERTION_METHOD, updatedAssertionMethod);

List<VerificationMethod> methods = didDocument.getVerificationMethods();
List<VerificationMethod> updatedMethods = new ArrayList<>(methods);
updatedMethods.add(jwkVerificationMethod);
didDocument.put("verificationMethod", updatedMethods);

public DidDocument buildDidDocument(String bpn, Did did, List<VerificationMethod> jwkVerificationMethods) {
DidDocumentBuilder didDocumentBuilder = new DidDocumentBuilder();
didDocumentBuilder.id(did.toUri());
didDocumentBuilder.verificationMethods(jwkVerificationMethods);
DidDocument didDocument = didDocumentBuilder.build();
//modify context URLs
List<URI> context = didDocument.getContext();
List<URI> mutableContext = new ArrayList<>(context);
miwSettings.didDocumentContextUrls().forEach(uri -> {
if (!mutableContext.contains(uri)) {
mutableContext.add(uri);
}
});
didDocument.put("@context", mutableContext);
didDocument = DidDocument.fromJson(didDocument.toJson());
log.debug("did document created for bpn ->{}", StringEscapeUtils.escapeJava(bpn));
return didDocument;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@
import org.eclipse.tractusx.managedidentitywallets.exception.PermissionViolationException;
import org.eclipse.tractusx.managedidentitywallets.utils.Validate;
import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory;
import org.eclipse.tractusx.ssi.lib.crypt.x21559.x21559PrivateKey;
import org.eclipse.tractusx.ssi.lib.crypt.x25519.X25519PrivateKey;
import org.eclipse.tractusx.ssi.lib.did.resolver.DidResolver;
import org.eclipse.tractusx.ssi.lib.exception.InvalidJsonLdException;
import org.eclipse.tractusx.ssi.lib.exception.InvalidePrivateKeyFormat;
import org.eclipse.tractusx.ssi.lib.exception.JwtExpiredException;
import org.eclipse.tractusx.ssi.lib.exception.did.DidParseException;
import org.eclipse.tractusx.ssi.lib.exception.json.InvalidJsonLdException;
import org.eclipse.tractusx.ssi.lib.exception.key.InvalidPrivateKeyFormatException;
import org.eclipse.tractusx.ssi.lib.exception.proof.JwtExpiredException;
import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtFactory;
import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtValidator;
import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtVerifier;
Expand All @@ -59,7 +60,7 @@
import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentationBuilder;
import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentationType;
import org.eclipse.tractusx.ssi.lib.proof.LinkedDataProofValidation;
import org.eclipse.tractusx.ssi.lib.serialization.jsonLd.JsonLdSerializerImpl;
import org.eclipse.tractusx.ssi.lib.serialization.jsonld.JsonLdSerializerImpl;
import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedJwtPresentationFactory;
import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedJwtPresentationFactoryImpl;
import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedVerifiablePresentation;
Expand Down Expand Up @@ -141,7 +142,7 @@ public Map<String, Object> createPresentation(Map<String, Object> data, boolean
return buildVP(asJwt, audience, callerBpn, callerWallet, verifiableCredentials, SupportedAlgorithms.ED25519);
}

@SneakyThrows({ InvalidePrivateKeyFormat.class })
@SneakyThrows({ InvalidPrivateKeyFormatException.class })
private Map<String, Object> buildVP(boolean asJwt, String audience, String callerBpn, Wallet callerWallet,
List<VerifiableCredential> verifiableCredentials, SupportedAlgorithms algorithm) {
Map<String, Object> response = new HashMap<>();
Expand Down Expand Up @@ -169,15 +170,16 @@ private void buildVPJsonLd(String callerBpn, List<VerifiableCredential> verifiab
response.put(StringPool.VP, verifiablePresentation);
}

private void buildVPJwtEdDSA(String audience, String callerBpn, Wallet callerWallet, List<VerifiableCredential> verifiableCredentials, SupportedAlgorithms algorithm, Map<String, Object> response) throws InvalidePrivateKeyFormat {
private void buildVPJwtEdDSA(String audience, String callerBpn, Wallet callerWallet, List<VerifiableCredential> verifiableCredentials, SupportedAlgorithms algorithm, Map<String, Object> response) throws InvalidPrivateKeyFormatException {
Pair<Did, Object> result = getPrivateKey(callerWallet, algorithm, audience, callerBpn);
String keyId = walletKeyService.getWalletKeyIdByWalletId(callerWallet.getId());

SerializedJwtPresentationFactory presentationFactory = new SerializedJwtPresentationFactoryImpl(
new SignedJwtFactory(new OctetKeyPairFactory()), new JsonLdSerializerImpl(), result.getKey());

x21559PrivateKey ed25519Key = (x21559PrivateKey) result.getRight();
x21559PrivateKey privateKey = new x21559PrivateKey(ed25519Key.asByte());
SignedJWT presentation = presentationFactory.createPresentation(result.getLeft(), verifiableCredentials, audience, privateKey);
X25519PrivateKey ed25519Key = (X25519PrivateKey) result.getRight();
X25519PrivateKey privateKey = new X25519PrivateKey(ed25519Key.asByte());
SignedJWT presentation = presentationFactory.createPresentation(result.getLeft(), verifiableCredentials, audience, privateKey, keyId);

response.put(StringPool.VP, presentation.serialize());
}
Expand All @@ -192,6 +194,7 @@ private void buildVPJwtES256K(String audience, String callerBpn, Wallet callerWa
response.put(StringPool.VP, presentation.serialize());
}

@SneakyThrows({ DidParseException.class})
private Pair<Did, Object> getPrivateKey(Wallet callerWallet, SupportedAlgorithms algorithm, String audience, String callerBpn) {
log.debug("Creating VP as JWT for bpn ->{}", callerBpn);
Validate.isFalse(StringUtils.hasText(audience)).launch(new BadDataException("Audience needed to create VP as JWT"));
Expand Down
Loading
Loading