From 64d9ae96836d246f3fc1a1b6101f6dfa174218dd Mon Sep 17 00:00:00 2001 From: Alessio Fabiani Date: Thu, 10 Oct 2024 17:26:45 +0200 Subject: [PATCH] [FIXES #2408] C206-DEUTSCHE_BAHN-2023-SUPPORT - SSO - Supported OpenID services (#372) (#374) (cherry picked from commit 8132a81864a28c5995f107ebfb271ed8222a1a46) --- .../GeoStoreKeycloakAuthProvider.java | 2 +- .../security/keycloak/KeyCloakFilter.java | 2 +- .../security/oauth2/OAuth2Configuration.java | 2 +- .../OAuth2GeoStoreAuthenticationFilter.java | 4 +- .../OAuth2GeoStoreSecurityConfiguration.java | 4 +- .../oauth2/OAuth2SessionServiceDelegate.java | 40 ++++++++++++++----- .../openid_connect/OpenIdConnectFilter.java | 5 ++- .../OpenIdConnectSecurityConfiguration.java | 4 +- .../OpenIdConnectIntegrationTest.java | 2 +- 9 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/GeoStoreKeycloakAuthProvider.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/GeoStoreKeycloakAuthProvider.java index 90aae1d9..c135d78b 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/GeoStoreKeycloakAuthProvider.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/GeoStoreKeycloakAuthProvider.java @@ -86,7 +86,7 @@ public Authentication authenticate(Authentication authentication) HttpServletRequest request = getRequest(); // set tokens as request attributes so that can made available in a cookie for the frontend // on the callback url. - if (accessToken != null) { + if (accessToken != null && !accessToken.isExpired()) { expiration = accessToken.getExp(); if (request != null) request.setAttribute(ACCESS_TOKEN_PARAM, accessToken); } diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakFilter.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakFilter.java index d89fd354..e61053e4 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakFilter.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakFilter.java @@ -169,7 +169,7 @@ protected void updateCache(Authentication authentication) { KeyCloakHelper helper = GeoStoreContext.bean(KeyCloakHelper.class); KeycloakTokenDetails keycloakDetails = (KeycloakTokenDetails) details; String accessToken = keycloakDetails.getAccessToken(); - if (accessToken != null) { + if (accessToken != null && !accessToken.isEmpty()) { cache.putCacheEntry(accessToken, authentication); if (helper != null) { HttpFacade facade = new SimpleHttpFacade(getRequest(), getResponse()); diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2Configuration.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2Configuration.java index aeee55fa..9e4b4ddf 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2Configuration.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2Configuration.java @@ -422,7 +422,7 @@ private static HttpHeaders getHeaders(String accessToken, OAuth2Configuration co configuration.clientId, configuration .clientSecret); // Set client ID and client secret for authentication - else if (accessToken != null) { + else if (accessToken != null && !accessToken.isEmpty()) { headers.set("Authorization", "Bearer " + accessToken); } return headers; diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreAuthenticationFilter.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreAuthenticationFilter.java index 27ab982c..210238e3 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreAuthenticationFilter.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreAuthenticationFilter.java @@ -304,7 +304,9 @@ protected String getPreAuthenticatedPrincipal( LOGGER.debug("About to configure the REST Resource Template"); configureRestTemplate(); - if (accessToken != null) { + if (accessToken != null + && accessToken.getValue() != null + && !accessToken.getValue().isEmpty()) { LOGGER.debug("Setting the access token on the OAuth2ClientContext"); restTemplate.getOAuth2ClientContext().setAccessToken(accessToken); } diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreSecurityConfiguration.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreSecurityConfiguration.java index 87166205..6b7e7ffb 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreSecurityConfiguration.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2GeoStoreSecurityConfiguration.java @@ -54,8 +54,8 @@ import org.springframework.security.oauth2.common.AuthenticationScheme; /** - * Base abstract class for @Configuration classes providing needed beans from the Spring OAuth2 - * mechanism. + * Base abstract class for @Configuration classes providing the necessary beans from the Spring + * OAuth2 mechanism. */ @Configuration public abstract class OAuth2GeoStoreSecurityConfiguration implements ApplicationContextAware { diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2SessionServiceDelegate.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2SessionServiceDelegate.java index 2e83f821..8cbad1aa 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2SessionServiceDelegate.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/OAuth2SessionServiceDelegate.java @@ -56,6 +56,7 @@ import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -90,7 +91,8 @@ public SessionToken refresh(String refreshToken, String accessToken) { OAuth2AccessToken currentToken = retrieveAccessToken(accessToken); Date expiresIn = currentToken.getExpiration(); - if (refreshToken == null) refreshToken = getParameterValue(REFRESH_TOKEN_PARAM, request); + if (refreshToken == null || refreshToken.isEmpty()) + refreshToken = getParameterValue(REFRESH_TOKEN_PARAM, request); Date fiveMinutesFromNow = fiveMinutesFromNow(); SessionToken sessionToken = null; OAuth2Configuration configuration = configuration(); @@ -100,15 +102,19 @@ public SessionToken refresh(String refreshToken, String accessToken) { if (LOGGER.isDebugEnabled()) LOGGER.info("Going to refresh the token."); try { sessionToken = doRefresh(refreshToken, accessToken, configuration); - if (sessionToken == null) - sessionToken = - sessionToken( - accessToken, refreshToken, currentToken.getExpiration()); } catch (NullPointerException npe) { LOGGER.error("Current configuration wasn't correctly initialized."); } } } + if (sessionToken == null) + sessionToken = sessionToken(accessToken, refreshToken, currentToken.getExpiration()); + + request.setAttribute( + OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, sessionToken.getAccessToken()); + request.setAttribute( + OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, sessionToken.getTokenType()); + return sessionToken; } @@ -131,6 +137,7 @@ protected SessionToken doRefresh( requestBody.add("grant_type", "refresh_token"); requestBody.add("refresh_token", refreshToken); requestBody.add("client_secret", configuration.getClientSecret()); + requestBody.add("client_id", configuration.getClientId()); HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); @@ -151,9 +158,21 @@ protected SessionToken doRefresh( LOGGER.error("Error trying to obtain a refresh token.", ex); } - if (newToken != null && newToken.getValue() != null) { + if (refreshToken != null + && accessToken != null + && !refreshToken.isEmpty() + && !accessToken.isEmpty() + && newToken != null + && newToken.getValue() != null + && !newToken.getValue().isEmpty()) { // update the Authentication - updateAuthToken(accessToken, newToken, refreshToken, configuration); + String newRefreshToken = + newToken.getRefreshToken() != null + && newToken.getRefreshToken().getValue() != null + && !newToken.getRefreshToken().getValue().isEmpty() + ? newToken.getRefreshToken().getValue() + : refreshToken; + updateAuthToken(accessToken, newToken, newRefreshToken, configuration); sessionToken = sessionToken(newToken.getValue(), refreshToken, newToken.getExpiration()); } else if (accessToken != null) { @@ -190,7 +209,7 @@ private static HttpHeaders getHttpHeaders( configuration.clientId, configuration .clientSecret); // Set client ID and client secret for authentication - else if (accessToken != null) { + else if (accessToken != null && !accessToken.isEmpty()) { headers.set("Authorization", "Bearer " + accessToken); } headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // Set content type @@ -321,7 +340,10 @@ public void doLogout(String sessionId) { OAuth2Configuration configuration = configuration(); if (configuration != null && configuration.isEnabled()) { - if (token != null && accessToken != null) { + if (token != null + && accessToken != null + && !token.isEmpty() + && !accessToken.isEmpty()) { if (configuration.isGlobalLogoutEnabled()) doLogoutInternal(token, configuration, accessToken); if (configuration.getRevokeEndpoint() != null) clearSession(restTemplate, request); diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectFilter.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectFilter.java index ed101082..56f9975d 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectFilter.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectFilter.java @@ -91,7 +91,10 @@ protected String getPreAuthenticatedPrincipal( } // we must validate String token = null; - if (accessToken != null) { + if (accessToken != null + && !accessToken.isExpired() + && accessToken.getValue() != null + && !accessToken.getValue().isEmpty()) { token = accessToken.getValue(); } else { token = (String) req.getAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE); diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectSecurityConfiguration.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectSecurityConfiguration.java index 8d4513e6..aac956fe 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectSecurityConfiguration.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/oauth2/openid_connect/OpenIdConnectSecurityConfiguration.java @@ -141,7 +141,7 @@ public OpenIdConnectFilter oidcOpenIdFilter() { oidcTokenServices(), oauth2RestTemplate(), configuration(), - oidcCache(), + oAuth2Cache(), openIdConnectBearerTokenValidator()); } @@ -157,7 +157,7 @@ public OpenIdConnectTokenServices oidcTokenServices() { } @Bean - public TokenAuthenticationCache oidcCache() { + public TokenAuthenticationCache oAuth2Cache() { return new TokenAuthenticationCache(); } } diff --git a/src/modules/rest/impl/src/test/java/it/geosolutions/geostore/rest/security/oauth2/openid_connect/OpenIdConnectIntegrationTest.java b/src/modules/rest/impl/src/test/java/it/geosolutions/geostore/rest/security/oauth2/openid_connect/OpenIdConnectIntegrationTest.java index 7e98249f..981778cb 100644 --- a/src/modules/rest/impl/src/test/java/it/geosolutions/geostore/rest/security/oauth2/openid_connect/OpenIdConnectIntegrationTest.java +++ b/src/modules/rest/impl/src/test/java/it/geosolutions/geostore/rest/security/oauth2/openid_connect/OpenIdConnectIntegrationTest.java @@ -153,7 +153,7 @@ public OAuth2Configuration configuration() { securityConfiguration.oidcTokenServices(), restTemplate, configuration, - securityConfiguration.oidcCache(), + securityConfiguration.oAuth2Cache(), securityConfiguration.openIdConnectBearerTokenValidator()); }