Skip to content

Commit

Permalink
feat: add DataPlane Token Refresh API (#1120)
Browse files Browse the repository at this point in the history
  • Loading branch information
paullatzelsperger authored Mar 12, 2024
1 parent 88db876 commit 3c9e166
Show file tree
Hide file tree
Showing 16 changed files with 730 additions and 24 deletions.
1 change: 1 addition & 0 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ maven/mavencentral/org.eclipse.edc/data-plane-http-oauth2-core/0.5.2-SNAPSHOT, A
maven/mavencentral/org.eclipse.edc/data-plane-http-oauth2/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/data-plane-http-spi/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/data-plane-http/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/data-plane-public-api-v2/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/data-plane-public-api/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/data-plane-selector-core/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
maven/mavencentral/org.eclipse.edc/data-plane-selector-spi/0.5.2-SNAPSHOT, Apache-2.0, approved, technology.edc
Expand Down
5 changes: 4 additions & 1 deletion edc-dataplane/edc-dataplane-base/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
runtimeOnly(project(":edc-extensions:dataplane:dataplane-proxy:edc-dataplane-proxy-provider-api"))
runtimeOnly(project(":edc-extensions:dataplane:dataplane-proxy:edc-dataplane-proxy-provider-core"))
runtimeOnly(project(":edc-extensions:dataplane:dataplane-token-refresh:token-refresh-core"))
runtimeOnly(project(":edc-extensions:dataplane:dataplane-token-refresh:token-refresh-api"))

runtimeOnly(libs.edc.jsonld) // needed by the DataPlaneSignalingApi
runtimeOnly(libs.edc.identity.core.did) // for the DID Public Key Resolver
Expand All @@ -43,7 +44,9 @@ dependencies {

runtimeOnly(libs.edc.dpf.api.control)
runtimeOnly(libs.edc.dpf.api.signaling)
runtimeOnly(libs.edc.dpf.api.public)

runtimeOnly(libs.edc.dpf.api.public.v1)
runtimeOnly(libs.edc.dpf.api.public.v2)
runtimeOnly(libs.edc.core.connector)
runtimeOnly(libs.edc.boot)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft
*
* 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
*/

plugins {
`java-library`
`maven-publish`
id("io.swagger.core.v3.swagger-gradle-plugin")
}

dependencies {
api(project(":spi:tokenrefresh-spi"))
implementation(libs.edc.spi.core)
implementation(libs.edc.spi.web)
implementation(libs.jakarta.rsApi)

testImplementation(libs.edc.junit)
testImplementation(libs.restAssured)
testImplementation(testFixtures(libs.edc.core.jersey))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft
*
* 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.dataplane.tokenrefresh.api;

import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.system.ServiceExtension;
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 static org.eclipse.tractusx.edc.dataplane.tokenrefresh.api.TokenRefreshApiExtension.NAME;

@Extension(value = NAME)
public class TokenRefreshApiExtension implements ServiceExtension {

public static final String NAME = "DataPlane Token Refresh API Extension";
private static final String PUBLIC_API_CONTEXT = "public";
@Inject
private DataPlaneTokenRefreshService refreshService;

@Inject
private WebService webService;

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

@Override
public void initialize(ServiceExtensionContext context) {
var controller = new TokenRefreshApiController(refreshService);
webService.registerResource(PUBLIC_API_CONTEXT, controller);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft
*
* 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.dataplane.tokenrefresh.api.v1;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
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;

@SecurityScheme(name = "Authentication",
description = "Self-Issued ID token containing an access_token",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT")
@OpenAPIDefinition(info = @Info(description = "With this API clients can refresh their access token for a provider's HTTP data plane using an authentication token and a refresh token.", title = "Token Refresh API"))
@Tag(name = "Token Refresh API")
public interface TokenRefreshApi {

@Operation(description = "Resolves all groups for a particular BPN",
parameters = { @Parameter(name = "grant_type", description = "The grant type. Must be \"refresh_token\""),
@Parameter(name = "refresh_token", description = "The refresh token") },
responses = {
@ApiResponse(responseCode = "200", description = "The access token and refresh token were updated. Expiry should be " +
"interpreted as starting from the time of message reception, allowing for some leeway.",
content = @Content(schema = @Schema(implementation = TokenResponse.class))),
@ApiResponse(responseCode = "401", description = "The token could not be refreshed due to an authentication error, either the refresh token or the Authorization header were invalid.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)))),
@ApiResponse(responseCode = "400", description = "Request body was malformed, query parameters were missing, etc.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class))))
})
TokenResponse refreshToken(String grantType, String refreshToken, String bearerToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft
*
* 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.dataplane.tokenrefresh.api.v1;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
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 static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION;

@Produces({ MediaType.APPLICATION_JSON })
@Path("/token")
public class TokenRefreshApiController implements TokenRefreshApi {
private static final String REFRESH_TOKEN_GRANT = "refresh_token";
private final DataPlaneTokenRefreshService tokenRefreshService;

public TokenRefreshApiController(DataPlaneTokenRefreshService tokenRefreshService) {
this.tokenRefreshService = tokenRefreshService;
}

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Override
public TokenResponse refreshToken(@QueryParam("grant_type") String grantType,
@QueryParam("refresh_token") String refreshToken,
@HeaderParam(AUTHORIZATION) String bearerToken) {
if (!REFRESH_TOKEN_GRANT.equals(grantType)) {
throw new InvalidRequestException("Grant type MUST be '%s' but was '%s'".formatted(REFRESH_TOKEN_GRANT, grantType));
}

return tokenRefreshService.refreshToken(refreshToken, bearerToken)
.orElseThrow(f -> new AuthenticationFailedException(f.getFailureDetail()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#################################################################################
# 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
#################################################################################

org.eclipse.tractusx.edc.dataplane.tokenrefresh.api.TokenRefreshApiExtension
Loading

0 comments on commit 3c9e166

Please sign in to comment.