mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-04 12:29:09 +00:00
Add SecurityContextHolderStrategy Java Configuration for Saml2
Issue gh-11061
This commit is contained in:
parent
3c8a80c364
commit
97253c9293
@ -233,6 +233,7 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
|||||||
relyingPartyRegistrationRepository(http);
|
relyingPartyRegistrationRepository(http);
|
||||||
this.saml2WebSsoAuthenticationFilter = new Saml2WebSsoAuthenticationFilter(getAuthenticationConverter(http),
|
this.saml2WebSsoAuthenticationFilter = new Saml2WebSsoAuthenticationFilter(getAuthenticationConverter(http),
|
||||||
this.loginProcessingUrl);
|
this.loginProcessingUrl);
|
||||||
|
this.saml2WebSsoAuthenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||||
setAuthenticationRequestRepository(http, this.saml2WebSsoAuthenticationFilter);
|
setAuthenticationRequestRepository(http, this.saml2WebSsoAuthenticationFilter);
|
||||||
setAuthenticationFilter(this.saml2WebSsoAuthenticationFilter);
|
setAuthenticationFilter(this.saml2WebSsoAuthenticationFilter);
|
||||||
super.loginProcessingUrl(this.loginProcessingUrl);
|
super.loginProcessingUrl(this.loginProcessingUrl);
|
||||||
|
@ -34,7 +34,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutRequestValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutRequestValidator;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutResponseValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutResponseValidator;
|
||||||
@ -255,6 +255,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
|||||||
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(registrations,
|
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(registrations,
|
||||||
this.logoutRequestConfigurer.logoutRequestValidator(), logoutResponseResolver, logoutHandlers);
|
this.logoutRequestConfigurer.logoutRequestValidator(), logoutResponseResolver, logoutHandlers);
|
||||||
filter.setLogoutRequestMatcher(createLogoutRequestMatcher());
|
filter.setLogoutRequestMatcher(createLogoutRequestMatcher());
|
||||||
|
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||||
return postProcess(filter);
|
return postProcess(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +279,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
|||||||
|
|
||||||
private RequestMatcher createLogoutMatcher() {
|
private RequestMatcher createLogoutMatcher() {
|
||||||
RequestMatcher logout = new AntPathRequestMatcher(this.logoutUrl, "POST");
|
RequestMatcher logout = new AntPathRequestMatcher(this.logoutUrl, "POST");
|
||||||
RequestMatcher saml2 = new Saml2RequestMatcher();
|
RequestMatcher saml2 = new Saml2RequestMatcher(getSecurityContextHolderStrategy());
|
||||||
return new AndRequestMatcher(logout, saml2);
|
return new AndRequestMatcher(logout, saml2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,9 +491,15 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
|||||||
|
|
||||||
private static class Saml2RequestMatcher implements RequestMatcher {
|
private static class Saml2RequestMatcher implements RequestMatcher {
|
||||||
|
|
||||||
|
private final SecurityContextHolderStrategy securityContextHolderStrategy;
|
||||||
|
|
||||||
|
Saml2RequestMatcher(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
||||||
|
this.securityContextHolderStrategy = securityContextHolderStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(HttpServletRequest request) {
|
public boolean matches(HttpServletRequest request) {
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (authentication == null) {
|
if (authentication == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
|
|||||||
import org.springframework.security.authentication.ProviderManager;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
@ -64,6 +65,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
|
import org.springframework.security.core.context.SecurityContextChangedListener;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
||||||
import org.springframework.security.saml2.core.Saml2Utils;
|
import org.springframework.security.saml2.core.Saml2Utils;
|
||||||
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
||||||
@ -112,10 +115,13 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.springframework.security.config.Customizer.withDefaults;
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
@ -191,6 +197,26 @@ public class Saml2LoginConfigurerTests {
|
|||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saml2LoginWhenCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||||
|
this.spring
|
||||||
|
.register(Saml2LoginConfig.class, SecurityContextChangedListenerConfig.class, ResourceController.class)
|
||||||
|
.autowire();
|
||||||
|
// @formatter:off
|
||||||
|
MockHttpSession session = (MockHttpSession) this.mvc
|
||||||
|
.perform(post("/login/saml2/sso/registration-id")
|
||||||
|
.param("SAMLResponse", SIGNED_RESPONSE))
|
||||||
|
.andExpect(redirectedUrl("/")).andReturn().getRequest().getSession(false);
|
||||||
|
this.mvc.perform(get("/").session(session))
|
||||||
|
.andExpect(content().string("test@saml.user"));
|
||||||
|
// @formatter:on
|
||||||
|
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||||
|
verify(strategy, atLeastOnce()).getContext();
|
||||||
|
SecurityContextChangedListener listener = this.spring.getContext()
|
||||||
|
.getBean(SecurityContextChangedListener.class);
|
||||||
|
verify(listener, times(2)).securityContextChanged(setAuthentication(Saml2Authentication.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void saml2LoginWhenConfiguringAuthenticationManagerThenTheManagerIsUsed() throws Exception {
|
public void saml2LoginWhenConfiguringAuthenticationManagerThenTheManagerIsUsed() throws Exception {
|
||||||
// setup application context
|
// setup application context
|
||||||
|
@ -42,11 +42,13 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
|||||||
import org.springframework.mock.web.MockHttpSession;
|
import org.springframework.mock.web.MockHttpSession;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.core.Saml2Utils;
|
import org.springframework.security.saml2.core.Saml2Utils;
|
||||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||||
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
||||||
@ -270,6 +272,24 @@ public class Saml2LogoutConfigurerTests {
|
|||||||
verify(getBean(LogoutHandler.class)).logout(any(), any(), any());
|
verify(getBean(LogoutHandler.class)).logout(any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saml2LogoutRequestWhenCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||||
|
this.spring.register(Saml2LogoutDefaultsConfig.class, SecurityContextChangedListenerConfig.class).autowire();
|
||||||
|
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user",
|
||||||
|
Collections.emptyMap());
|
||||||
|
principal.setRelyingPartyRegistrationId("get");
|
||||||
|
Saml2Authentication user = new Saml2Authentication(principal, "response",
|
||||||
|
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||||
|
MvcResult result = this.mvc.perform(get("/logout/saml2/slo").param("SAMLRequest", this.apLogoutRequest)
|
||||||
|
.param("RelayState", this.apLogoutRequestRelayState).param("SigAlg", this.apLogoutRequestSigAlg)
|
||||||
|
.param("Signature", this.apLogoutRequestSignature).with(samlQueryString()).with(authentication(user)))
|
||||||
|
.andExpect(status().isFound()).andReturn();
|
||||||
|
String location = result.getResponse().getHeader("Location");
|
||||||
|
assertThat(location).startsWith("https://ap.example.org/logout/saml2/response");
|
||||||
|
verify(getBean(LogoutHandler.class)).logout(any(), any(), any());
|
||||||
|
verify(getBean(SecurityContextHolderStrategy.class), atLeastOnce()).getContext();
|
||||||
|
}
|
||||||
|
|
||||||
// gh-11235
|
// gh-11235
|
||||||
@Test
|
@Test
|
||||||
public void saml2LogoutRequestWhenLowercaseEncodingThenLogsOutAndSendsLogoutResponse() throws Exception {
|
public void saml2LogoutRequestWhenLowercaseEncodingThenLogsOutAndSendsLogoutResponse() throws Exception {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user