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 14be9c20..90aae1d9 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 @@ -76,7 +76,6 @@ public GeoStoreKeycloakAuthProvider(KeyCloakConfiguration configuration) { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication; OidcKeycloakAccount account = token.getAccount(); KeycloakSecurityContext context = account.getKeycloakSecurityContext(); @@ -127,7 +126,7 @@ public Authentication authenticate(Authentication authentication) User user = retrieveUser(username, "", grantedAuthoritiesMapper, keycloakGroups); addEveryOne(user.getGroups()); if (user.getRole() == null) { - // no role get the one configured to be default for authenticated users. + // no role gets the one configured to be default for authenticated users. Role defRole = configuration.getAuthenticatedDefaultRole(); user.setRole(defRole); } 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 c7289993..d89fd354 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 @@ -29,14 +29,16 @@ import static it.geosolutions.geostore.services.rest.SessionServiceDelegate.PROVIDER_KEY; import static it.geosolutions.geostore.services.rest.security.keycloak.KeyCloakLoginService.KEYCLOAK_REDIRECT; -import static it.geosolutions.geostore.services.rest.security.oauth2.OAuth2Utils.ACCESS_TOKEN_PARAM; -import static it.geosolutions.geostore.services.rest.security.oauth2.OAuth2Utils.REFRESH_TOKEN_PARAM; +import static it.geosolutions.geostore.services.rest.security.oauth2.OAuth2Utils.*; +import static it.geosolutions.geostore.services.rest.security.oauth2.OAuth2Utils.getResponse; import it.geosolutions.geostore.services.UserService; import it.geosolutions.geostore.services.rest.security.TokenAuthenticationCache; import it.geosolutions.geostore.services.rest.security.oauth2.OAuth2Utils; +import it.geosolutions.geostore.services.rest.utils.GeoStoreContext; import java.io.IOException; import java.util.Date; +import java.util.Objects; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -48,10 +50,13 @@ import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.RequestAuthenticator; import org.keycloak.adapters.spi.AuthOutcome; +import org.keycloak.adapters.spi.HttpFacade; +import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.filter.GenericFilterBean; @@ -59,6 +64,7 @@ * Keycloak Authentication Filter. Manage the logic to authenticate a user against a keycloak * server. */ +@SuppressWarnings("PMD.UnusedLocalVariable") public class KeyCloakFilter extends GenericFilterBean { private static final Logger LOGGER = LogManager.getLogger(KeyCloakFilter.class); @@ -144,8 +150,8 @@ protected Authentication authenticateAndUpdateCache( } else { entryPoint = new KeycloakAuthenticationEntryPoint(authenticator.getChallenge()); } - RequestContextHolder.getRequestAttributes() - .setAttribute(KEYCLOAK_REDIRECT, entryPoint, 0); + Objects.requireNonNull(RequestContextHolder.getRequestAttributes()) + .setAttribute(KEYCLOAK_REDIRECT, entryPoint, RequestAttributes.SCOPE_REQUEST); } else { LOGGER.warn("Failed to authentication and to redirect the user."); } @@ -160,10 +166,16 @@ protected Authentication authenticateAndUpdateCache( protected void updateCache(Authentication authentication) { Object details = authentication.getDetails(); if (details instanceof KeycloakTokenDetails) { + KeyCloakHelper helper = GeoStoreContext.bean(KeyCloakHelper.class); KeycloakTokenDetails keycloakDetails = (KeycloakTokenDetails) details; String accessToken = keycloakDetails.getAccessToken(); if (accessToken != null) { cache.putCacheEntry(accessToken, authentication); + if (helper != null) { + HttpFacade facade = new SimpleHttpFacade(getRequest(), getResponse()); + KeycloakDeployment deployment = helper.getDeployment(facade); + KeycloakCookieUtils.setTokenCookie(deployment, facade, keycloakDetails); + } } } } diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakLoginService.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakLoginService.java index 3d925ea6..77f9d976 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakLoginService.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeyCloakLoginService.java @@ -33,6 +33,7 @@ import it.geosolutions.geostore.services.rest.IdPLoginRest; import it.geosolutions.geostore.services.rest.security.oauth2.Oauth2LoginService; import java.io.IOException; +import java.util.Objects; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.Response; @@ -41,11 +42,12 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; /** * Keycloak implementation for a LoginService. Since keycloak redirects to the url from which the - * call to the authorization page was issued no internal redirect is really performed here. + * call to the authorization page was issued, no internal redirect is really performed here. */ public class KeyCloakLoginService extends Oauth2LoginService { @@ -59,18 +61,25 @@ public KeyCloakLoginService(IdPLoginRest loginRest) { @Override public void doLogin(HttpServletRequest request, HttpServletResponse response, String provider) { + KeycloakTokenDetails details = getDetails(); + boolean attempInternalRedirect = (details != null && details.getAccessToken() != null); + AuthenticationEntryPoint challenge = (AuthenticationEntryPoint) - RequestContextHolder.getRequestAttributes() - .getAttribute(KEYCLOAK_REDIRECT, 0); - if (challenge != null) { + Objects.requireNonNull(RequestContextHolder.getRequestAttributes()) + .getAttribute(KEYCLOAK_REDIRECT, RequestAttributes.SCOPE_REQUEST); + if (challenge == null) attempInternalRedirect = true; + else if (!attempInternalRedirect) { try { challenge.commence(request, response, null); + attempInternalRedirect = false; } catch (Exception e) { LOGGER.error("Error while redirecting to Keycloak authorization.", e); throw new RuntimeException(e); } - } else { + } + + if (attempInternalRedirect) { try { response.sendRedirect(configuration(provider).getInternalRedirectUri()); } catch (IOException e) { diff --git a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeycloakCookieUtils.java b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeycloakCookieUtils.java index 6fe3b1fa..9eae50f2 100644 --- a/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeycloakCookieUtils.java +++ b/src/modules/rest/impl/src/main/java/it/geosolutions/geostore/services/rest/security/keycloak/KeycloakCookieUtils.java @@ -45,7 +45,7 @@ static void setTokenCookie( String cookie = accessToken + SEPARATOR + idToken + SEPARATOR + refreshToken; String cookiePath = getCookiePath(deployment, facade); - // forces the expiration of the old keycloak cookie after refresh token. Keycloak doesn't do + // Forces the expiration of the old keycloak cookie after refresh token. Keycloak doesn't do // it for us. facade.getResponse() .setCookie(