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

feat: add TokenRefreshHandler #1126

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
1 change: 1 addition & 0 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ maven/mavencentral/org.eclipse.edc/dsp-transfer-process-transform/0.5.2-SNAPSHOT
maven/mavencentral/org.eclipse.edc/dsp-transfer-process/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/dsp-version-api/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/dsp/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/edr-store-spi/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/http-spi/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/http/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/iam-mock/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
Expand Down
47 changes: 0 additions & 47 deletions edc-extensions/README.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.web.spi.WebService;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.api.v1.TokenRefreshApiController;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.DataPlaneTokenRefreshService;

import static org.eclipse.tractusx.edc.dataplane.tokenrefresh.api.TokenRefreshApiExtension.NAME;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.eclipse.edc.web.spi.ApiErrorDetail;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.model.TokenResponse;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.model.TokenResponse;

@SecurityScheme(name = "Authentication",
description = "Self-Issued ID token containing an access_token",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
import jakarta.ws.rs.core.MediaType;
import org.eclipse.edc.web.spi.exception.AuthenticationFailedException;
import org.eclipse.edc.web.spi.exception.InvalidRequestException;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.model.TokenResponse;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.model.TokenResponse;

import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import io.restassured.specification.RequestSpecification;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.model.TokenResponse;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.model.TokenResponse;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.runtime.metamodel.annotation.Setting;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.security.PrivateKeyResolver;
import org.eclipse.edc.spi.security.Vault;
import org.eclipse.edc.spi.system.Hostname;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.types.TypeManager;
import org.eclipse.edc.token.JwtGenerationService;
import org.eclipse.edc.token.spi.TokenValidationService;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.DataPlaneTokenRefreshService;
import org.jetbrains.annotations.NotNull;

import java.security.PrivateKey;
Expand All @@ -48,7 +50,11 @@ public class DataPlaneTokenRefreshServiceExtension implements ServiceExtension {
public static final String NAME = "DataPlane Token Refresh Service extension";
public static final int DEFAULT_TOKEN_EXPIRY_TOLERANCE_SECONDS = 5;
@Setting(value = "Token expiry tolerance period in seconds to allow for clock skew", defaultValue = "" + DEFAULT_TOKEN_EXPIRY_TOLERANCE_SECONDS)
public static final String TOKEN_EXPIRY_TOLERANCE_SECONDS_PROPERTY = "edc.dataplane.api.token.expiry.tolerance";
public static final String TOKEN_EXPIRY_TOLERANCE_SECONDS_PROPERTY = "edc.dataplane.token.expiry.tolerance";

@Setting(value = "The HTTP endpoint where clients can request a renewal of their access token for the public dataplane API")
public static final String REFRESH_ENDPOINT_PROPERTY = "edc.dataplane.token.refresh.endpoint";

@Inject
private TokenValidationService tokenValidationService;
@Inject
Expand All @@ -63,6 +69,8 @@ public class DataPlaneTokenRefreshServiceExtension implements ServiceExtension {
private Vault vault;
@Inject
private TypeManager typeManager;
@Inject
private Hostname hostname;

private DataPlaneTokenRefreshServiceImpl tokenRefreshService;

Expand All @@ -83,16 +91,36 @@ public DataPlaneTokenRefreshService createRefreshTokenService(ServiceExtensionCo
return getTokenRefreshService(context);
}

private int getExpiryToleranceConfig(ServiceExtensionContext context) {
return context.getConfig().getInteger(TOKEN_EXPIRY_TOLERANCE_SECONDS_PROPERTY, DEFAULT_TOKEN_EXPIRY_TOLERANCE_SECONDS);
}

@NotNull
private DataPlaneTokenRefreshServiceImpl getTokenRefreshService(ServiceExtensionContext context) {
if (tokenRefreshService == null) {
var epsilon = context.getConfig().getInteger(TOKEN_EXPIRY_TOLERANCE_SECONDS_PROPERTY, DEFAULT_TOKEN_EXPIRY_TOLERANCE_SECONDS);
tokenRefreshService = new DataPlaneTokenRefreshServiceImpl(clock, tokenValidationService, didPkResolver, accessTokenDataStore, new JwtGenerationService(), getPrivateKeySupplier(context), context.getMonitor(), null,
epsilon, vault, typeManager.getMapper());
var monitor = context.getMonitor().withPrefix("DataPlane Token Refresh");
var expiryTolerance = getExpiryToleranceConfig(context);
var refreshEndpoint = getRefreshEndpointConfig(context, monitor);
monitor.debug("Token refresh endpoint: %s".formatted(refreshEndpoint));
monitor.debug("Token refresh time tolerance: %d s".formatted(expiryTolerance));
tokenRefreshService = new DataPlaneTokenRefreshServiceImpl(clock, tokenValidationService, didPkResolver, accessTokenDataStore, new JwtGenerationService(),
getPrivateKeySupplier(context), context.getMonitor(), refreshEndpoint, expiryTolerance,
vault, typeManager.getMapper());
}
return tokenRefreshService;
}

private String getRefreshEndpointConfig(ServiceExtensionContext context, Monitor monitor) {
var refreshEndpoint = context.getConfig().getString(REFRESH_ENDPOINT_PROPERTY, null);
if (refreshEndpoint == null) {
var port = context.getConfig().getInteger("web.http.public.port", 8185);
var path = context.getConfig().getString("web.http.public.path", "/api/v2/public");
refreshEndpoint = "http://%s:%d%s".formatted(hostname.get(), port, path);
monitor.warning("Config property '%s' was not specified, the default '%s' will be used.".formatted(REFRESH_ENDPOINT_PROPERTY, refreshEndpoint));
}
return refreshEndpoint;
}

@NotNull
private Supplier<PrivateKey> getPrivateKeySupplier(ServiceExtensionContext context) {
return () -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.core.rules.ClaimIsPresentRule;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.core.rules.IssuerEqualsSubjectRule;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.core.rules.RefreshTokenValidationRule;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.DataPlaneTokenRefreshService;
import org.eclipse.tractusx.edc.dataplane.tokenrefresh.spi.model.TokenResponse;
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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -18,16 +18,22 @@
********************************************************************************/

plugins {
`maven-publish`
`java-library`
}

dependencies {
implementation(project(":edc-extensions:bpn-validation"))
implementation(project(":edc-extensions:data-encryption"))
implementation(project(":edc-extensions:dataplane:dataplane-selector-configuration"))
implementation(project(":edc-extensions:postgresql-migration"))
implementation(project(":edc-extensions:provision-additional-headers"))
implementation(project(":edc-extensions:transferprocess-sftp-client"))
implementation(project(":edc-extensions:transferprocess-sftp-common"))
implementation(project(":edc-extensions:transferprocess-sftp-provisioner"))
implementation(project(":spi:tokenrefresh-spi"))
implementation(libs.edc.spi.core)
implementation(libs.edc.spi.edrstore)
implementation(libs.edc.spi.http)
implementation(libs.edc.spi.token)
implementation(libs.edc.spi.jwt)
implementation(libs.edc.spi.identitytrust)
implementation(libs.edc.util)
implementation(libs.nimbus.jwt)


testImplementation(libs.edc.junit)
testImplementation(libs.restAssured)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/********************************************************************************
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

package org.eclipse.tractusx.edc.common.tokenrefresh;

import org.eclipse.edc.edr.spi.store.EndpointDataReferenceStore;
import org.eclipse.edc.identitytrust.SecureTokenService;
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.http.EdcHttpClient;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.types.TypeManager;
import org.eclipse.tractusx.edc.spi.tokenrefresh.common.TokenRefreshHandler;

import static org.eclipse.tractusx.edc.common.tokenrefresh.TokenRefreshHandlerExtension.NAME;


@Extension(value = NAME)
public class TokenRefreshHandlerExtension implements ServiceExtension {
public static final String NAME = "Token Refresh Handler Extension";
// this setting is defined by the IdentityAndTrustExtension
private static final String PARTICIPANT_DID_PROPERTY = "edc.iam.issuer.id";
@Inject
private EndpointDataReferenceStore edrStore;
@Inject
private EdcHttpClient httpClient;
@Inject
private SecureTokenService secureTokenService;
@Inject
private TypeManager typeManager;

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

@Provider
public TokenRefreshHandler createTokenRefreshHander(ServiceExtensionContext context) {
return new TokenRefreshHandlerImpl(edrStore, httpClient, getOwnDid(context), context.getMonitor(), secureTokenService, typeManager.getMapper());
}

private String getOwnDid(ServiceExtensionContext context) {
return context.getConfig().getString(PARTICIPANT_DID_PROPERTY);
}
}
Loading
Loading