Skip to content

Commit

Permalink
Merge pull request #291 from Cofinity-X/pr-upstream-keystorage
Browse files Browse the repository at this point in the history
feat: abstract key storage and signing operations
  • Loading branch information
borisrizov-zf authored Jun 3, 2024
2 parents 688daa8 + af87ecb commit ba2f0e8
Show file tree
Hide file tree
Showing 54 changed files with 2,105 additions and 448 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# [0.5.0-develop.17](https://github.com/eclipse-tractusx/managed-identity-wallet/compare/v0.5.0-develop.16...v0.5.0-develop.17) (2024-05-29)



### Bug Fixes

* api doc folder structure ([ebd691a](https://github.com/eclipse-tractusx/managed-identity-wallet/commit/ebd691a8a5c05f26a6aa10b778d4c8be6189a4af))
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ This process ensures that any issues with the database schema are resolved by re
| ENFORCE_HTTPS_IN_DID_RESOLUTION | Enforce https during web did resolution | true |
| CONTRACT_TEMPLATES_URL | Contract templates URL used in summary VC | https://public.catena-x.org/contracts/ |
| APP_LOG_LEVEL | Log level of application | INFO |
| AUTHORITY_SIGNING_SERVICE_TYPE | Base wallet signing type, Currency only LOCAL is supported | Local |
| LOCAL_SIGNING_KEY_STORAGE_TYPE | Key storage type, currently only DB is supported | DB |
| | | |

# Technical Debts and Known issue
Expand Down
2 changes: 2 additions & 0 deletions dev-assets/env-files/env.docker.dist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ ENCRYPTION_KEY=
AUTHORITY_WALLET_BPN=BPNL000000000000
AUTHORITY_WALLET_DID=did:web:localhost:BPNL000000000000
AUTHORITY_WALLET_NAME=Catena-X
AUTHORITY_SIGNING_SERVICE_TYPE=LOCAL
LOCAL_SIGNING_KEY_STORAGE_TYPE=DB
KEYCLOAK_REALM=miw_test
VC_SCHEMA_LINK="https://www.w3.org/2018/credentials/v1, https://catenax-ng.github.io/product-core-schemas/businessPartnerData.json"
VC_EXPIRY_DATE=01-01-2025
Expand Down
2 changes: 2 additions & 0 deletions dev-assets/env-files/env.local.dist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ ENCRYPTION_KEY=
AUTHORITY_WALLET_BPN=BPNL000000000000
AUTHORITY_WALLET_DID=did:web:localhost:BPNL000000000000
AUTHORITY_WALLET_NAME=Catena-X
AUTHORITY_SIGNING_SERVICE_TYPE=LOCAL
LOCAL_SIGNING_KEY_STORAGE_TYPE=DB
KEYCLOAK_REALM=miw_test
VC_SCHEMA_LINK="https://www.w3.org/2018/credentials/v1, https://catenax-ng.github.io/product-core-schemas/businessPartnerData.json"
VC_EXPIRY_DATE=01-01-2025
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand Down Expand Up @@ -28,6 +28,10 @@
import com.smartsensesolutions.java.commons.specification.SpecificationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.StringEscapeUtils;
import org.eclipse.tractusx.managedidentitywallets.domain.SigningServiceType;
import org.eclipse.tractusx.managedidentitywallets.signing.KeyProvider;
import org.eclipse.tractusx.managedidentitywallets.signing.LocalSigningService;
import org.eclipse.tractusx.managedidentitywallets.signing.SigningService;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -40,6 +44,9 @@
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

/**
* The type Application config.
Expand All @@ -50,11 +57,13 @@ public class ApplicationConfig implements WebMvcConfigurer {

private final SwaggerUiConfigProperties properties;
private final String resourceBundlePath;
private final MIWSettings miwSettings;

@Autowired
public ApplicationConfig(@Value("${resource.bundle.path:classpath:i18n/language}") String resourceBundlePath, SwaggerUiConfigProperties properties) {
public ApplicationConfig(@Value("${resource.bundle.path:classpath:i18n/language}") String resourceBundlePath, SwaggerUiConfigProperties properties, MIWSettings miwSettings) {
this.resourceBundlePath = resourceBundlePath;
this.properties = properties;
this.miwSettings = miwSettings;
}

/**
Expand Down Expand Up @@ -98,4 +107,23 @@ public LocalValidatorFactoryBean validator() {
beanValidatorFactory.setValidationMessageSource(messageSource());
return beanValidatorFactory;
}

@Bean
public Map<SigningServiceType, SigningService> availableKeyStorages(List<SigningService> storages, List<KeyProvider> keyProviders) {
KeyProvider localSigningKeyProvider = keyProviders.stream().filter(s -> s.getKeyStorageType().equals(miwSettings.localSigningKeyStorageType()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("no key provider with type %s found".formatted(miwSettings.localSigningKeyStorageType())));

Map<SigningServiceType, SigningService> available = new EnumMap<>(SigningServiceType.class);
storages.forEach(
s -> {
if(s instanceof LocalSigningService local){
local.setKeyProvider(localSigningKeyProvider);
}
available.put(s.getSupportedServiceType(), s);
}
);

return available;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -21,6 +21,8 @@

package org.eclipse.tractusx.managedidentitywallets.config;

import org.eclipse.tractusx.managedidentitywallets.domain.KeyStorageType;
import org.eclipse.tractusx.managedidentitywallets.domain.SigningServiceType;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.format.annotation.DateTimeFormat;

Expand All @@ -39,5 +41,8 @@ public record MIWSettings(String host, String encryptionKey, String authorityWal
@DateTimeFormat(pattern = "dd-MM-yyyy") Date vcExpiryDate,
Set<String> supportedFrameworkVCTypes,
boolean enforceHttps, String contractTemplatesUrl,
List<URI> didDocumentContextUrls) {
List<URI> didDocumentContextUrls,
KeyStorageType localSigningKeyStorageType,
SigningServiceType authoritySigningServiceType) {
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@

package org.eclipse.tractusx.managedidentitywallets.constant;

import lombok.experimental.UtilityClass;

/**
* The type Miw verifiable credential type.
*/
@UtilityClass
public class MIWVerifiableCredentialType {

public static final String VERIFIABLE_CREDENTIAL = "VerifiableCredential";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ private StringPool() {

public static final String BPN_NUMBER_REGEX = "^(BPN)(L|S|A)[0-9A-Z]{12}";

public static final String W3_ID_JWS_2020_V1_CONTEXT_URL = "https://w3id.org/security/suites/jws-2020/v1";

public static final String COMA_SEPARATOR = ", ";
public static final String BLANK_SEPARATOR = " ";
public static final String COLON_SEPARATOR = ":";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,21 @@
import org.apache.commons.lang3.StringUtils;
import org.eclipse.tractusx.managedidentitywallets.apidocs.SecureTokenControllerApiDoc;
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.domain.BusinessPartnerNumber;
import org.eclipse.tractusx.managedidentitywallets.domain.DID;
import org.eclipse.tractusx.managedidentitywallets.domain.IdpTokenResponse;
import org.eclipse.tractusx.managedidentitywallets.domain.SigningServiceType;
import org.eclipse.tractusx.managedidentitywallets.domain.StsTokenErrorResponse;
import org.eclipse.tractusx.managedidentitywallets.domain.StsTokenResponse;
import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequest;
import org.eclipse.tractusx.managedidentitywallets.exception.InvalidIdpTokenResponseException;
import org.eclipse.tractusx.managedidentitywallets.exception.InvalidSecureTokenRequestException;
import org.eclipse.tractusx.managedidentitywallets.exception.UnknownBusinessPartnerNumberException;
import org.eclipse.tractusx.managedidentitywallets.exception.UnsupportedGrantTypeException;
import org.eclipse.tractusx.managedidentitywallets.interfaces.SecureTokenService;
import org.eclipse.tractusx.managedidentitywallets.service.IdpAuthorization;
import org.eclipse.tractusx.managedidentitywallets.signing.SigningService;
import org.eclipse.tractusx.managedidentitywallets.validator.SecureTokenRequestValidator;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
Expand All @@ -57,6 +59,7 @@
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

Expand All @@ -69,17 +72,19 @@
@Tag(name = "STS")
public class SecureTokenController {

private final SecureTokenService tokenService;

private final IdpAuthorization idpAuthorization;

private final WalletRepository walletRepo;

private final Map<SigningServiceType, SigningService> availableSigningServices;

@InitBinder
void initBinder(WebDataBinder webDataBinder) {
webDataBinder.addValidators(new SecureTokenRequestValidator());
}


@SneakyThrows
@PostMapping(path = "/api/token", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
@SecureTokenControllerApiDoc.PostSecureTokenDocJson
Expand All @@ -103,7 +108,8 @@ private ResponseEntity<StsTokenResponse> processTokenRequest(SecureTokenRequest
// handle idp authorization
IdpTokenResponse idpResponse = idpAuthorization.fromSecureTokenRequest(secureTokenRequest);
BusinessPartnerNumber bpn = idpResponse.bpn();
DID selfDid = new DID(walletRepo.getByBpn(bpn.toString()).getDid());
Wallet selfWallet = walletRepo.getByBpn(bpn.toString());
DID selfDid = new DID(selfWallet.getDid());
DID partnerDid;
if (Pattern.compile(StringPool.BPN_NUMBER_REGEX).matcher(secureTokenRequest.getAudience()).matches()) {
partnerDid = new DID(walletRepo.getByBpn(secureTokenRequest.getAudience()).getDid());
Expand All @@ -113,18 +119,21 @@ private ResponseEntity<StsTokenResponse> processTokenRequest(SecureTokenRequest
throw new InvalidSecureTokenRequestException("You must provide an audience either as a BPN or DID.");
}

SigningServiceType signingServiceType = selfWallet.getSigningServiceType();
SigningService signingService = availableSigningServices.get(signingServiceType);

// create the SI token and put/create the access_token inside
JWT responseJwt;
if (secureTokenRequest.assertValidWithAccessToken()) {
log.debug("Signing si token.");
responseJwt = tokenService.issueToken(
responseJwt = signingService.issueToken(
selfDid,
partnerDid,
JWTParser.parse(secureTokenRequest.getAccessToken())
);
} else if (secureTokenRequest.assertValidWithScopes()) {
log.debug("Creating access token and signing si token.");
responseJwt = tokenService.issueToken(
responseJwt = signingService.issueToken(
selfDid,
partnerDid,
Set.of(secureTokenRequest.getBearerAccessScope())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -27,6 +27,8 @@
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
Expand All @@ -37,6 +39,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.eclipse.tractusx.managedidentitywallets.domain.SigningServiceType;
import org.eclipse.tractusx.managedidentitywallets.utils.StringToDidDocumentConverter;
import org.eclipse.tractusx.ssi.lib.model.did.DidDocument;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
Expand Down Expand Up @@ -72,6 +75,10 @@ public class Wallet extends MIWBaseEntity {
@Column(nullable = false)
private String algorithm;

@Enumerated(EnumType.STRING)
@Column(name = "signing_service_type", nullable = false)
private SigningServiceType signingServiceType;

@Column(nullable = false)
@Convert(converter = StringToDidDocumentConverter.class)
private DidDocument didDocument;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand Down Expand Up @@ -30,7 +30,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -47,13 +47,14 @@
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table(name="wallet_key")
public class WalletKey extends MIWBaseEntity {

@Id
@JsonIgnore
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", columnDefinition = "serial", nullable = false, unique = true)
private Long id;
private long id;

@Column(nullable = false)
private String vaultAccessToken;
Expand All @@ -68,8 +69,7 @@ public class WalletKey extends MIWBaseEntity {
private String publicKey;

@ManyToOne
@MapsId
@JoinColumn(name = "walletId", columnDefinition = "bigint")
@JoinColumn(name = "wallet_id", columnDefinition = "bigint")
@JsonBackReference
private Wallet wallet;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,43 @@ public interface WalletKeyRepository extends BaseRepository<WalletKey, Long> {
/**
* Gets by wallet id and algorithm.
*
* @param id the id
* param algorithm the algorithm
* @param id the wallet id
* @param algorithm the algorithm
* @return the by wallet id
*/
WalletKey getByWalletIdAndAlgorithm(Long id, String algorithm);

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

WalletKey findFirstByWallet_Bpn(String bpn);

/**
* Find first by wallet did wallet key.
*
* @param did the did
* @return the wallet key
*/
WalletKey findFirstByWallet_Did(String did);

/**
* Gets by key id and algorithm.
*
* @param keyId the key id
* @param algorithm the algorithm
* @return the by key id and algorithm
*/
WalletKey getByKeyIdAndAlgorithm(String keyId, String algorithm);

/**
* Gets by algorithm and wallet bpn.
*
* @param name the name
* @param keyName the key name
* @return the by algorithm and wallet bpn
*/
WalletKey getByAlgorithmAndWallet_Bpn(String name, String keyName);
}
Loading

0 comments on commit ba2f0e8

Please sign in to comment.