Skip to content

Commit

Permalink
feat: add TokenRefreshHandler (#1126)
Browse files Browse the repository at this point in the history
* feat: implement TokenRefreshhandler

* DEPENDENCIES

* checkstyle, sonar
  • Loading branch information
paullatzelsperger authored Mar 15, 2024
1 parent a3b4c06 commit 5978673
Show file tree
Hide file tree
Showing 19 changed files with 572 additions and 73 deletions.
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

0 comments on commit 5978673

Please sign in to comment.