Skip to content

Commit

Permalink
feat: STS client SQL store implementation (#4474)
Browse files Browse the repository at this point in the history
* feat: STS client SQL store implementation

* pr remarks

* chore: deps file
  • Loading branch information
wolf4ood authored Sep 16, 2024
1 parent 7e0e0f5 commit 06cfb23
Show file tree
Hide file tree
Showing 26 changed files with 1,364 additions and 205 deletions.
2 changes: 1 addition & 1 deletion DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ maven/mavencentral/com.jcraft/jzlib/1.1.3, BSD-2-Clause, approved, CQ6218
maven/mavencentral/com.lmax/disruptor/3.4.4, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.networknt/json-schema-validator/1.0.76, Apache-2.0, approved, CQ22638
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.28, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.41.1, , restricted, clearlydefined
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.41.1, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.puppycrawl.tools/checkstyle/10.18.1, LGPL-2.1-or-later AND (Apache-2.0 AND LGPL-2.1-or-later) AND Apache-2.0, approved, #16060
maven/mavencentral/com.samskivert/jmustache/1.15, BSD-2-Clause AND BSD-3-Clause, approved, clearlydefined
maven/mavencentral/com.squareup.okhttp3/okhttp-dnsoverhttps/4.12.0, Apache-2.0, approved, #11159
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,17 @@ void token() {
var did = "did:example:subject";
var audience = "audience";
var token = "token";
var publicKeyReference = "publicKeyReference";
var name = "Name";
var expiresIn = 3600;

var client = StsClient.Builder.newInstance()
.id(id)
.clientId(clientId)
.name("Name")
.name(name)
.secretAlias(clientKeyAlias)
.privateKeyAlias(privateKeyAlias)
.publicKeyReference(publicKeyReference)
.did(did)
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.CLIENT_ID;
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.CLIENT_NAME;
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.CLIENT_PRIVATE_KEY_ALIAS;
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.CLIENT_PUBLIC_KEY_REFERENCE;
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.CLIENT_SECRET_ALIAS;
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.CONFIG_PREFIX;
import static org.eclipse.edc.iam.identitytrust.sts.client.configuration.StsClientConfigurationExtension.ID;
Expand Down Expand Up @@ -65,6 +66,7 @@ void initialize_withClient(ServiceExtensionContext context, StsClientConfigurati
.privateKeyAlias("pAlias")
.secretAlias("sAlias")
.did("did:example:subject")
.publicKeyReference("publicReference")
.build();
var clientAlias = "client";
var config = ConfigFactory.fromMap(clientConfig(client, clientAlias));
Expand All @@ -74,7 +76,9 @@ void initialize_withClient(ServiceExtensionContext context, StsClientConfigurati
var capture = ArgumentCaptor.forClass(StsClient.class);
verify(clientStore).create(capture.capture());

assertThat(capture.getValue()).usingRecursiveComparison().isEqualTo(client);
assertThat(capture.getValue()).usingRecursiveComparison()
.ignoringFields("createdAt")
.isEqualTo(client);
}

private Map<String, String> clientConfig(StsClient client, String clientAlias) {
Expand All @@ -84,7 +88,8 @@ private Map<String, String> clientConfig(StsClient client, String clientAlias) {
clientAlias + "." + CLIENT_ID, client.getClientId(),
clientAlias + "." + CLIENT_SECRET_ALIAS, client.getSecretAlias(),
clientAlias + "." + CLIENT_DID, client.getDid(),
clientAlias + "." + CLIENT_PRIVATE_KEY_ALIAS, client.getPrivateKeyAlias()
clientAlias + "." + CLIENT_PRIVATE_KEY_ALIAS, client.getPrivateKeyAlias(),
clientAlias + "." + CLIENT_PUBLIC_KEY_REFERENCE, client.getPublicKeyReference()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ dependencies {
implementation(project(":spi:common:keys-spi"))
implementation(project(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust-sts-embedded"))
implementation(project(":core:common:token-core"))
implementation(project(":core:common:lib:store-lib"))

testImplementation(testFixtures(project(":spi:common:identity-trust-sts-spi")))
testImplementation(project(":core:common:lib:boot-lib"))
testImplementation(project(":core:common:lib:crypto-common-lib"))
testImplementation(project(":core:common:lib:keys-lib"))
testImplementation(project(":core:common:junit"))
testImplementation(project(":core:common:lib:query-lib"))
testImplementation(libs.nimbus.jwt)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,26 @@
import org.eclipse.edc.iam.identitytrust.sts.defaults.store.InMemoryStsClientStore;
import org.eclipse.edc.iam.identitytrust.sts.spi.store.StsClientStore;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.system.ServiceExtension;

@Extension(StsDefaultStoresExtension.NAME)
public class StsDefaultStoresExtension implements ServiceExtension {

public static final String NAME = "Secure Token Service Default Stores";

@Inject
private CriterionOperatorRegistry criterionOperatorRegistry;

@Override
public String name() {
return NAME;
}

@Provider(isDefault = true)
public StsClientStore clientStore() {
return new InMemoryStsClientStore();
return new InMemoryStsClientStore(criterionOperatorRegistry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@

import org.eclipse.edc.iam.identitytrust.sts.spi.model.StsClient;
import org.eclipse.edc.iam.identitytrust.sts.spi.store.StsClientStore;
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.query.QueryResolver;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.StoreResult;
import org.eclipse.edc.store.ReflectionBasedQueryResolver;
import org.jetbrains.annotations.NotNull;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

import static java.lang.String.format;

Expand All @@ -29,19 +35,54 @@
*/
public class InMemoryStsClientStore implements StsClientStore {

// we store it by clientId
private final Map<String, StsClient> clients = new ConcurrentHashMap<>();
private final QueryResolver<StsClient> queryResolver;


public InMemoryStsClientStore(CriterionOperatorRegistry criterionOperatorRegistry) {
queryResolver = new ReflectionBasedQueryResolver<>(StsClient.class, criterionOperatorRegistry);
}

@Override
public StoreResult<StsClient> create(StsClient client) {
return Optional.ofNullable(clients.putIfAbsent(client.getClientId(), client))
.map(old -> StoreResult.<StsClient>alreadyExists(format("Client with id %s already exists", client.getClientId())))
.map(old -> StoreResult.<StsClient>alreadyExists(format(CLIENT_EXISTS_TEMPLATE, client.getClientId())))
.orElseGet(() -> StoreResult.success(client));
}

@Override
public StoreResult<StsClient> findByClientId(String id) {
return Optional.ofNullable(clients.get(id))
public StoreResult<Void> update(StsClient stsClient) {
var prev = clients.replace(stsClient.getClientId(), stsClient);
return Optional.ofNullable(prev)
.map(a -> StoreResult.<Void>success())
.orElse(StoreResult.notFound(format(CLIENT_NOT_FOUND_BY_ID_TEMPLATE, stsClient.getId())));
}

@Override
public @NotNull Stream<StsClient> findAll(QuerySpec spec) {
return queryResolver.query(clients.values().stream(), spec);
}

@Override
public StoreResult<StsClient> findById(String id) {
return clients.values().stream()
.filter(client -> client.getId().equals(id))
.findFirst()
.map(StoreResult::success)
.orElseGet(() -> StoreResult.notFound(format(CLIENT_NOT_FOUND_BY_ID_TEMPLATE, id)));
}

@Override
public StoreResult<StsClient> findByClientId(String clientId) {
return Optional.ofNullable(clients.get(clientId))
.map(StoreResult::success)
.orElseGet(() -> StoreResult.notFound(format("Client with id %s not found.", id)));
.orElseGet(() -> StoreResult.notFound(format(CLIENT_NOT_FOUND_BY_CLIENT_ID_TEMPLATE, clientId)));
}

@Override
public StoreResult<StsClient> deleteById(String id) {
return findById(id)
.onSuccess(client -> clients.remove(client.getClientId()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.eclipse.edc.keys.keyparsers.PemParser;
import org.eclipse.edc.keys.spi.KeyParserRegistry;
import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.query.CriterionOperatorRegistryImpl;
import org.eclipse.edc.security.token.jwt.DefaultJwsSignerProvider;
import org.eclipse.edc.spi.security.Vault;
import org.eclipse.edc.token.JwtGenerationService;
Expand Down Expand Up @@ -56,7 +57,7 @@
@ComponentTest
public class StsClientTokenIssuanceIntegrationTest {

private final InMemoryStsClientStore clientStore = new InMemoryStsClientStore();
private final InMemoryStsClientStore clientStore = new InMemoryStsClientStore(CriterionOperatorRegistryImpl.ofDefaults());
private final Vault vault = new InMemoryVault(mock());
private final KeyParserRegistry keyParserRegistry = new KeyParserRegistryImpl();
private StsClientServiceImpl clientService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.eclipse.edc.iam.identitytrust.sts.spi.store.StsClientStore;
import org.eclipse.edc.iam.identitytrust.sts.spi.store.fixtures.StsClientStoreTestBase;
import org.eclipse.edc.query.CriterionOperatorRegistryImpl;
import org.junit.jupiter.api.BeforeEach;

public class InMemoryStsClientStoreTest extends StsClientStoreTestBase {
Expand All @@ -24,7 +25,7 @@ public class InMemoryStsClientStoreTest extends StsClientStoreTestBase {

@BeforeEach
void setUp() {
store = new InMemoryStsClientStore();
store = new InMemoryStsClientStore(CriterionOperatorRegistryImpl.ofDefaults());
}

@Override
Expand Down
31 changes: 31 additions & 0 deletions extensions/common/store/sql/sts-client-store-sql/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

plugins {
`java-library`
}

dependencies {
api(project(":spi:common:core-spi"))
api(project(":spi:common:transaction-spi"))

implementation(project(":extensions:common:sql:sql-core"))
implementation(project(":extensions:common:sql:sql-bootstrapper"))
implementation(project(":spi:common:identity-trust-sts-spi"))
implementation(project(":spi:common:transaction-datasource-spi"))
testImplementation(project(":core:common:junit"))
testImplementation(testFixtures(project(":extensions:common:sql:sql-core")))
testImplementation(testFixtures(project(":spi:common:identity-trust-sts-spi")))

}
Loading

0 comments on commit 06cfb23

Please sign in to comment.