diff --git a/edc-extensions/tokenrefresh-handler/build.gradle.kts b/edc-extensions/tokenrefresh-handler/build.gradle.kts index 68c602e5b..c2612c77d 100644 --- a/edc-extensions/tokenrefresh-handler/build.gradle.kts +++ b/edc-extensions/tokenrefresh-handler/build.gradle.kts @@ -29,9 +29,9 @@ dependencies { 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) - implementation(libs.edc.core.token) //needed for the JwtGenerationService testImplementation(libs.edc.junit) diff --git a/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerExtension.java b/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerExtension.java index ec51c008d..fcc6d9fc8 100644 --- a/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerExtension.java +++ b/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerExtension.java @@ -20,6 +20,7 @@ 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; @@ -27,13 +28,8 @@ 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.TokenGenerationService; import org.eclipse.tractusx.edc.spi.tokenrefresh.common.TokenRefreshHandler; -import java.security.PrivateKey; -import java.util.function.Supplier; - import static org.eclipse.tractusx.edc.common.tokenrefresh.TokenRefreshHandlerExtension.NAME; @@ -47,10 +43,13 @@ public class TokenRefreshHandlerExtension implements ServiceExtension { @Inject private EdcHttpClient httpClient; @Inject - private TokenGenerationService tokenGenerationService; + private SecureTokenService secureTokenService; @Inject private TypeManager typeManager; + @Inject + private SecureTokenService sts; + @Override public String name() { return NAME; @@ -58,20 +57,10 @@ public String name() { @Provider public TokenRefreshHandler createTokenRefreshHander(ServiceExtensionContext context) { - return new TokenRefreshHandlerImpl(edrStore, httpClient, getPrivateKeySupplier(context), getPublicKeySupplier(context), getOwnDid(context), context.getMonitor(), new JwtGenerationService(), typeManager.getMapper()); + return new TokenRefreshHandlerImpl(edrStore, httpClient, getOwnDid(context), context.getMonitor(), secureTokenService, typeManager.getMapper()); } private String getOwnDid(ServiceExtensionContext context) { return context.getConfig().getString(PARTICIPANT_DID_PROPERTY); } - - private Supplier getPublicKeySupplier(ServiceExtensionContext context) { - return null; - } - - private Supplier getPrivateKeySupplier(ServiceExtensionContext context) { - return null; - } - - } diff --git a/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImpl.java b/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImpl.java index a874da08e..0fa192480 100644 --- a/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImpl.java +++ b/edc-extensions/tokenrefresh-handler/src/main/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImpl.java @@ -25,60 +25,55 @@ import okhttp3.Request; import okhttp3.RequestBody; import org.eclipse.edc.edr.spi.store.EndpointDataReferenceStore; -import org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames; +import org.eclipse.edc.identitytrust.SecureTokenService; import org.eclipse.edc.spi.http.EdcHttpClient; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.result.Result; -import org.eclipse.edc.token.spi.KeyIdDecorator; -import org.eclipse.edc.token.spi.TokenDecorator; -import org.eclipse.edc.token.spi.TokenGenerationService; import org.eclipse.edc.util.string.StringUtils; import org.eclipse.tractusx.edc.spi.tokenrefresh.common.TokenRefreshHandler; import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.model.TokenResponse; import java.io.IOException; -import java.security.PrivateKey; import java.text.ParseException; -import java.util.List; -import java.util.function.Supplier; +import java.util.Map; +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.ISSUER; +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.JWT_ID; +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.SUBJECT; import static org.eclipse.edc.util.string.StringUtils.isNullOrBlank; public class TokenRefreshHandlerImpl implements TokenRefreshHandler { + public static final String PROPERTY_AUTHORIZATION = "authorization"; + public static final String PROPERTY_REFRESH_TOKEN = "refreshToken"; + public static final String PROPERTY_REFRESH_ENDPOINT = "refreshEndpoint"; private final EndpointDataReferenceStore edrStore; private final EdcHttpClient httpClient; - private final Supplier privateKeySupplier; - private final Supplier publicKeySupplier; private final String ownDid; private final Monitor monitor; - private final TokenGenerationService tokenGenerationService; + private final SecureTokenService secureTokenService; private final ObjectMapper objectMapper; /** * Creates a new TokenRefreshHandler * - * @param edrStore a persistent storage where {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} objects are stored. - * @param httpClient needed to make the actual refresh call against the refresh endpoint - * @param privateKeySupplier a {@link Supplier} that provides the private key that is used to sign the authentication token - * @param publicKeySupplier provides the ID of the public key, which is added to the header of the authentication token. - * The public key material identified by this ID must be resolvable via the participant's DID document. - * @param ownDid the DID of this connector - * @param tokenGenerationService Service to generate the authentication token - * @param objectMapper ObjectMapper to interpret JSON responses + * @param edrStore a persistent storage where {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} objects are stored. + * @param httpClient needed to make the actual refresh call against the refresh endpoint + * @param ownDid the DID of this connector + * @param secureTokenService Service to generate the authentication token + * @param objectMapper ObjectMapper to interpret JSON responses */ public TokenRefreshHandlerImpl(EndpointDataReferenceStore edrStore, EdcHttpClient httpClient, - Supplier privateKeySupplier, - Supplier publicKeySupplier, String ownDid, - Monitor monitor, TokenGenerationService tokenGenerationService, ObjectMapper objectMapper) { + Monitor monitor, + SecureTokenService secureTokenService, + ObjectMapper objectMapper) { this.edrStore = edrStore; this.httpClient = httpClient; - this.privateKeySupplier = privateKeySupplier; - this.publicKeySupplier = publicKeySupplier; this.ownDid = ownDid; this.monitor = monitor; - this.tokenGenerationService = tokenGenerationService; + this.secureTokenService = secureTokenService; this.objectMapper = objectMapper; } @@ -89,9 +84,9 @@ public Result refreshToken(String tokenId) { return Result.failure(edrResult.getFailureDetail()); } var edr = edrResult.getContent(); - var accessToken = edr.getStringProperty("authorization"); - var refreshToken = edr.getProperties().get("refreshToken"); - var refreshEndpoint = edr.getProperties().get("refreshEndpoint"); + var accessToken = edr.getStringProperty(PROPERTY_AUTHORIZATION); + var refreshToken = edr.getProperties().get(PROPERTY_REFRESH_TOKEN); + var refreshEndpoint = edr.getProperties().get(PROPERTY_REFRESH_ENDPOINT); if (isNullOrBlank(accessToken)) { return Result.failure("Cannot perform token refresh: required property 'authorization' not found on EDR."); @@ -103,20 +98,18 @@ public Result refreshToken(String tokenId) { return Result.failure("Cannot perform token refresh: required property 'refreshEndpoint' not found on EDR."); } - var audience = getStringClaim(accessToken, JwtRegisteredClaimNames.ISSUER); + var audience = getStringClaim(accessToken, ISSUER); if (audience.failed()) { return audience.mapTo(); } - var decorators = List.of( - new KeyIdDecorator(publicKeySupplier.get()), - tp -> tp.claims(JwtRegisteredClaimNames.JWT_ID, tokenId), - tp -> tp.claims(JwtRegisteredClaimNames.ISSUER, ownDid), - tp -> tp.claims(JwtRegisteredClaimNames.SUBJECT, ownDid), - tp -> tp.claims(JwtRegisteredClaimNames.AUDIENCE, audience.getContent()), - (TokenDecorator) tp -> tp.claims("access_token", accessToken) + var claims = Map.of( + JWT_ID, tokenId, + ISSUER, ownDid, + SUBJECT, ownDid, + AUDIENCE, audience.getContent() ); - var authTokenResult = tokenGenerationService.generate(privateKeySupplier, decorators.toArray(new TokenDecorator[0])); + var authTokenResult = secureTokenService.createToken(claims, accessToken); if (authTokenResult.failed()) { return authTokenResult.mapTo(); } diff --git a/edc-extensions/tokenrefresh-handler/src/test/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImplTest.java b/edc-extensions/tokenrefresh-handler/src/test/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImplTest.java index 2884baac4..362e81fbc 100644 --- a/edc-extensions/tokenrefresh-handler/src/test/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImplTest.java +++ b/edc-extensions/tokenrefresh-handler/src/test/java/org/eclipse/tractusx/edc/common/tokenrefresh/TokenRefreshHandlerImplTest.java @@ -35,13 +35,12 @@ import okhttp3.Response; import okhttp3.ResponseBody; import org.eclipse.edc.edr.spi.store.EndpointDataReferenceStore; +import org.eclipse.edc.identitytrust.SecureTokenService; import org.eclipse.edc.spi.http.EdcHttpClient; import org.eclipse.edc.spi.iam.TokenRepresentation; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.spi.result.StoreResult; import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.token.spi.TokenDecorator; -import org.eclipse.edc.token.spi.TokenGenerationService; import org.eclipse.tractusx.edc.spi.tokenrefresh.dataplane.model.TokenResponse; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; @@ -59,6 +58,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -74,7 +74,7 @@ class TokenRefreshHandlerImplTest { private static final String PROVIDER_DID = "did:web:alice"; private final EndpointDataReferenceStore edrStore = mock(); private final EdcHttpClient mockedHttpClient = mock(); - private final TokenGenerationService mockedTokenService = mock(); + private final SecureTokenService mockedTokenService = mock(); private TokenRefreshHandlerImpl tokenRefreshHandler; private PrivateKey consumerKey; private ObjectMapper objectMapper; @@ -94,14 +94,14 @@ private static String createJwt() { void setup() throws JOSEException { consumerKey = new ECKeyGenerator(Curve.P_256).generate().toPrivateKey(); objectMapper = new ObjectMapper(); - tokenRefreshHandler = new TokenRefreshHandlerImpl(edrStore, mockedHttpClient, () -> consumerKey, () -> PUBLIC_KEY_ID, CONSUMER_DID, mock(), + tokenRefreshHandler = new TokenRefreshHandlerImpl(edrStore, mockedHttpClient, CONSUMER_DID, mock(), mockedTokenService, objectMapper); } @Test void refresh_validateCorrectRequest() throws IOException { when(edrStore.resolveByTransferProcess(anyString())).thenReturn(StoreResult.success(createEdr().build())); - when(mockedTokenService.generate(any(), any(TokenDecorator[].class))).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); + when(mockedTokenService.createToken(anyMap(), anyString())).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); var tokenResponse = new TokenResponse("new-access-token", "new-refresh-token", 60 * 5L, "bearer"); var successResponse = createResponse(tokenResponse, 200, ""); when(mockedHttpClient.execute(any())).thenReturn(successResponse); @@ -129,7 +129,7 @@ void refresh_edrNotFound() { @ParameterizedTest(name = "{3}") @ArgumentsSource(InvalidEdrProvider.class) - void refresh_edrLacksRequiredProperties(String authorization, String refreshToken, String refreshEndpoint, String desc) throws IOException { + void refresh_edrLacksRequiredProperties(String authorization, String refreshToken, String refreshEndpoint, String desc) { var invalidEdr = DataAddress.Builder.newInstance().type("test-type") .property("authorization", authorization) .property("refreshToken", refreshToken) @@ -145,7 +145,7 @@ void refresh_edrLacksRequiredProperties(String authorization, String refreshToke @Test void refresh_endpointReturnsFailure() throws IOException { when(edrStore.resolveByTransferProcess(anyString())).thenReturn(StoreResult.success(createEdr().build())); - when(mockedTokenService.generate(any(), any(TokenDecorator[].class))).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); + when(mockedTokenService.createToken(anyMap(), anyString())).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); var response401 = createResponse(null, 401, "Not authorized"); when(mockedHttpClient.execute(any())).thenReturn(response401); @@ -158,7 +158,7 @@ void refresh_endpointReturnsFailure() throws IOException { @Test void refresh_endpointReturnsEmptyBody() throws IOException { when(edrStore.resolveByTransferProcess(anyString())).thenReturn(StoreResult.success(createEdr().build())); - when(mockedTokenService.generate(any(), any(TokenDecorator[].class))).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); + when(mockedTokenService.createToken(anyMap(), anyString())).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); var successResponse = createResponse(null, 200, ""); when(mockedHttpClient.execute(any())).thenReturn(successResponse); var res = tokenRefreshHandler.refreshToken("token-id"); @@ -169,7 +169,7 @@ void refresh_endpointReturnsEmptyBody() throws IOException { @Test void refresh_ioException() throws IOException { when(edrStore.resolveByTransferProcess(anyString())).thenReturn(StoreResult.success(createEdr().build())); - when(mockedTokenService.generate(any(), any(TokenDecorator[].class))).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); + when(mockedTokenService.createToken(anyMap(), anyString())).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("foo-auth-token").build())); when(mockedHttpClient.execute(any())).thenThrow(new IOException("test exception")); assertThat(tokenRefreshHandler.refreshToken("token-id")).isFailed() @@ -184,9 +184,9 @@ void refresh_accessTokenIsNotJwt() { } @Test - void refresh_tokenGenerationFailed() throws IOException { + void refresh_tokenGenerationFailed() { when(edrStore.resolveByTransferProcess(anyString())).thenReturn(StoreResult.success(createEdr().build())); - when(mockedTokenService.generate(any(), any(TokenDecorator[].class))).thenReturn(Result.failure("foobar")); + when(mockedTokenService.createToken(anyMap(), anyString())).thenReturn(Result.failure("foobar")); assertThat(tokenRefreshHandler.refreshToken("token-id")).isFailed() .detail().isEqualTo("foobar"); } @@ -213,7 +213,7 @@ private DataAddress.Builder createEdr() { private static class InvalidEdrProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + public Stream provideArguments(ExtensionContext extensionContext) { return Stream.of( Arguments.of(createJwt(), "foo-refresh-token", null, "refresh endpoint is null"), Arguments.of(createJwt(), "foo-refresh-token", "", "refresh endpoint is empty"),