Skip to content

Commit

Permalink
fix: applies STS remote refactor of upstream EDC (#1501)
Browse files Browse the repository at this point in the history
* fix: applies STS remote refactor of upstream EDC

* fix tests

* fix tests

* chore: dependencies file
  • Loading branch information
wolf4ood authored Aug 16, 2024
1 parent ebe513d commit f0139f5
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 245 deletions.
426 changes: 213 additions & 213 deletions DEPENDENCIES

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions edc-extensions/bdrs-client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ dependencies {
testImplementation(libs.awaitility)
testImplementation(libs.edc.identity.trust.sts.embedded)
testImplementation(libs.edc.core.token)
testImplementation(libs.edc.lib.cryptocommon)
testImplementation(libs.testcontainers.junit)
testImplementation(testFixtures(libs.edc.identity.vc.jwt)) // JwtCreationUtils
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiablePresentation;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiablePresentationContainer;
import org.eclipse.edc.junit.annotations.ComponentTest;
import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.security.token.jwt.DefaultJwsSignerProvider;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.result.Result;
Expand Down Expand Up @@ -120,6 +122,7 @@ class BdrsClientImplComponentTest {
private final Monitor monitor = mock();
private final ObjectMapper mapper = new ObjectMapper();
private final CredentialServiceClient csMock = mock();
private final PrivateKeyResolver privateKeyResolver = mock();

private BdrsClientImpl client;
private ECKey vpHolderKey;
Expand All @@ -128,11 +131,12 @@ class BdrsClientImplComponentTest {
@BeforeEach
void setup() throws JOSEException, IOException, ParseException {

var privateKeyAlias = "privateKeyAlias";
vcIssuerKey = ECKey.parse(Files.readString(Path.of(SHARED_TEMP_DIR, ISSUER_NAME + "/key.json")));
vpHolderKey = ECKey.parse(Files.readString(Path.of(SHARED_TEMP_DIR, HOLDER_NAME + "/key.json")));

var pk = vpHolderKey.toPrivateKey();
var sts = new EmbeddedSecureTokenService(new JwtGenerationService(), () -> pk, () -> vpHolderKey.getKeyID(), Clock.systemUTC(), 10);
var sts = new EmbeddedSecureTokenService(new JwtGenerationService(new DefaultJwsSignerProvider(privateKeyResolver)), () -> privateKeyAlias, () -> vpHolderKey.getKeyID(), Clock.systemUTC(), 10);

var directoryPort = BDRS_SERVER_CONTAINER.getMappedPort(8082);
client = new BdrsClientImpl("http://%s:%d/api/directory".formatted(BDRS_SERVER_CONTAINER.getHost(), directoryPort), 1,
Expand All @@ -144,6 +148,7 @@ void setup() throws JOSEException, IOException, ParseException {
sts,
csMock);

when(privateKeyResolver.resolvePrivateKey(privateKeyAlias)).thenReturn(Result.success(pk));
// need to wait until healthy, otherwise BDRS will respond with a 404
await().atMost(Duration.ofSeconds(20)).untilAsserted(() -> {
assertThat(BDRS_SERVER_CONTAINER.isHealthy()).isTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.edc.connector.dataplane.spi.iam.DataPlaneAccessTokenService;
import org.eclipse.edc.connector.dataplane.spi.store.AccessTokenDataStore;
import org.eclipse.edc.iam.did.spi.resolution.DidPublicKeyResolver;
import org.eclipse.edc.jwt.signer.spi.JwsSignerProvider;
import org.eclipse.edc.keys.spi.LocalPublicKeyService;
import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
Expand Down Expand Up @@ -95,6 +96,9 @@ public class DataPlaneTokenRefreshServiceExtension implements ServiceExtension {
@Inject
private Hostname hostname;

@Inject
private JwsSignerProvider jwsSignerProvider;

private DataPlaneTokenRefreshServiceImpl tokenRefreshService;

@Override
Expand Down Expand Up @@ -127,8 +131,8 @@ private DataPlaneTokenRefreshServiceImpl getTokenRefreshService(ServiceExtension
var tokenExpiry = getExpiryConfig(context);
monitor.debug("Token refresh endpoint: %s".formatted(refreshEndpoint));
monitor.debug("Token refresh time tolerance: %d s".formatted(expiryTolerance));
tokenRefreshService = new DataPlaneTokenRefreshServiceImpl(clock, tokenValidationService, didPkResolver, localPublicKeyService, accessTokenDataStore, new JwtGenerationService(),
getPrivateKeySupplier(context), context.getMonitor(), refreshEndpoint, getOwnDid(context), expiryTolerance, tokenExpiry,
tokenRefreshService = new DataPlaneTokenRefreshServiceImpl(clock, tokenValidationService, didPkResolver, localPublicKeyService, accessTokenDataStore, new JwtGenerationService(jwsSignerProvider),
() -> context.getConfig().getString(TOKEN_SIGNER_PRIVATE_KEY_ALIAS), context.getMonitor(), refreshEndpoint, getOwnDid(context), expiryTolerance, tokenExpiry,
() -> context.getConfig().getString(TOKEN_VERIFIER_PUBLIC_KEY_ALIAS), vault, typeManager.getMapper());
}
return tokenRefreshService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.model.TokenResponse;

import java.security.PrivateKey;
import java.time.Clock;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -84,7 +83,7 @@ public class DataPlaneTokenRefreshServiceImpl implements DataPlaneTokenRefreshSe
private final LocalPublicKeyService localPublicKeyService;
private final AccessTokenDataStore accessTokenDataStore;
private final TokenGenerationService tokenGenerationService;
private final Supplier<PrivateKey> privateKeySupplier;
private final Supplier<String> privateKeyIdSupplier;
private final Supplier<String> publicKeyIdSupplier;
private final Monitor monitor;
private final String refreshEndpoint;
Expand All @@ -100,7 +99,7 @@ public DataPlaneTokenRefreshServiceImpl(Clock clock,
LocalPublicKeyService localPublicKeyService,
AccessTokenDataStore accessTokenDataStore,
TokenGenerationService tokenGenerationService,
Supplier<PrivateKey> privateKeySupplier,
Supplier<String> privateKeyIdSupplier,
Monitor monitor,
String refreshEndpoint,
String ownDid,
Expand All @@ -114,7 +113,7 @@ public DataPlaneTokenRefreshServiceImpl(Clock clock,
this.localPublicKeyService = localPublicKeyService;
this.accessTokenDataStore = accessTokenDataStore;
this.tokenGenerationService = tokenGenerationService;
this.privateKeySupplier = privateKeySupplier;
this.privateKeyIdSupplier = privateKeyIdSupplier;
this.monitor = monitor;
this.refreshEndpoint = refreshEndpoint;
this.clock = clock;
Expand Down Expand Up @@ -307,7 +306,7 @@ private Result<TokenRepresentationWithId> createToken(TokenParameters tokenParam
allDecorators.add(tp -> tp.claims(JwtRegisteredClaimNames.EXPIRATION_TIME, exp));
}

return tokenGenerationService.generate(privateKeySupplier, allDecorators.toArray(new TokenDecorator[0]))
return tokenGenerationService.generate(privateKeyIdSupplier.get(), allDecorators.toArray(new TokenDecorator[0]))
.map(tr -> new TokenRepresentationWithId(tokenId.get(), tr));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
import org.eclipse.edc.junit.annotations.ComponentTest;
import org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames;
import org.eclipse.edc.keys.spi.LocalPublicKeyService;
import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.query.CriterionOperatorRegistryImpl;
import org.eclipse.edc.security.token.jwt.CryptoConverter;
import org.eclipse.edc.security.token.jwt.DefaultJwsSignerProvider;
import org.eclipse.edc.spi.iam.TokenParameters;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.spi.types.domain.DataAddress;
Expand Down Expand Up @@ -72,6 +74,7 @@ class DataPlaneTokenRefreshServiceImplComponentTest {
public static final String PROVIDER_DID = "did:web:alice";
private final DidPublicKeyResolver didPkResolverMock = mock();
private final LocalPublicKeyService localPublicKeyService = mock();
private final PrivateKeyResolver privateKeyResolver = mock();
private DataPlaneTokenRefreshServiceImpl tokenRefreshService;
private InMemoryAccessTokenDataStore tokenDataStore;
private ECKey consumerKey;
Expand All @@ -80,6 +83,7 @@ class DataPlaneTokenRefreshServiceImplComponentTest {
@BeforeEach
void setup() throws JOSEException {

var privateKeyAlias = "privateKeyAlias";
providerKey = new ECKeyGenerator(Curve.P_384).keyID(PROVIDER_BPN + "#provider-key").keyUse(KeyUse.SIGNATURE).generate();
consumerKey = new ECKeyGenerator(Curve.P_384).keyID(CONSUMER_DID + "#consumer-key").keyUse(KeyUse.SIGNATURE).generate();

Expand All @@ -91,8 +95,8 @@ void setup() throws JOSEException {
didPkResolverMock,
localPublicKeyService,
tokenDataStore,
new JwtGenerationService(),
() -> privateKey,
new JwtGenerationService(new DefaultJwsSignerProvider(privateKeyResolver)),
() -> privateKeyAlias,
mock(),
TEST_REFRESH_ENDPOINT,
PROVIDER_DID,
Expand All @@ -102,6 +106,7 @@ void setup() throws JOSEException {
new InMemoryVault(mock()),
new ObjectMapper());

when(privateKeyResolver.resolvePrivateKey(privateKeyAlias)).thenReturn(Result.success(privateKey));
when(localPublicKeyService.resolveKey(eq(consumerKey.getKeyID()))).thenReturn(Result.success(consumerKey.toPublicKey()));
when(localPublicKeyService.resolveKey(eq(providerKey.getKeyID()))).thenReturn(Result.success(providerKey.toPublicKey()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public SecureTokenService secureTokenService(ServiceExtensionContext context) {
})
.orElseGet(() -> {
monitor.info("DIM URL not configured, will use the standard EDC Remote STS client");
return new RemoteSecureTokenService(oauth2Client, clientConfiguration);
return new RemoteSecureTokenService(oauth2Client, clientConfiguration, vault);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private boolean isExpired() {

@NotNull
private Result<Oauth2CredentialsRequest> createRequest() {
var secret = vault.resolveSecret(configuration.clientSecret());
var secret = vault.resolveSecret(configuration.clientSecretAlias());
if (secret != null) {
var builder = SharedSecretOauth2CredentialsRequest.Builder.newInstance()
.url(configuration.tokenUrl())
Expand All @@ -95,7 +95,7 @@ private Result<Oauth2CredentialsRequest> createRequest() {

return Result.success(builder.build());
} else {
return Result.failure("Failed to fetch client secret from the vault with alias: %s".formatted(configuration.clientSecret()));
return Result.failure("Failed to fetch client secret from the vault with alias: %s".formatted(configuration.clientSecretAlias()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void initialize(ServiceExtensionContext context, StsClientConfigurationExtension

assertThat(extension.clientConfiguration(context)).satisfies(stsConfig -> {
assertThat(stsConfig.clientId()).isEqualTo("clientId");
assertThat(stsConfig.clientSecret()).isEqualTo("clientSecretAlias");
assertThat(stsConfig.clientSecretAlias()).isEqualTo("clientSecretAlias");
assertThat(stsConfig.tokenUrl()).isEqualTo("url");
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.edc.iam.identitytrust.spi.SecureTokenService;
import org.eclipse.edc.iam.identitytrust.sts.embedded.EmbeddedSecureTokenService;
import org.eclipse.edc.junit.extensions.EmbeddedRuntime;
import org.eclipse.edc.security.token.jwt.DefaultJwsSignerProvider;
import org.eclipse.edc.spi.iam.AudienceResolver;
import org.eclipse.edc.spi.iam.IdentityService;
import org.eclipse.edc.spi.result.Result;
Expand Down Expand Up @@ -62,13 +63,15 @@ public ParticipantRuntime(String moduleName, String runtimeName, String bpn, Map
this.registerServiceMock(IdentityService.class, new MockBpnIdentityService(bpn));
this.registerServiceMock(AudienceResolver.class, remoteMessage -> Result.success(remoteMessage.getCounterPartyAddress()));
this.registerServiceMock(BdrsClient.class, (s) -> s);

var kid = properties.get("edc.iam.issuer.id") + "#key-1";
var privateAlias = properties.get("edc.transfer.proxy.token.signer.privatekey.alias");
try {
runtimeKeyPair = new ECKeyGenerator(Curve.P_256).keyID(kid).generate();
KeyPool.register(kid, runtimeKeyPair.toKeyPair());
var privateKey = runtimeKeyPair.toPrivateKey();

registerServiceMock(SecureTokenService.class, new EmbeddedSecureTokenService(new JwtGenerationService(), () -> privateKey, () -> kid, Clock.systemUTC(), Duration.ofMinutes(10).toMillis()));
registerServiceMock(SecureTokenService.class, new EmbeddedSecureTokenService(new JwtGenerationService(new DefaultJwsSignerProvider((k) -> Result.success(privateKey))), () -> privateAlias, () -> kid, Clock.systemUTC(), Duration.ofMinutes(10).toMillis()));
registerServiceMock(DidPublicKeyResolver.class, keyId -> Result.success(KeyPool.forId(keyId).getPublic()));
} catch (JOSEException e) {
throw new RuntimeException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.eclipse.edc.json.JacksonTypeManager;
import org.eclipse.edc.junit.annotations.EndToEndTest;
import org.eclipse.edc.junit.extensions.RuntimeExtension;
import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.security.token.jwt.DefaultJwsSignerProvider;
import org.eclipse.edc.spi.types.TypeManager;
import org.eclipse.edc.token.JwtGenerationService;
import org.eclipse.edc.token.spi.TokenGenerationService;
Expand All @@ -36,7 +38,6 @@
import org.mockserver.integration.ClientAndServer;
import org.mockserver.model.HttpResponse;

import java.security.PrivateKey;
import java.time.Clock;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -64,11 +65,7 @@ static void unwind() {
}

private static EmbeddedSecureTokenService tokenServiceFor(TokenGenerationService tokenGenerationService, IatpParticipant iatpDimParticipant) {
return new EmbeddedSecureTokenService(tokenGenerationService, privateKeySupplier(iatpDimParticipant), publicIdSupplier(iatpDimParticipant), Clock.systemUTC(), 60 * 60);
}

private static Supplier<PrivateKey> privateKeySupplier(IatpParticipant participant) {
return () -> participant.getKeyPair().getPrivate();
return new EmbeddedSecureTokenService(tokenGenerationService, iatpDimParticipant::getPrivateKeyAlias, publicIdSupplier(iatpDimParticipant), Clock.systemUTC(), 60 * 60);
}

private static Supplier<String> publicIdSupplier(IatpParticipant participant) {
Expand All @@ -78,11 +75,13 @@ private static Supplier<String> publicIdSupplier(IatpParticipant participant) {
@BeforeAll
static void prepare() {

var tokenGeneration = new JwtGenerationService();
var consumerTokenGeneration = new JwtGenerationService(new DefaultJwsSignerProvider(CONSUMER_RUNTIME.getService(PrivateKeyResolver.class)));
var providerTokenGeneration = new JwtGenerationService(new DefaultJwsSignerProvider(PROVIDER_RUNTIME.getService(PrivateKeyResolver.class)));


var generatorServices = Map.of(
CONSUMER.getDid(), tokenServiceFor(tokenGeneration, CONSUMER),
PROVIDER.getDid(), tokenServiceFor(tokenGeneration, PROVIDER));
CONSUMER.getDid(), tokenServiceFor(consumerTokenGeneration, CONSUMER),
PROVIDER.getDid(), tokenServiceFor(providerTokenGeneration, PROVIDER));

oauthServer = ClientAndServer.startClientAndServer(STS.stsUri().getPort());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,16 @@

import org.eclipse.edc.iam.identitytrust.spi.SecureTokenService;
import org.eclipse.edc.iam.identitytrust.sts.embedded.EmbeddedSecureTokenService;
import org.eclipse.edc.jwt.signer.spi.JwsSignerProvider;
import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.token.JwtGenerationService;

import java.security.PrivateKey;
import java.time.Clock;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class SecureTokenServiceExtension implements ServiceExtension {
public static final String STS_PRIVATE_KEY_ALIAS = "edc.iam.sts.privatekey.alias";
Expand All @@ -45,13 +43,15 @@ public class SecureTokenServiceExtension implements ServiceExtension {
@Inject
private Clock clock;

@Inject
private JwsSignerProvider jwsSignerProvider;

@Provider
public SecureTokenService createEmbeddedSts(ServiceExtensionContext context) {
var tokenExpiration = context.getSetting(STS_TOKEN_EXPIRATION, DEFAULT_STS_TOKEN_EXPIRATION_MIN);
var publicKeyId = context.getSetting(STS_PUBLIC_KEY_ID, null);
var privKeyAlias = context.getSetting(STS_PRIVATE_KEY_ALIAS, null);

Supplier<PrivateKey> supplier = () -> privateKeyResolver.resolvePrivateKey(privKeyAlias).orElseThrow(f -> new EdcException("This EDC instance is not operational due to the following error: %s".formatted(f.getFailureDetail())));
return new EmbeddedSecureTokenService(new JwtGenerationService(), supplier, () -> publicKeyId, clock, TimeUnit.MINUTES.toSeconds(tokenExpiration));
return new EmbeddedSecureTokenService(new JwtGenerationService(jwsSignerProvider), () -> privKeyAlias, () -> publicKeyId, clock, TimeUnit.MINUTES.toSeconds(tokenExpiration));
}
}
3 changes: 1 addition & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
format.version = "1.1"

[versions]
edc = "0.8.2-20240808-SNAPSHOT"

edc = "0.8.2-20240816-SNAPSHOT"
assertj = "3.26.3"
awaitility = "4.2.2"
aws = "2.27.2"
Expand Down

0 comments on commit f0139f5

Please sign in to comment.