Skip to content

Commit fa61c50

Browse files
authored
use_user_admin_server (#66)
Signed-off-by: Etienne Homer <[email protected]>
1 parent a1419aa commit fa61c50

File tree

9 files changed

+170
-2
lines changed

9 files changed

+170
-2
lines changed

src/main/java/org/gridsuite/gateway/GatewayConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public RouteLocator myRoutes(RouteLocatorBuilder builder, ApplicationContext con
5050
.route(p -> context.getBean(NetworkConversionServer.class).getRoute(p))
5151
.route(p -> context.getBean(OdreServer.class).getRoute(p))
5252
.route(p -> context.getBean(GeoDataServer.class).getRoute(p))
53+
.route(p -> context.getBean(UserAdminServer.class).getRoute(p))
5354
.route(p -> context.getBean(CgmesGlServer.class).getRoute(p))
5455
.build();
5556
}

src/main/java/org/gridsuite/gateway/ServiceURIsConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public class ServiceURIsConfig {
7878
@Value("${backing-services.geo-data-server.base-uri:http://geo-data-server/}")
7979
String geoDataServerBaseUri;
8080

81+
@Value("${backing-services.user-admin-server.base-uri:http://user-admin-server/}")
82+
String userAdminServerBaseUri;
83+
8184
@Value("${backing-services.cgmes-gl-server.base-uri:http://cgmes-gl-server/}")
8285
String cgmesGlServerBaseUri;
8386
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright (c) 2022, RTE (http://www.rte-france.com)
3+
This Source Code Form is subject to the terms of the Mozilla Public
4+
License, v. 2.0. If a copy of the MPL was not distributed with this
5+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package org.gridsuite.gateway.endpoints;
8+
9+
import org.gridsuite.gateway.ServiceURIsConfig;
10+
import org.springframework.stereotype.Component;
11+
12+
/**
13+
* @author Etienne Homer <etienne.homer at rte-france.com>
14+
*/
15+
@Component(value = UserAdminServer.ENDPOINT_NAME)
16+
public class UserAdminServer implements EndPointElementServer {
17+
18+
public static final String ENDPOINT_NAME = "user-admin";
19+
20+
private final ServiceURIsConfig servicesURIsConfig;
21+
22+
public UserAdminServer(ServiceURIsConfig servicesURIsConfig) {
23+
this.servicesURIsConfig = servicesURIsConfig;
24+
}
25+
26+
@Override
27+
public String getEndpointBaseUri() {
28+
return servicesURIsConfig.getUserAdminServerBaseUri();
29+
}
30+
31+
@Override
32+
public String getEndpointName() {
33+
return ENDPOINT_NAME;
34+
}
35+
}

src/main/java/org/gridsuite/gateway/filters/TokenValidatorGlobalPreFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public TokenValidatorGlobalPreFilter(GatewayService gatewayService) {
6464
@Override
6565
public int getOrder() {
6666
// Before ElementAccessControllerGlobalPreFilter to enforce authentication
67-
return Ordered.LOWEST_PRECEDENCE - 3;
67+
return Ordered.LOWEST_PRECEDENCE - 4;
6868
}
6969

7070
@Override
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Copyright (c) 2022, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package org.gridsuite.gateway.filters;
8+
9+
import lombok.NonNull;
10+
import org.gridsuite.gateway.services.UserAdminService;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
14+
import org.springframework.core.Ordered;
15+
import org.springframework.http.HttpHeaders;
16+
import org.springframework.http.HttpStatus;
17+
import org.springframework.stereotype.Component;
18+
import org.springframework.web.server.ServerWebExchange;
19+
import reactor.core.publisher.Mono;
20+
21+
import java.util.Objects;
22+
23+
import static org.gridsuite.gateway.GatewayConfig.HEADER_USER_ID;
24+
25+
/**
26+
* @author Etienne Homer <etienne.homer at rte-france.com>
27+
*/
28+
@Component
29+
public class UserAdminControlGlobalPreFilter extends AbstractGlobalPreFilter {
30+
private static final Logger LOGGER = LoggerFactory.getLogger(UserAdminControlGlobalPreFilter.class);
31+
32+
private UserAdminService userAdminService;
33+
34+
public UserAdminControlGlobalPreFilter(UserAdminService userAdminService) {
35+
this.userAdminService = userAdminService;
36+
}
37+
38+
@Override
39+
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull GatewayFilterChain chain) {
40+
LOGGER.debug("Filter : {}", getClass().getSimpleName());
41+
42+
HttpHeaders httpHeaders = exchange.getRequest().getHeaders();
43+
String sub = Objects.requireNonNull(httpHeaders.get(HEADER_USER_ID)).get(0);
44+
45+
return userAdminService.userExists(sub).flatMap(userExist -> Boolean.TRUE.equals(userExist) ? chain.filter(exchange) : completeWithCode(exchange, HttpStatus.FORBIDDEN));
46+
}
47+
48+
@Override
49+
public int getOrder() {
50+
return Ordered.LOWEST_PRECEDENCE - 3;
51+
}
52+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Copyright (c) 2022, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package org.gridsuite.gateway.services;
8+
9+
import org.gridsuite.gateway.ServiceURIsConfig;
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.stereotype.Service;
12+
import org.springframework.web.reactive.function.client.WebClient;
13+
import reactor.core.publisher.Mono;
14+
15+
/**
16+
* @author Etienne Homer <etienne.homer at rte-france.com>
17+
*/
18+
@Service
19+
public class UserAdminService {
20+
21+
private static final String USER_ADMIN_SERVER_API_VERSION = "v1";
22+
23+
private static final String DELIMITER = "/";
24+
25+
private static final String USER_ADMIN_SERVER_ROOT_PATH = DELIMITER + USER_ADMIN_SERVER_API_VERSION + DELIMITER + "users";
26+
27+
private final WebClient webClient;
28+
29+
@Autowired
30+
public UserAdminService(ServiceURIsConfig servicesURIsConfig, WebClient.Builder webClientBuilder) {
31+
this.webClient = webClientBuilder.baseUrl(servicesURIsConfig.getUserAdminServerBaseUri()).build();
32+
}
33+
34+
public Mono<Boolean> userExists(String sub) {
35+
return webClient
36+
.head()
37+
.uri(uriBuilder -> uriBuilder
38+
.path(USER_ADMIN_SERVER_ROOT_PATH + DELIMITER + sub)
39+
.build()
40+
)
41+
.retrieve()
42+
.toBodilessEntity()
43+
.single()
44+
.map(entity -> entity.getStatusCode().value() == 200);
45+
}
46+
}

src/main/resources/application-local.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ backing-services:
4040
base-uri: http://localhost:8090
4141
geo-data-server:
4242
base-uri: http://localhost:8087
43+
user-admin-server:
44+
base-uri: http://localhost:5033
4345
cgmes-gl-server:
4446
base-uri: http://localhost:8095
4547

src/test/java/org/gridsuite/gateway/ElementAccessControlTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"backing-services.study-server.base-uri=http://localhost:${wiremock.server.port}",
4848
"backing-services.actions-server.base-uri=http://localhost:${wiremock.server.port}",
4949
"backing-services.filter-server.base-uri=http://localhost:${wiremock.server.port}",
50+
"backing-services.user-admin-server.base-uri=http://localhost:${wiremock.server.port}",
5051
}
5152
)
5253
@AutoConfigureWireMock(port = 0)
@@ -509,6 +510,12 @@ public void testAccessControlInfos() {
509510
}
510511

511512
private void initStubForJwk() {
513+
stubFor(head(urlEqualTo(String.format("/v1/users/%s", "user1"))).withPort(port)
514+
.willReturn(aResponse().withStatus(200)));
515+
516+
stubFor(head(urlEqualTo(String.format("/v1/users/%s", "user2"))).withPort(port)
517+
.willReturn(aResponse().withStatus(200)));
518+
512519
stubFor(get(urlEqualTo("/.well-known/openid-configuration"))
513520
.willReturn(aResponse()
514521
.withHeader("Content-Type", "application/json")

src/test/java/org/gridsuite/gateway/TokenValidationTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
"backing-services.dynamic-mapping-server.base-uri=http://localhost:${wiremock.server.port}",
6868
"backing-services.filter-server.base-uri=http://localhost:${wiremock.server.port}",
6969
"backing-services.report-server.base-uri=http://localhost:${wiremock.server.port}",
70-
"backing-services.network-modification-server.base-uri=http://localhost:${wiremock.server.port}"
70+
"backing-services.network-modification-server.base-uri=http://localhost:${wiremock.server.port}",
71+
"backing-services.user-admin-server.base-uri=http://localhost:${wiremock.server.port}",
7172
})
7273

7374
@AutoConfigureWireMock(port = 0)
@@ -380,6 +381,9 @@ public void testWebsockets() {
380381
}
381382

382383
private void initStubForJwk() {
384+
stubFor(head(urlEqualTo(String.format("/v1/users/%s", "chmits"))).withPort(port)
385+
.willReturn(aResponse().withStatus(200)));
386+
383387
stubFor(get(urlEqualTo("/.well-known/openid-configuration"))
384388
.willReturn(aResponse()
385389
.withHeader("Content-Type", "application/json")
@@ -393,6 +397,9 @@ private void initStubForJwk() {
393397

394398
@Test
395399
public void testJwksUpdate() {
400+
stubFor(head(urlEqualTo(String.format("/v1/users/%s", "chmits"))).withPort(port)
401+
.willReturn(aResponse().withStatus(200)));
402+
396403
stubFor(get(urlEqualTo("/v1/cases"))
397404
.willReturn(aResponse()
398405
.withHeader("Content-Type", "application/json")
@@ -455,6 +462,8 @@ public void testJwksUpdate() {
455462

456463
@Test
457464
public void invalidToken() {
465+
stubFor(head(urlEqualTo(String.format("/v1/users/%s", "chmits"))).withPort(port)
466+
.willReturn(aResponse().withStatus(200)));
458467

459468
stubFor(get(urlEqualTo("/v1/cases"))
460469
.willReturn(aResponse()
@@ -529,6 +538,19 @@ public void invalidToken() {
529538
ws -> ws.receive().then()).doOnSuccess(s -> Assert.fail("Should have thrown"));
530539
}
531540

541+
@Test
542+
public void forbiddenUserTest() {
543+
initStubForJwk();
544+
stubFor(head(urlEqualTo(String.format("/v1/users/%s", "chmits"))).withPort(port)
545+
.willReturn(aResponse().withStatus(204)));
546+
547+
webClient
548+
.get().uri("case/v1/cases")
549+
.header("Authorization", "Bearer " + token)
550+
.exchange()
551+
.expectStatus().isEqualTo(403);
552+
}
553+
532554
@TestConfiguration
533555
static class MyTestConfiguration {
534556
@Bean

0 commit comments

Comments
 (0)