Skip to content

Commit 4b6b175

Browse files
authored
simple-ui: improve the oidc id token refresh (#2534)
* simple-ui: improve the oidc id token refresh * make sure we get the latest context after refresh * further simplification of the method * remove principal oidc check * remove relying on previous oidcuser, as the infinite loop was fixed on spring security * simplify the granted authorities fetch * rollback some changes to simplify review * lint
1 parent 9b121b3 commit 4b6b175

File tree

2 files changed

+15
-42
lines changed

2 files changed

+15
-42
lines changed

hawkbit-simple-ui/src/main/java/org/eclipse/hawkbit/ui/simple/SimpleUIApp.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ public class SimpleUIApp implements AppShellConfigurator {
5858

5959
private static final Function<OAuth2TokenManager, RequestInterceptor> AUTHORIZATION = oAuth2TokenManager -> requestTemplate -> {
6060
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
61-
if (oAuth2TokenManager != null && authentication instanceof OAuth2AuthenticationToken oAuth2AuthenticationToken) {
62-
String bearerToken = oAuth2TokenManager.getToken(oAuth2AuthenticationToken);
61+
if (authentication instanceof OAuth2AuthenticationToken authenticationToken) {
62+
String bearerToken = oAuth2TokenManager.getToken(authenticationToken);
6363
requestTemplate.header("Authorization", "Bearer " + bearerToken);
6464
} else {
6565
requestTemplate.header(
@@ -108,16 +108,14 @@ HawkbitMgmtClient hawkbitMgmtClient(final Tenant tenant, final HawkbitClient haw
108108
@Bean
109109
OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService(final HawkbitMgmtClient hawkbitClient) {
110110
final OidcUserService delegate = new OidcUserService();
111-
return userRequest -> {
111+
return (userRequest) -> {
112112
OidcUser oidcUser = delegate.loadUser(userRequest);
113-
114113
final OAuth2AuthenticationToken tempToken = new OAuth2AuthenticationToken(
115114
oidcUser,
116115
emptyList(),
117116
userRequest.getClientRegistration().getRegistrationId()
118117
);
119-
final List<SimpleGrantedAuthority> grantedAuthorities =
120-
getGrantedAuthorities(hawkbitClient, tempToken);
118+
final List<SimpleGrantedAuthority> grantedAuthorities = getGrantedAuthorities(hawkbitClient, tempToken);
121119
return new DefaultOidcUser(
122120
grantedAuthorities,
123121
oidcUser.getIdToken(),

hawkbit-simple-ui/src/main/java/org/eclipse/hawkbit/ui/simple/security/OAuth2TokenManager.java

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,73 +10,48 @@
1010
package org.eclipse.hawkbit.ui.simple.security;
1111

1212
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
13+
import org.springframework.security.core.context.SecurityContext;
14+
import org.springframework.security.core.context.SecurityContextHolder;
1315
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
1416
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
1517
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
1618
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
1719
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
18-
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
19-
import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
20-
import org.springframework.security.oauth2.client.endpoint.RestClientRefreshTokenTokenResponseClient;
21-
import org.springframework.security.oauth2.client.registration.ClientRegistration;
22-
import org.springframework.security.oauth2.core.OAuth2AccessToken;
23-
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
24-
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
2520
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
2621
import org.springframework.stereotype.Component;
2722

28-
import java.util.Optional;
29-
3023
@Component
3124
@ConditionalOnProperty(prefix = "hawkbit.server.security.oauth2.client", name = "enabled")
3225
public class OAuth2TokenManager {
3326

3427
private final OAuth2AuthorizedClientService clientService;
3528
private final OAuth2AuthorizedClientManager clientManager;
36-
private final OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> tokenResponseClient;
3729

3830
OAuth2TokenManager(
3931
final OAuth2AuthorizedClientService clientService,
4032
final OAuth2AuthorizedClientManager clientManager
4133
) {
4234
this.clientService = clientService;
4335
this.clientManager = clientManager;
44-
this.tokenResponseClient = new RestClientRefreshTokenTokenResponseClient();
4536
}
4637

4738
public String getToken(final OAuth2AuthenticationToken authentication) {
48-
return Optional.ofNullable(authorizedToken(authentication)).orElse(
49-
((DefaultOidcUser) authentication.getPrincipal()).getIdToken().getTokenValue()
50-
);
51-
}
52-
53-
/**
54-
* Tries to refresh the id token if it is expired and adds it to the request.
55-
*/
56-
private String authorizedToken(final OAuth2AuthenticationToken authentication) {
39+
final String currentToken = ((DefaultOidcUser) authentication.getPrincipal()).getIdToken().getTokenValue();
5740
String registrationId = authentication.getAuthorizedClientRegistrationId();
58-
OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest.withClientRegistrationId(registrationId).principal(authentication).build();
5941

6042
// This ensures that there is a client already, otherwise we won't be able to call the manager for authorization
6143
OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(registrationId, authentication.getName());
62-
if (authorizedClient == null) return null;
44+
if (authorizedClient == null) return currentToken;
6345

6446
// Will ensure that the token is refreshed if needed; do not rely on it being not null as it won't be available
6547
// during the first calls made to get the rights and generate the authorities
66-
OAuth2AuthorizedClient refreshClient = clientManager.authorize(request);
67-
if (refreshClient == null) return null;
68-
69-
// A small trick to refresh the token if it is expired; the current spring version does not refresh the ID Token when the Access Token is refreshed
70-
// This won't be necessary after Spring Security 6.5; cf. https://github.com/spring-projects/spring-security/pull/16589
71-
OAuth2AccessToken accessToken = refreshClient.getAccessToken();
72-
OAuth2RefreshToken refreshToken = refreshClient.getRefreshToken();
73-
ClientRegistration clientRegistration = refreshClient.getClientRegistration();
74-
// if this is null, please request it via the scopes
75-
if (refreshToken == null) return null;
48+
OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest.withClientRegistrationId(registrationId).principal(authentication).build();
49+
// since Spring Security 6.5 this will trigger a refresh of the id token
50+
authorizedClient = clientManager.authorize(request);
51+
if (authorizedClient == null) return currentToken;
7652

77-
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
78-
clientRegistration, accessToken, refreshToken);
79-
OAuth2AccessTokenResponse response = tokenResponseClient.getTokenResponse(refreshTokenGrantRequest);
80-
return (String) response.getAdditionalParameters().get("id_token");
53+
// we need to fetch the newly created context containing the matching token
54+
SecurityContext securityContext = SecurityContextHolder.getContext();
55+
return ((DefaultOidcUser) securityContext.getAuthentication().getPrincipal()).getIdToken().getTokenValue();
8156
}
8257
}

0 commit comments

Comments
 (0)