Skip to content

Commit

Permalink
feat: Standalone STS (#3556)
Browse files Browse the repository at this point in the history
* feat: Standalone STS

* feat: STS client configuration extension + launcher

* pr remarks

* chore: update dependencies file

* pr remarks
  • Loading branch information
wolf4ood committed Oct 25, 2023
1 parent 0afa286 commit 8f58ce8
Show file tree
Hide file tree
Showing 42 changed files with 1,568 additions and 99 deletions.
10 changes: 5 additions & 5 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
maven/mavencentral/com.apicatalog/carbon-did/0.0.2, Apache-2.0, approved, #9239
maven/mavencentral/com.apicatalog/iron-ed25519-cryptosuite-2020/0.8.1, , restricted, clearlydefined
maven/mavencentral/com.apicatalog/iron-ed25519-cryptosuite-2020/0.8.1, Apache-2.0, approved, #11157
maven/mavencentral/com.apicatalog/iron-verifiable-credentials/0.8.1, Apache-2.0, approved, #9234
maven/mavencentral/com.apicatalog/titanium-json-ld/1.0.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.apicatalog/titanium-json-ld/1.3.1, Apache-2.0, approved, #8912
Expand Down Expand Up @@ -83,11 +83,11 @@ maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.28, Apache-2.0, approved, clea
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.37, Apache-2.0, approved, #11086
maven/mavencentral/com.puppycrawl.tools/checkstyle/10.0, LGPL-2.1-or-later, approved, #7936
maven/mavencentral/com.samskivert/jmustache/1.15, BSD-2-Clause, approved, clearlydefined
maven/mavencentral/com.squareup.okhttp3/okhttp-dnsoverhttps/4.12.0, , restricted, clearlydefined
maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, , restricted, clearlydefined
maven/mavencentral/com.squareup.okhttp3/okhttp-dnsoverhttps/4.12.0, Apache-2.0, approved, #11159
maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, Apache-2.0, approved, #11156
maven/mavencentral/com.squareup.okhttp3/okhttp/4.9.3, Apache-2.0 AND MPL-2.0, approved, #3225
maven/mavencentral/com.squareup.okio/okio-jvm/3.6.0, , restricted, clearlydefined
maven/mavencentral/com.squareup.okio/okio/3.6.0, , restricted, clearlydefined
maven/mavencentral/com.squareup.okio/okio-jvm/3.6.0, Apache-2.0, approved, #11158
maven/mavencentral/com.squareup.okio/okio/3.6.0, Apache-2.0, approved, #11155
maven/mavencentral/com.sun.activation/jakarta.activation/2.0.0, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf
maven/mavencentral/com.sun.activation/jakarta.activation/2.0.1, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf
maven/mavencentral/com.sun.mail/mailapi/1.6.2, CDDL-1.1 OR GPL-2.0-only WITH Classpath-exception-2.0, approved, clearlydefined
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class StsClientServiceImpl implements StsClientService {
private final StsClientStore stsClientStore;
private final TransactionContext transactionContext;
private final Vault vault;

public StsClientServiceImpl(StsClientStore stsClientStore, Vault vault, TransactionContext transactionContext) {
this.stsClientStore = stsClientStore;
this.vault = vault;
Expand All @@ -52,6 +52,6 @@ public ServiceResult<StsClient> authenticate(StsClient client, String secret) {
return Optional.ofNullable(vault.resolveSecret(client.getSecretAlias()))
.filter(vaultSecret -> vaultSecret.equals(secret))
.map(s -> ServiceResult.success(client))
.orElseGet(() -> ServiceResult.badRequest(format("Failed to authenticate client with id %s", client.getId())));
.orElseGet(() -> ServiceResult.unauthorized(format("Failed to authenticate client with id %s", client.getId())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
import java.util.Map;

import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE;
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.CLIENT_ID;
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.ISSUER;
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.SUBJECT;

public class StsClientTokenGeneratorServiceImpl implements StsClientTokenGeneratorService {

public static final String CLIENT_ID = "client_id";
private final long tokenExpiration;
private final StsTokenGenerationProvider tokenGenerationProvider;
private final Clock clock;
Expand All @@ -53,12 +53,21 @@ public ServiceResult<TokenRepresentation> tokenFor(StsClient client, StsClientTo
AUDIENCE, additionalParams.getAudience(),
CLIENT_ID, client.getClientId());

var tokenResult = embeddedTokenGenerator.createToken(claims, additionalParams.getBearerAccessScope());
var tokenResult = embeddedTokenGenerator.createToken(claims, additionalParams.getBearerAccessScope())
.map(this::enrichWithExpiration);

if (tokenResult.failed()) {
return ServiceResult.badRequest(tokenResult.getFailureDetail());
}
return ServiceResult.success(tokenResult.getContent());
}

private TokenRepresentation enrichWithExpiration(TokenRepresentation tokenRepresentation) {
return TokenRepresentation.Builder.newInstance()
.token(tokenRepresentation.getToken())
.additional(tokenRepresentation.getAdditional())
.expiresIn(tokenExpiration)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,27 @@

public class StsClientTokenGeneratorServiceImplTest {

public static final long TOKEN_EXPIRATION = 60 * 5;
private final StsTokenGenerationProvider tokenGenerationProvider = mock();
private final TokenGenerationService tokenGenerator = mock();
private StsClientTokenGeneratorServiceImpl clientTokenService;


@BeforeEach
void setup() {
clientTokenService = new StsClientTokenGeneratorServiceImpl(tokenGenerationProvider, Clock.systemUTC(), 60 * 5);
clientTokenService = new StsClientTokenGeneratorServiceImpl(tokenGenerationProvider, Clock.systemUTC(), TOKEN_EXPIRATION);
}

@Test
void tokenFor() {
var client = createClient("clientId");
var token = TokenRepresentation.Builder.newInstance().token("token").build();
var token = TokenRepresentation.Builder.newInstance().token("token").expiresIn(TOKEN_EXPIRATION).build();
when(tokenGenerationProvider.tokenGeneratorFor(client)).thenReturn(tokenGenerator);
when(tokenGenerator.generate(any())).thenReturn(Result.success(token));

var inserted = clientTokenService.tokenFor(client, StsClientTokenAdditionalParams.Builder.newInstance().audience("aud").build());

assertThat(inserted).isSucceeded().isEqualTo(token);
assertThat(inserted).isSucceeded().usingRecursiveComparison().isEqualTo(token);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 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`
`maven-publish`
}

dependencies {
api(project(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust-sts-api"))
api(project(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust-sts-client-configuration"))
}

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ plugins {

dependencies {
api(project(":spi:common:web-spi"))
api(project(":spi:common:identity-trust-sts-spi"))

implementation(libs.jakarta.rsApi)
implementation(libs.swagger.annotations.jakarta)
Expand All @@ -29,5 +30,7 @@ dependencies {

testImplementation(project(":core:common:junit"))
testImplementation(testFixtures(project(":extensions:common:http:jersey-core")))
testImplementation(testFixtures(project(":spi:common:identity-trust-sts-spi")))
testImplementation(libs.restAssured)
}

Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ public interface SecureTokenServiceApi {
content = @Content(array = @ArraySchema(schema = @Schema(implementation = StsTokenErrorResponse.class))))
})
StsTokenResponse token(@BeanParam StsTokenRequest request);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2023 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
*
*/

package org.eclipse.edc.connector.api.sts;

import org.eclipse.edc.connector.api.sts.configuration.StsApiConfiguration;
import org.eclipse.edc.connector.api.sts.controller.SecureTokenServiceApiController;
import org.eclipse.edc.connector.api.sts.exception.StsTokenExceptionMapper;
import org.eclipse.edc.connector.api.sts.validation.StsTokenRequestValidator;
import org.eclipse.edc.iam.identitytrust.sts.service.StsClientService;
import org.eclipse.edc.iam.identitytrust.sts.service.StsClientTokenGeneratorService;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.web.spi.WebService;

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

public static final String NAME = "Secure Token Service API";

@Inject
private StsApiConfiguration stsApiConfiguration;

@Inject
private StsClientService clientService;

@Inject
private StsClientTokenGeneratorService tokenService;

@Inject
private Monitor monitor;

@Inject
private WebService webService;

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

@Override
public void initialize(ServiceExtensionContext context) {
webService.registerResource(stsApiConfiguration.getContextAlias(), new SecureTokenServiceApiController(clientService, tokenService, new StsTokenRequestValidator()));
webService.registerResource(stsApiConfiguration.getContextAlias(), new StsTokenExceptionMapper());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2023 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
*
*/

package org.eclipse.edc.connector.api.sts;

import org.eclipse.edc.connector.api.sts.configuration.StsApiConfiguration;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provides;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.web.spi.WebServer;
import org.eclipse.edc.web.spi.configuration.WebServiceConfigurer;
import org.eclipse.edc.web.spi.configuration.WebServiceSettings;

@Extension(value = StsApiConfigurationExtension.NAME)
@Provides({ StsApiConfiguration.class })
public class StsApiConfigurationExtension implements ServiceExtension {

public static final String NAME = "Secure Token Service API configuration";
public static final String STS_CONTEXT_ALIAS = "sts";
private static final String WEB_SERVICE_NAME = "STS API";
private static final int DEFAULT_STS_API_PORT = 9292;
private static final String DEFAULT_STS_API_CONTEXT_PATH = "/api/v1/sts";

public static final WebServiceSettings SETTINGS = WebServiceSettings.Builder.newInstance()
.apiConfigKey("web.http." + STS_CONTEXT_ALIAS)
.contextAlias(STS_CONTEXT_ALIAS)
.defaultPath(DEFAULT_STS_API_CONTEXT_PATH)
.defaultPort(DEFAULT_STS_API_PORT)
.useDefaultContext(true)
.name(WEB_SERVICE_NAME)
.build();

@Inject
private WebServer webServer;
@Inject
private WebServiceConfigurer configurator;

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

@Override
public void initialize(ServiceExtensionContext context) {
var config = configurator.configure(context, webServer, SETTINGS);
context.registerService(StsApiConfiguration.class, new StsApiConfiguration(config));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2023 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
*
*/

package org.eclipse.edc.connector.api.sts.configuration;

import org.eclipse.edc.web.spi.configuration.WebServiceConfiguration;

/**
* Configuration for the STS API
*/
public class StsApiConfiguration extends WebServiceConfiguration {

public StsApiConfiguration(WebServiceConfiguration webServiceConfiguration) {
this.contextAlias = webServiceConfiguration.getContextAlias();
this.path = webServiceConfiguration.getPath();
this.port = webServiceConfiguration.getPort();
}
}

0 comments on commit 8f58ce8

Please sign in to comment.