[KEYCLOAK-6547] - AuthenticatedActionsHandler should process responses after identity is established
This commit is contained in:
parent
acc5f5c6d1
commit
7c14a6a503
3 changed files with 115 additions and 4 deletions
|
@ -23,6 +23,7 @@ import org.keycloak.adapters.springsecurity.AdapterDeploymentContextFactoryBean;
|
||||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
|
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
|
||||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
|
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
|
||||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakLogoutHandler;
|
import org.keycloak.adapters.springsecurity.authentication.KeycloakLogoutHandler;
|
||||||
|
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter;
|
||||||
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;
|
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;
|
||||||
import org.keycloak.adapters.springsecurity.filter.KeycloakCsrfRequestMatcher;
|
import org.keycloak.adapters.springsecurity.filter.KeycloakCsrfRequestMatcher;
|
||||||
import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter;
|
import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter;
|
||||||
|
@ -120,6 +121,7 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
|
||||||
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
|
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
|
||||||
.addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
|
.addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
|
||||||
.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
|
.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
|
||||||
|
.addFilterAfter(keycloakAuthenticatedActionsRequestFilter(), KeycloakSecurityContextRequestFilter.class)
|
||||||
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
|
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
|
||||||
.and()
|
.and()
|
||||||
.logout()
|
.logout()
|
||||||
|
@ -132,4 +134,9 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
|
||||||
protected KeycloakSecurityContextRequestFilter keycloakSecurityContextRequestFilter() {
|
protected KeycloakSecurityContextRequestFilter keycloakSecurityContextRequestFilter() {
|
||||||
return new KeycloakSecurityContextRequestFilter();
|
return new KeycloakSecurityContextRequestFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
protected KeycloakAuthenticatedActionsFilter keycloakAuthenticatedActionsRequestFilter() {
|
||||||
|
return new KeycloakAuthenticatedActionsFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.adapters.springsecurity.filter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
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.keycloak.KeycloakPrincipal;
|
||||||
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
|
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||||
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
|
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.filter.GenericFilterBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class KeycloakAuthenticatedActionsFilter extends GenericFilterBean implements ApplicationContextAware {
|
||||||
|
|
||||||
|
private static final String FILTER_APPLIED = KeycloakAuthenticatedActionsFilter.class.getPackage().getName() + ".authenticated-actions";
|
||||||
|
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
private AdapterDeploymentContext deploymentContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
if (request.getAttribute(FILTER_APPLIED) != null) {
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
|
||||||
|
|
||||||
|
KeycloakSecurityContext keycloakSecurityContext = getKeycloakPrincipal();
|
||||||
|
|
||||||
|
if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {
|
||||||
|
HttpFacade facade = new SimpleHttpFacade((HttpServletRequest) request, (HttpServletResponse) response);
|
||||||
|
KeycloakDeployment deployment = resolveDeployment(request, response);
|
||||||
|
AuthenticatedActionsHandler actions = new AuthenticatedActionsHandler(deployment, OIDCHttpFacade.class.cast(facade));
|
||||||
|
if (actions.handledRequest()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilterBean() {
|
||||||
|
deploymentContext = applicationContext.getBean(AdapterDeploymentContext.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeycloakSecurityContext getKeycloakPrincipal() {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
if (authentication != null) {
|
||||||
|
Object principal = authentication.getPrincipal();
|
||||||
|
|
||||||
|
if (principal instanceof KeycloakPrincipal) {
|
||||||
|
return KeycloakPrincipal.class.cast(principal).getKeycloakSecurityContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeycloakDeployment resolveDeployment(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||||
|
return deploymentContext.resolveDeployment(new SimpleHttpFacade(HttpServletRequest.class.cast(servletRequest), HttpServletResponse.class.cast(servletResponse)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearAuthenticationContext() {
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
}
|
||||||
|
}
|
|
@ -174,10 +174,6 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
|
||||||
else if (AuthOutcome.AUTHENTICATED.equals(result)) {
|
else if (AuthOutcome.AUTHENTICATED.equals(result)) {
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
Assert.notNull(authentication, "Authentication SecurityContextHolder was null");
|
Assert.notNull(authentication, "Authentication SecurityContextHolder was null");
|
||||||
AuthenticatedActionsHandler actions = new AuthenticatedActionsHandler(deployment, OIDCHttpFacade.class.cast(facade));
|
|
||||||
if (actions.handledRequest()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return authenticationManager.authenticate(authentication);
|
return authenticationManager.authenticate(authentication);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
Loading…
Reference in a new issue