Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIXES #2971] MapStore - SSO keycloak kerberos #360

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ public GeoStoreKeycloakAuthProvider(KeyCloakConfiguration configuration) {
}

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication;
OidcKeycloakAccount account = token.getAccount();
KeycloakSecurityContext context = account.getKeycloakSecurityContext();
Expand Down Expand Up @@ -130,7 +130,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
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 @@ -27,19 +27,37 @@
*/
package it.geosolutions.geostore.services.rest.security.keycloak;

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.*;
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;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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;

Expand All @@ -52,15 +70,10 @@
import java.io.IOException;
import java.util.Date;


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;

/**
* Keycloak Authentication Filter. Manage the logic to authenticate a user against a keycloak server.
*/
@SuppressWarnings("PMD.UnusedLocalVariable")
public class KeyCloakFilter extends GenericFilterBean {


Expand Down Expand Up @@ -140,7 +153,9 @@ protected Authentication authenticateAndUpdateCache(HttpServletRequest request,
} 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 @@ -151,13 +166,19 @@ protected Authentication authenticateAndUpdateCache(HttpServletRequest request,
* Updates the cache with the new Authentication entry.
* @param authentication the new Authentication entry.
*/
protected void updateCache(Authentication authentication){
Object details=authentication.getDetails();
if (details instanceof KeycloakTokenDetails){
KeycloakTokenDetails keycloakDetails=(KeycloakTokenDetails) details;
String accessToken=keycloakDetails.getAccessToken();
if (accessToken!=null){
cache.putCacheEntry(accessToken,authentication);
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 @@ -30,11 +30,18 @@
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;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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 javax.servlet.http.HttpServletRequest;
Expand All @@ -47,9 +54,8 @@
import static it.geosolutions.geostore.services.rest.security.oauth2.OAuth2Utils.getRefreshAccessToken;

/**
* 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.
* 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.
*/
public class KeyCloakLoginService extends Oauth2LoginService {

Expand All @@ -64,16 +70,25 @@ public KeyCloakLoginService(IdPLoginRest loginRest) {

@Override
public void doLogin(HttpServletRequest request, HttpServletResponse response, String provider) {
AuthenticationEntryPoint challenge = (AuthenticationEntryPoint) RequestContextHolder.getRequestAttributes()
.getAttribute(KEYCLOAK_REDIRECT, 0);
if (challenge != null) {
KeycloakTokenDetails details = getDetails();
boolean attempInternalRedirect = (details != null && details.getAccessToken() != null);

AuthenticationEntryPoint challenge =
(AuthenticationEntryPoint)
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 @@ -51,8 +51,18 @@ static void setTokenCookie(KeycloakDeployment deployment, HttpFacade facade, Key
.append(refreshToken).toString();

String cookiePath = getCookiePath(deployment, facade);
// forces the expiration of the old keycloak cookie after refresh token. Keycloak doesn't do it for us.
facade.getResponse().setCookie(AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE, cookie, cookiePath, null, 0, deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr()), true);

// Forces the expiration of the old keycloak cookie after refresh token. Keycloak doesn't do
// it for us.
facade.getResponse()
.setCookie(
AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE,
cookie,
cookiePath,
null,
0,
deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr()),
true);
}

static String getCookiePath(KeycloakDeployment deployment, HttpFacade facade) {
Expand Down
Loading