Skip to content

Commit

Permalink
[FIXES #2971] MapStore - SSO keycloak kerberos (#356)
Browse files Browse the repository at this point in the history
  • Loading branch information
afabiani authored Jul 9, 2024
1 parent 16bbce6 commit be62769
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -48,17 +50,21 @@
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;

/**
* 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);
Expand Down Expand Up @@ -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.");
}
Expand All @@ -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);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit be62769

Please sign in to comment.