Skip to content

Commit 6b28c9b

Browse files
jonenstsBouzols
andauthored
Allow to optionally send idtokens to user-identity-server for identity replication (#111)
Signed-off-by: Jon Harper <> Co-authored-by: sBouzols <[email protected]>
1 parent 1e9146b commit 6b28c9b

File tree

6 files changed

+78
-2
lines changed

6 files changed

+78
-2
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,7 @@ public class ServiceURIsConfig {
113113

114114
@Value("${gridsuite.services.spreadsheet-config-server.base-uri:http://spreadsheet-config-server/}")
115115
String spreadsheetConfigServerBaseUri;
116+
117+
@Value("${gridsuite.services.user-identity-server.base-uri:http://user-identity-server/}")
118+
String userIdentityServerBaseUri;
116119
}

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import lombok.Getter;
2121
import org.gridsuite.gateway.GatewayService;
2222
import org.gridsuite.gateway.dto.TokenIntrospection;
23+
import org.gridsuite.gateway.services.UserIdentityService;
2324
import org.slf4j.Logger;
2425
import org.slf4j.LoggerFactory;
2526
import org.springframework.beans.factory.annotation.Value;
@@ -56,14 +57,19 @@ public class TokenValidatorGlobalPreFilter extends AbstractGlobalPreFilter {
5657
public static final String UNAUTHORIZED_THE_TOKEN_CANNOT_BE_TRUSTED = "{}: 401 Unauthorized, The token cannot be trusted";
5758
public static final String CACHE_OUTDATED = "{}: Bad JSON Object Signing and Encryption, cache outdated";
5859
private final GatewayService gatewayService;
60+
private final UserIdentityService userIdentityService;
5961

6062
@Value("${allowed-issuers}")
6163
private List<String> allowedIssuers;
6264

65+
@Value("${storeIdToken:false}")
66+
private boolean storeIdTokens;
67+
6368
private Map<String, JWKSet> jwkSetCache = new ConcurrentHashMap<>();
6469

65-
public TokenValidatorGlobalPreFilter(GatewayService gatewayService) {
70+
public TokenValidatorGlobalPreFilter(GatewayService gatewayService, UserIdentityService userIdentityService) {
6671
this.gatewayService = gatewayService;
72+
this.userIdentityService = userIdentityService;
6773
}
6874

6975
@Override
@@ -159,6 +165,21 @@ private Mono<Void> validate(FilterInfos filterInfos, JWKSet jwkset) throws BadJO
159165
// we can safely trust the JWT
160166
LOGGER.debug("JWT Token verified, it can be trusted");
161167

168+
// TODO how do we differentiate between JWT Access Token (no user information)
169+
// and JWT ID tokens with little or no user information for which we use
170+
// defaults like the sub. Do we need the storage server to always accumulate
171+
// the data to guard against access token clearing data from a previous id token ?
172+
// or do we need an explicit endpoint where our front sends idtoken (the frontend knows
173+
// whether it has requested an access token or and id token) ? but then we maybe miss
174+
// some tokens if for some reason the frontend doesn't send the token, whereas here
175+
// we are guaranteed that we receive the token.
176+
if (storeIdTokens) {
177+
userIdentityService.storeToken(filterInfos.getJwtClaimsSet().getSubject(), filterInfos.getJwtClaimsSet())
178+
// send in the background and don't wait for the result. This is the hot path on
179+
// all requests !
180+
.subscribe();
181+
}
182+
162183
//we add the subject header
163184
filterInfos.getExchange().getRequest()
164185
.mutate()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (c) 2024, 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+
14+
import com.nimbusds.jwt.JWTClaimsSet;
15+
16+
import reactor.core.publisher.Mono;
17+
18+
/**
19+
* @author Jon Schuhmacher <jon.harper at rte-france.com>
20+
*/
21+
@Service
22+
public class UserIdentityService {
23+
24+
private static final String USER_IDENTITY_SERVER_API_VERSION = "v1";
25+
26+
private static final String DELIMITER = "/";
27+
28+
private static final String USER_IDENTITY_SERVER_STORE_PATH = DELIMITER + USER_IDENTITY_SERVER_API_VERSION + DELIMITER
29+
+ "users/identities/";
30+
31+
private final WebClient webClient;
32+
33+
@Autowired
34+
public UserIdentityService(ServiceURIsConfig servicesURIsConfig, WebClient.Builder webClientBuilder) {
35+
this.webClient = webClientBuilder.baseUrl(servicesURIsConfig.getUserIdentityServerBaseUri()).build();
36+
}
37+
38+
// NOTE: this API actually responds with the parsed identity but we don't use it here
39+
public Mono<Void> storeToken(String sub, JWTClaimsSet jwtClaimsSet) {
40+
return webClient.put()
41+
.uri(uriBuilder -> uriBuilder
42+
.path(USER_IDENTITY_SERVER_STORE_PATH + DELIMITER + sub)
43+
.build()
44+
).bodyValue(jwtClaimsSet.getClaims()).retrieve().bodyToMono(Void.class);
45+
}
46+
47+
}

src/main/resources/application-local.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,7 @@ gridsuite:
6767
state-estimation-orchestrator-server:
6868
base-uri: http://localhost:5041
6969
spreadsheet-config-server:
70-
base-uri: http://localhost:5035
70+
base-uri: http://localhost:5035
71+
user-identity-server:
72+
base-uri: http://localhost:5034
73+

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"gridsuite.services.network-modification-server.base-uri=http://localhost:${wiremock.server.port}",
7171
"gridsuite.services.user-admin-server.base-uri=http://localhost:${wiremock.server.port}",
7272
"gridsuite.services.sensitivity-analysis-server.base-uri=http://localhost:${wiremock.server.port}",
73+
"gridsuite.services.user-identity-server.base-uri=http://localhost:${wiremock.server.port}",
7374
"allowed-issuers=http://localhost:${wiremock.server.port}"
7475
})
7576
@AutoConfigureWireMock(port = 0)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
allowed-issuers: http://localhost
22
client_id: gridsuite
33
client_secret: secret
4+
storeIdToken: true

0 commit comments

Comments
 (0)