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

fix: applies STS remote refactor of upstream EDC #1501

Merged
merged 4 commits into from
Aug 16, 2024
Merged
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
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
Loading