18 changed files with 1336 additions and 6 deletions
@ -0,0 +1,236 @@
@@ -0,0 +1,236 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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.springframework.security.config.http; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Objects; |
||||
import java.util.function.Predicate; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import org.w3c.dom.Element; |
||||
|
||||
import org.springframework.beans.BeanMetadataElement; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
||||
import org.springframework.beans.factory.support.ManagedList; |
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser; |
||||
import org.springframework.beans.factory.xml.ParserContext; |
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.security.core.context.SecurityContextHolder; |
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; |
||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2RelyingPartyInitiatedLogoutSuccessHandler; |
||||
import org.springframework.security.web.authentication.logout.LogoutFilter; |
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessEventPublishingLogoutHandler; |
||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; |
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; |
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher; |
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; |
||||
import org.springframework.security.web.util.matcher.RequestMatcher; |
||||
import org.springframework.util.CollectionUtils; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* SAML 2.0 Single Logout {@link BeanDefinitionParser} |
||||
* |
||||
* @author Marcus da Coregio |
||||
* @since 5.7 |
||||
*/ |
||||
final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser { |
||||
|
||||
private static final String ATT_LOGOUT_REQUEST_URL = "logout-request-url"; |
||||
|
||||
private static final String ATT_LOGOUT_RESPONSE_URL = "logout-response-url"; |
||||
|
||||
private static final String ATT_LOGOUT_URL = "logout-url"; |
||||
|
||||
private List<BeanMetadataElement> logoutHandlers; |
||||
|
||||
private String logoutUrl = "/logout"; |
||||
|
||||
private String logoutRequestUrl = "/logout/saml2/slo"; |
||||
|
||||
private String logoutResponseUrl = "/logout/saml2/slo"; |
||||
|
||||
private BeanMetadataElement logoutSuccessHandler; |
||||
|
||||
private BeanDefinition logoutRequestFilter; |
||||
|
||||
private BeanDefinition logoutResponseFilter; |
||||
|
||||
private BeanDefinition logoutFilter; |
||||
|
||||
Saml2LogoutBeanDefinitionParser(ManagedList<BeanMetadataElement> logoutHandlers, |
||||
BeanMetadataElement logoutSuccessHandler) { |
||||
this.logoutHandlers = logoutHandlers; |
||||
this.logoutSuccessHandler = logoutSuccessHandler; |
||||
} |
||||
|
||||
@Override |
||||
public BeanDefinition parse(Element element, ParserContext pc) { |
||||
String logoutUrl = element.getAttribute(ATT_LOGOUT_URL); |
||||
if (StringUtils.hasText(logoutUrl)) { |
||||
this.logoutUrl = logoutUrl; |
||||
} |
||||
String logoutRequestUrl = element.getAttribute(ATT_LOGOUT_REQUEST_URL); |
||||
if (StringUtils.hasText(logoutRequestUrl)) { |
||||
this.logoutRequestUrl = logoutRequestUrl; |
||||
} |
||||
String logoutResponseUrl = element.getAttribute(ATT_LOGOUT_RESPONSE_URL); |
||||
if (StringUtils.hasText(logoutResponseUrl)) { |
||||
this.logoutResponseUrl = logoutResponseUrl; |
||||
} |
||||
WebConfigUtils.validateHttpRedirect(this.logoutUrl, pc, element); |
||||
WebConfigUtils.validateHttpRedirect(this.logoutRequestUrl, pc, element); |
||||
WebConfigUtils.validateHttpRedirect(this.logoutResponseUrl, pc, element); |
||||
if (CollectionUtils.isEmpty(this.logoutHandlers)) { |
||||
this.logoutHandlers = createDefaultLogoutHandlers(); |
||||
} |
||||
if (this.logoutSuccessHandler == null) { |
||||
this.logoutSuccessHandler = createDefaultLogoutSuccessHandler(); |
||||
} |
||||
BeanMetadataElement relyingPartyRegistrationRepository = Saml2LogoutBeanDefinitionParserUtils |
||||
.getRelyingPartyRegistrationRepository(element); |
||||
BeanMetadataElement registrations = BeanDefinitionBuilder |
||||
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class) |
||||
.addConstructorArgValue(relyingPartyRegistrationRepository).getBeanDefinition(); |
||||
BeanMetadataElement logoutResponseResolver = Saml2LogoutBeanDefinitionParserUtils |
||||
.getLogoutResponseResolver(element, registrations); |
||||
BeanMetadataElement logoutRequestValidator = Saml2LogoutBeanDefinitionParserUtils |
||||
.getLogoutRequestValidator(element); |
||||
BeanMetadataElement logoutRequestMatcher = createSaml2LogoutRequestMatcher(); |
||||
this.logoutRequestFilter = BeanDefinitionBuilder.rootBeanDefinition(Saml2LogoutRequestFilter.class) |
||||
.addConstructorArgValue(registrations).addConstructorArgValue(logoutRequestValidator) |
||||
.addConstructorArgValue(logoutResponseResolver).addConstructorArgValue(this.logoutHandlers) |
||||
.addPropertyValue("logoutRequestMatcher", logoutRequestMatcher).getBeanDefinition(); |
||||
BeanMetadataElement logoutResponseValidator = Saml2LogoutBeanDefinitionParserUtils |
||||
.getLogoutResponseValidator(element); |
||||
BeanMetadataElement logoutRequestRepository = Saml2LogoutBeanDefinitionParserUtils |
||||
.getLogoutRequestRepository(element); |
||||
BeanMetadataElement logoutResponseMatcher = createSaml2LogoutResponseMatcher(); |
||||
this.logoutResponseFilter = BeanDefinitionBuilder.rootBeanDefinition(Saml2LogoutResponseFilter.class) |
||||
.addConstructorArgValue(registrations).addConstructorArgValue(logoutResponseValidator) |
||||
.addConstructorArgValue(this.logoutSuccessHandler) |
||||
.addPropertyValue("logoutRequestMatcher", logoutResponseMatcher) |
||||
.addPropertyValue("logoutRequestRepository", logoutRequestRepository).getBeanDefinition(); |
||||
BeanMetadataElement logoutRequestResolver = Saml2LogoutBeanDefinitionParserUtils |
||||
.getLogoutRequestResolver(element, registrations); |
||||
BeanMetadataElement saml2LogoutRequestSuccessHandler = BeanDefinitionBuilder |
||||
.rootBeanDefinition(Saml2RelyingPartyInitiatedLogoutSuccessHandler.class) |
||||
.addConstructorArgValue(logoutRequestResolver).getBeanDefinition(); |
||||
this.logoutFilter = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class) |
||||
.addConstructorArgValue(saml2LogoutRequestSuccessHandler).addConstructorArgValue(this.logoutHandlers) |
||||
.addPropertyValue("logoutRequestMatcher", createLogoutRequestMatcher()).getBeanDefinition(); |
||||
return null; |
||||
} |
||||
|
||||
private static List<BeanMetadataElement> createDefaultLogoutHandlers() { |
||||
List<BeanMetadataElement> handlers = new ManagedList<>(); |
||||
handlers.add(BeanDefinitionBuilder.rootBeanDefinition(SecurityContextLogoutHandler.class).getBeanDefinition()); |
||||
handlers.add(BeanDefinitionBuilder.rootBeanDefinition(LogoutSuccessEventPublishingLogoutHandler.class) |
||||
.getBeanDefinition()); |
||||
return handlers; |
||||
} |
||||
|
||||
private static BeanMetadataElement createDefaultLogoutSuccessHandler() { |
||||
return BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlLogoutSuccessHandler.class) |
||||
.addPropertyValue("defaultTargetUrl", "/login?logout").getBeanDefinition(); |
||||
} |
||||
|
||||
private BeanMetadataElement createLogoutRequestMatcher() { |
||||
BeanMetadataElement logoutMatcher = BeanDefinitionBuilder.rootBeanDefinition(AntPathRequestMatcher.class) |
||||
.addConstructorArgValue(this.logoutUrl).addConstructorArgValue("POST").getBeanDefinition(); |
||||
BeanMetadataElement saml2Matcher = BeanDefinitionBuilder.rootBeanDefinition(Saml2RequestMatcher.class) |
||||
.getBeanDefinition(); |
||||
return BeanDefinitionBuilder.rootBeanDefinition(AndRequestMatcher.class) |
||||
.addConstructorArgValue(toManagedList(logoutMatcher, saml2Matcher)).getBeanDefinition(); |
||||
} |
||||
|
||||
private BeanMetadataElement createSaml2LogoutRequestMatcher() { |
||||
BeanMetadataElement logoutRequestMatcher = BeanDefinitionBuilder.rootBeanDefinition(AntPathRequestMatcher.class) |
||||
.addConstructorArgValue(this.logoutRequestUrl).getBeanDefinition(); |
||||
BeanMetadataElement saml2RequestMatcher = BeanDefinitionBuilder |
||||
.rootBeanDefinition(ParameterRequestMatcher.class).addConstructorArgValue("SAMLRequest") |
||||
.getBeanDefinition(); |
||||
return BeanDefinitionBuilder.rootBeanDefinition(AndRequestMatcher.class) |
||||
.addConstructorArgValue(toManagedList(logoutRequestMatcher, saml2RequestMatcher)).getBeanDefinition(); |
||||
} |
||||
|
||||
private BeanMetadataElement createSaml2LogoutResponseMatcher() { |
||||
BeanMetadataElement logoutResponseMatcher = BeanDefinitionBuilder |
||||
.rootBeanDefinition(AntPathRequestMatcher.class).addConstructorArgValue(this.logoutResponseUrl) |
||||
.getBeanDefinition(); |
||||
BeanMetadataElement saml2ResponseMatcher = BeanDefinitionBuilder |
||||
.rootBeanDefinition(ParameterRequestMatcher.class).addConstructorArgValue("SAMLResponse") |
||||
.getBeanDefinition(); |
||||
return BeanDefinitionBuilder.rootBeanDefinition(AndRequestMatcher.class) |
||||
.addConstructorArgValue(toManagedList(logoutResponseMatcher, saml2ResponseMatcher)).getBeanDefinition(); |
||||
} |
||||
|
||||
private static List<BeanMetadataElement> toManagedList(BeanMetadataElement... elements) { |
||||
List<BeanMetadataElement> managedList = new ManagedList<>(); |
||||
managedList.addAll(Arrays.asList(elements)); |
||||
return managedList; |
||||
} |
||||
|
||||
BeanDefinition getLogoutRequestFilter() { |
||||
return this.logoutRequestFilter; |
||||
} |
||||
|
||||
BeanDefinition getLogoutResponseFilter() { |
||||
return this.logoutResponseFilter; |
||||
} |
||||
|
||||
BeanDefinition getLogoutFilter() { |
||||
return this.logoutFilter; |
||||
} |
||||
|
||||
private static class ParameterRequestMatcher implements RequestMatcher { |
||||
|
||||
Predicate<String> test = Objects::nonNull; |
||||
|
||||
String name; |
||||
|
||||
ParameterRequestMatcher(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
@Override |
||||
public boolean matches(HttpServletRequest request) { |
||||
return this.test.test(request.getParameter(this.name)); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class Saml2RequestMatcher implements RequestMatcher { |
||||
|
||||
@Override |
||||
public boolean matches(HttpServletRequest request) { |
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
||||
if (authentication == null) { |
||||
return false; |
||||
} |
||||
return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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.springframework.security.config.http; |
||||
|
||||
import org.w3c.dom.Element; |
||||
|
||||
import org.springframework.beans.BeanMetadataElement; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
||||
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.registration.RelyingPartyRegistrationRepository; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* @author Marcus da Coregio |
||||
* @since 5.7 |
||||
*/ |
||||
final class Saml2LogoutBeanDefinitionParserUtils { |
||||
|
||||
private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref"; |
||||
|
||||
private static final String ATT_LOGOUT_REQUEST_VALIDATOR_REF = "logout-request-validator-ref"; |
||||
|
||||
private static final String ATT_LOGOUT_REQUEST_REPOSITORY_REF = "logout-request-repository-ref"; |
||||
|
||||
private static final String ATT_LOGOUT_REQUEST_RESOLVER_REF = "logout-request-resolver-ref"; |
||||
|
||||
private static final String ATT_LOGOUT_RESPONSE_RESOLVER_REF = "logout-response-resolver-ref"; |
||||
|
||||
private static final String ATT_LOGOUT_RESPONSE_VALIDATOR_REF = "logout-response-validator-ref"; |
||||
|
||||
private Saml2LogoutBeanDefinitionParserUtils() { |
||||
} |
||||
|
||||
static BeanMetadataElement getRelyingPartyRegistrationRepository(Element element) { |
||||
String relyingPartyRegistrationRepositoryRef = element |
||||
.getAttribute(ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF); |
||||
if (StringUtils.hasText(relyingPartyRegistrationRepositoryRef)) { |
||||
return new RuntimeBeanReference(relyingPartyRegistrationRepositoryRef); |
||||
} |
||||
return new RuntimeBeanReference(RelyingPartyRegistrationRepository.class); |
||||
} |
||||
|
||||
static BeanMetadataElement getLogoutResponseResolver(Element element, BeanMetadataElement registrations) { |
||||
String logoutResponseResolver = element.getAttribute(ATT_LOGOUT_RESPONSE_RESOLVER_REF); |
||||
if (StringUtils.hasText(logoutResponseResolver)) { |
||||
return new RuntimeBeanReference(logoutResponseResolver); |
||||
} |
||||
return BeanDefinitionBuilder.rootBeanDefinition( |
||||
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver") |
||||
.addConstructorArgValue(registrations).getBeanDefinition(); |
||||
} |
||||
|
||||
static BeanMetadataElement getLogoutRequestValidator(Element element) { |
||||
String logoutRequestValidator = element.getAttribute(ATT_LOGOUT_REQUEST_VALIDATOR_REF); |
||||
if (StringUtils.hasText(logoutRequestValidator)) { |
||||
return new RuntimeBeanReference(logoutRequestValidator); |
||||
} |
||||
return BeanDefinitionBuilder.rootBeanDefinition(OpenSamlLogoutRequestValidator.class).getBeanDefinition(); |
||||
} |
||||
|
||||
static BeanMetadataElement getLogoutResponseValidator(Element element) { |
||||
String logoutResponseValidator = element.getAttribute(ATT_LOGOUT_RESPONSE_VALIDATOR_REF); |
||||
if (StringUtils.hasText(logoutResponseValidator)) { |
||||
return new RuntimeBeanReference(logoutResponseValidator); |
||||
} |
||||
return BeanDefinitionBuilder.rootBeanDefinition(OpenSamlLogoutResponseValidator.class).getBeanDefinition(); |
||||
} |
||||
|
||||
static BeanMetadataElement getLogoutRequestRepository(Element element) { |
||||
String logoutRequestRepository = element.getAttribute(ATT_LOGOUT_REQUEST_REPOSITORY_REF); |
||||
if (StringUtils.hasText(logoutRequestRepository)) { |
||||
return new RuntimeBeanReference(logoutRequestRepository); |
||||
} |
||||
return BeanDefinitionBuilder.rootBeanDefinition(HttpSessionLogoutRequestRepository.class).getBeanDefinition(); |
||||
} |
||||
|
||||
static BeanMetadataElement getLogoutRequestResolver(Element element, BeanMetadataElement registrations) { |
||||
String logoutRequestResolver = element.getAttribute(ATT_LOGOUT_REQUEST_RESOLVER_REF); |
||||
if (StringUtils.hasText(logoutRequestResolver)) { |
||||
return new RuntimeBeanReference(logoutRequestResolver); |
||||
} |
||||
return BeanDefinitionBuilder.rootBeanDefinition( |
||||
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver") |
||||
.addConstructorArgValue(registrations).getBeanDefinition(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,327 @@
@@ -0,0 +1,327 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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.springframework.security.config.http; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
import java.time.Instant; |
||||
import java.util.Collections; |
||||
|
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.junit.jupiter.api.extension.ExtendWith; |
||||
import org.opensaml.saml.saml2.core.LogoutRequest; |
||||
import org.opensaml.xmlsec.signature.support.SignatureConstants; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
import org.springframework.mock.web.MockHttpSession; |
||||
import org.springframework.security.authentication.TestingAuthenticationToken; |
||||
import org.springframework.security.config.test.SpringTestContext; |
||||
import org.springframework.security.config.test.SpringTestContextExtension; |
||||
import org.springframework.security.core.authority.AuthorityUtils; |
||||
import org.springframework.security.saml2.core.Saml2Utils; |
||||
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; |
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; |
||||
import org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects; |
||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; |
||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator; |
||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; |
||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponseValidator; |
||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutValidatorResult; |
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; |
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver; |
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseResolver; |
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; |
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; |
||||
import org.springframework.test.context.junit.jupiter.SpringExtension; |
||||
import org.springframework.test.web.servlet.MockMvc; |
||||
import org.springframework.test.web.servlet.MvcResult; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.hamcrest.Matchers.containsString; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; |
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; |
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; |
||||
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.put; |
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; |
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
||||
|
||||
/** |
||||
* Tests for {@link Saml2LogoutBeanDefinitionParser} |
||||
* |
||||
* @author Marcus da Coregio |
||||
*/ |
||||
@ExtendWith({ SpringExtension.class, SpringTestContextExtension.class }) |
||||
@SecurityTestExecutionListeners |
||||
public class Saml2LogoutBeanDefinitionParserTests { |
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this); |
||||
|
||||
private final Saml2LogoutRequestRepository logoutRequestRepository = new HttpSessionLogoutRequestRepository(); |
||||
|
||||
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/http/Saml2LogoutBeanDefinitionParserTests"; |
||||
|
||||
String apLogoutRequest = "nZFBa4MwGIb/iuQeE2NTXFDLQAaC26Hrdtgt1dQFNMnyxdH9+zlboeyww275SN7nzcOX787jEH0qD9qaAiUxRZEyre206Qv0cnjAGdqVOchxYE40trdT2KuPSUGI5qQBcbkq0OSNsBI0CCNHBSK04vn+sREspsJ5G2xrBxRVc1AbGZa29xAcCEK8i9VZjm5QsfU9GZYWsoCJv5ShqK4K1Ow5p5LyU4aP6XaLN3cpw9mGctydjrxNaZt1XM5vASZVGwjShAIxyhJMU8z4gSWCM8GSmDH+hqLX1Xv+JLpaiiXsb+3+lpMAyv8IoVI6rEzQ4QvrLie3uBX+NMfr6l/waT6t0AumvI6/FlN+Aw=="; |
||||
|
||||
String apLogoutRequestSigAlg = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256; |
||||
|
||||
String apLogoutRequestRelayState = "33591874-b123-4f2c-ab0d-2d0d84aa8b56"; |
||||
|
||||
String apLogoutRequestSignature = "oKqdzrmn2YAqXcwkow2lzRXr5PNHm0s/gWsRnaZYhC+Oq5ekK5uIKQYvtmNR94HJjDe1VRs+vVQCYivgdoTzBV2ZlffTXZmYsCsY9q4jbCWR6R5CbhU73/MkKQsPcyVvMhNYxnDYapIlxDsfoZNTboDEz3GM+HRoGRfl9emCXY0lPRYwqC4kpu7oMDBkafR0A09jPIxFuNpqlLPwUxL9m+DGkvDK3mFDN1xJcgZaK73HcuJe7Qh4huOrKNFetwc5EvqfiwgiWF6sfq9A+rZBfCIYo10NNLY7fNQAR2IqwcKtawHgTGWbeshRyFrwVYMR64EnClfxUHsHKf5kiZ2dlw=="; |
||||
|
||||
String apLogoutResponse = "fZHRa4MwEMb/Fcl7jEadGqplrAwK3Uvb9WFvZ4ydoInk4uj++1nXbmWMvhwcd9/3Jb9bLE99530oi63RBQn9gHhKS1O3+liQ1/0zzciyXCD0HR/ExhzN6LYKB6NReZNUo/ieFWS0WhjAFoWGXqFwUuweXzaC+4EYrHFGmo54K4Wu1eDmuHfnBhSM2cFXJ+iHTvnGHlk3x7DZmNlLGvHWq4Jstk0GUSjjiIZJI2lcpQnNeRLTAOo4fwCeQg3Trr6+cm/OqmnWVHECVGWQ0jgCSatsKvXUxhFvZF7xSYU4qrVGB9oVhAc8pEFEebLnkeBc8NyPePpGvMOV1/Q3cqEjZrG9hXKfCSAqe+ZAShio0q51n7StF+zW7gf9zoEb8U/7ZGrlHaAb1f0onLfFbpRSIRJWXkJ+bdm/Fy6/AA=="; |
||||
|
||||
String apLogoutResponseSigAlg = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256; |
||||
|
||||
String apLogoutResponseRelayState = "8f63887a-ec7e-4149-b6a0-dd730017f315"; |
||||
|
||||
String apLogoutResponseSignature = "h2fDqSIBfmnkRHKDMY4IxkCXcI0w98ydNsnPmv1b7GTZCWLbJ+oxaP2yZNPw7wOWXTv86cTPwKLjx5halKy5C+hhWnT0haKhuMcUvHlsgAMBbJKLV+1afzL4O77cvAQJmMNRK7ugXGNV5PTEnd1U4voy134OgdD5XycYiFVRZOwP5H84eJ9xxlvqQwqDvZTcgiF/ZS4ioZgzgnIFcbagZQ12LWNh26OMaUpIW04kCeO6t2dUsxOL6nZWvNrX/Zx1sORIpu4doDUa1RYC8YnjZeQEzDqUVC/dBO/mbVJ/hbF9tD0jBUx7YIgoXpqsWK4TcCsvmlmhrJXvGxDyoAWu2Q=="; |
||||
|
||||
String rpLogoutRequest = "nZFBa4MwGIb/iuQeY6NlGtQykIHgdui6HXaLmrqAJlm+OLp/v0wrlB122CXkI3mfNw/JD5dpDD6FBalVgXZhhAKhOt1LNRTo5fSAU3Qoc+DTSA1r9KBndxQfswAX+KQCth4VaLaKaQ4SmOKTAOY69nz/2DAaRsxY7XSnRxRUPigVd0vbu3MGGCHchOLCJzOKUNuBjEsLWcDErmUoqKsCNcc+yc5tsudYpPwOJzHvcJv6pfdjEtNzl7XU3wWYRa3AceUKRCO6w1GM6f5EY0Ypo1lIk+gNBa+bt38kulqyJWxv7f6W4wDC/gih0hoslJPuC8s+J7e4Df7k43X1L/jsdxt0xZTX8dfHlN8="; |
||||
|
||||
String rpLogoutRequestId = "LRd49fb45a-e8a7-43ac-b8ac-d8a7432fc9b2"; |
||||
|
||||
String rpLogoutRequestRelayState = "8f63887a-ec7e-4149-b6a0-dd730017f315"; |
||||
|
||||
String rpLogoutRequestSignature = "h2fDqSIBfmnkRHKDMY4IxkCXcI0w98ydNsnPmv1b7GTZCWLbJ+oxaP2yZNPw7wOWXTv86cTPwKLjx5halKy5C+hhWnT0haKhuMcUvHlsgAMBbJKLV+1afzL4O77cvAQJmMNRK7ugXGNV5PTEnd1U4voy134OgdD5XycYiFVRZOwP5H84eJ9xxlvqQwqDvZTcgiF/ZS4ioZgzgnIFcbagZQ12LWNh26OMaUpIW04kCeO6t2dUsxOL6nZWvNrX/Zx1sORIpu4doDUa1RYC8YnjZeQEzDqUVC/dBO/mbVJ/hbF9tD0jBUx7YIgoXpqsWK4TcCsvmlmhrJXvGxDyoAWu2Q=="; |
||||
|
||||
@Autowired(required = false) |
||||
private RelyingPartyRegistrationRepository repository; |
||||
|
||||
@Autowired |
||||
private MockMvc mvc; |
||||
|
||||
private Saml2Authentication saml2User; |
||||
|
||||
private MockHttpServletRequest request; |
||||
|
||||
private MockHttpServletResponse response; |
||||
|
||||
@BeforeEach |
||||
public void setup() { |
||||
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", |
||||
Collections.emptyMap()); |
||||
principal.setRelyingPartyRegistrationId("registration-id"); |
||||
this.saml2User = new Saml2Authentication(principal, "response", |
||||
AuthorityUtils.createAuthorityList("ROLE_USER")); |
||||
this.request = new MockHttpServletRequest("POST", ""); |
||||
this.request.setServletPath("/login/saml2/sso/test-rp"); |
||||
this.response = new MockHttpServletResponse(); |
||||
} |
||||
|
||||
@Test |
||||
public void logoutWhenLogoutSuccessHandlerAndNotSaml2LoginThenDefaultLogoutSuccessHandler() throws Exception { |
||||
this.spring.configLocations(this.xml("LogoutSuccessHandler")).autowire(); |
||||
TestingAuthenticationToken user = new TestingAuthenticationToken("user", "password"); |
||||
MvcResult result = this.mvc.perform(post("/logout").with(authentication(user)).with(csrf())) |
||||
.andExpect(status().isFound()).andReturn(); |
||||
String location = result.getResponse().getHeader("Location"); |
||||
assertThat(location).isEqualTo("/logoutSuccessEndpoint"); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenDefaultsThenLogsOutAndSendsLogoutRequest() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
MvcResult result = this.mvc.perform(post("/logout").with(authentication(this.saml2User)).with(csrf())) |
||||
.andExpect(status().isFound()).andReturn(); |
||||
String location = result.getResponse().getHeader("Location"); |
||||
assertThat(location).startsWith("https://ap.example.org/logout/saml2/request"); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenUnauthenticatedThenEntryPoint() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
this.mvc.perform(post("/logout").with(csrf())).andExpect(status().isFound()) |
||||
.andExpect(redirectedUrl("/login?logout")); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenMissingCsrfThen403() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
this.mvc.perform(post("/logout").with(authentication(this.saml2User))).andExpect(status().isForbidden()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenGetThenDefaultLogoutPage() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
MvcResult result = this.mvc.perform(get("/logout").with(authentication(this.saml2User))) |
||||
.andExpect(status().isOk()).andReturn(); |
||||
assertThat(result.getResponse().getContentAsString()).contains("Are you sure you want to log out?"); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenPutOrDeleteThen404() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
this.mvc.perform(put("/logout").with(authentication(this.saml2User)).with(csrf())) |
||||
.andExpect(status().isNotFound()); |
||||
this.mvc.perform(delete("/logout").with(authentication(this.saml2User)).with(csrf())) |
||||
.andExpect(status().isNotFound()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenNoRegistrationThen401() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", |
||||
Collections.emptyMap()); |
||||
principal.setRelyingPartyRegistrationId("wrong"); |
||||
Saml2Authentication authentication = new Saml2Authentication(principal, "response", |
||||
AuthorityUtils.createAuthorityList("ROLE_USER")); |
||||
this.mvc.perform(post("/logout").with(authentication(authentication)).with(csrf())) |
||||
.andExpect(status().isUnauthorized()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenCsrfDisabledAndNoAuthenticationThenFinalRedirect() throws Exception { |
||||
this.spring.configLocations(this.xml("CsrfDisabled-MockLogoutSuccessHandler")).autowire(); |
||||
this.mvc.perform(post("/logout")); |
||||
LogoutSuccessHandler logoutSuccessHandler = this.spring.getContext().getBean(LogoutSuccessHandler.class); |
||||
verify(logoutSuccessHandler).onLogoutSuccess(any(), any(), any()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutWhenCustomLogoutRequestResolverThenUses() throws Exception { |
||||
this.spring.configLocations(this.xml("CustomComponents")).autowire(); |
||||
RelyingPartyRegistration registration = this.repository.findByRegistrationId("registration-id"); |
||||
Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration) |
||||
.samlRequest(this.rpLogoutRequest).id(this.rpLogoutRequestId).relayState(this.rpLogoutRequestRelayState) |
||||
.parameters((params) -> params.put("Signature", this.rpLogoutRequestSignature)).build(); |
||||
given(getBean(Saml2LogoutRequestResolver.class).resolve(any(), any())).willReturn(logoutRequest); |
||||
this.mvc.perform(post("/logout").with(authentication(this.saml2User)).with(csrf())); |
||||
verify(getBean(Saml2LogoutRequestResolver.class)).resolve(any(), any()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutRequestWhenDefaultsThenLogsOutAndSendsLogoutResponse() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).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(authentication(user))) |
||||
.andExpect(status().isFound()).andReturn(); |
||||
String location = result.getResponse().getHeader("Location"); |
||||
assertThat(location).startsWith("https://ap.example.org/logout/saml2/response"); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutRequestWhenNoRegistrationThen400() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", |
||||
Collections.emptyMap()); |
||||
principal.setRelyingPartyRegistrationId("wrong"); |
||||
Saml2Authentication user = new Saml2Authentication(principal, "response", |
||||
AuthorityUtils.createAuthorityList("ROLE_USER")); |
||||
this.mvc.perform(get("/logout/saml2/slo").param("SAMLRequest", this.apLogoutRequest) |
||||
.param("RelayState", this.apLogoutRequestRelayState).param("SigAlg", this.apLogoutRequestSigAlg) |
||||
.param("Signature", this.apLogoutRequestSignature).with(authentication(user))) |
||||
.andExpect(status().isBadRequest()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutRequestWhenInvalidSamlRequestThen401() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
this.mvc.perform(get("/logout/saml2/slo").param("SAMLRequest", this.apLogoutRequest) |
||||
.param("RelayState", this.apLogoutRequestRelayState).param("SigAlg", this.apLogoutRequestSigAlg) |
||||
.with(authentication(this.saml2User))).andExpect(status().isUnauthorized()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutRequestWhenCustomLogoutRequestHandlerThenUses() throws Exception { |
||||
this.spring.configLocations(this.xml("CustomComponents")).autowire(); |
||||
RelyingPartyRegistration registration = this.repository.findByRegistrationId("registration-id"); |
||||
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration); |
||||
logoutRequest.setIssueInstant(Instant.now()); |
||||
given(getBean(Saml2LogoutRequestValidator.class).validate(any())) |
||||
.willReturn(Saml2LogoutValidatorResult.success()); |
||||
Saml2LogoutResponse logoutResponse = Saml2LogoutResponse.withRelyingPartyRegistration(registration).build(); |
||||
given(getBean(Saml2LogoutResponseResolver.class).resolve(any(), any())).willReturn(logoutResponse); |
||||
this.mvc.perform( |
||||
post("/logout/saml2/slo").param("SAMLRequest", "samlRequest").with(authentication(this.saml2User))) |
||||
.andReturn(); |
||||
verify(getBean(Saml2LogoutRequestValidator.class)).validate(any()); |
||||
verify(getBean(Saml2LogoutResponseResolver.class)).resolve(any(), any()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutResponseWhenDefaultsThenRedirects() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
RelyingPartyRegistration registration = this.repository.findByRegistrationId("get"); |
||||
Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration) |
||||
.samlRequest(this.rpLogoutRequest).id(this.rpLogoutRequestId).relayState(this.rpLogoutRequestRelayState) |
||||
.parameters((params) -> params.put("Signature", this.rpLogoutRequestSignature)).build(); |
||||
this.logoutRequestRepository.saveLogoutRequest(logoutRequest, this.request, this.response); |
||||
this.request.setParameter("RelayState", logoutRequest.getRelayState()); |
||||
assertThat(this.logoutRequestRepository.loadLogoutRequest(this.request)).isNotNull(); |
||||
this.mvc.perform(get("/logout/saml2/slo").session(((MockHttpSession) this.request.getSession())) |
||||
.param("SAMLResponse", this.apLogoutResponse).param("RelayState", this.apLogoutResponseRelayState) |
||||
.param("SigAlg", this.apLogoutResponseSigAlg).param("Signature", this.apLogoutResponseSignature)) |
||||
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout")); |
||||
assertThat(this.logoutRequestRepository.loadLogoutRequest(this.request)).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutResponseWhenInvalidSamlResponseThen401() throws Exception { |
||||
this.spring.configLocations(this.xml("Default")).autowire(); |
||||
RelyingPartyRegistration registration = this.repository.findByRegistrationId("registration-id"); |
||||
Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration) |
||||
.samlRequest(this.rpLogoutRequest).id(this.rpLogoutRequestId).relayState(this.rpLogoutRequestRelayState) |
||||
.parameters((params) -> params.put("Signature", this.rpLogoutRequestSignature)).build(); |
||||
this.logoutRequestRepository.saveLogoutRequest(logoutRequest, this.request, this.response); |
||||
String deflatedApLogoutResponse = Saml2Utils.samlEncode( |
||||
Saml2Utils.samlInflate(Saml2Utils.samlDecode(this.apLogoutResponse)).getBytes(StandardCharsets.UTF_8)); |
||||
this.mvc.perform(post("/logout/saml2/slo").session((MockHttpSession) this.request.getSession()) |
||||
.param("SAMLResponse", deflatedApLogoutResponse).param("RelayState", this.rpLogoutRequestRelayState) |
||||
.param("SigAlg", this.apLogoutRequestSigAlg).param("Signature", this.apLogoutResponseSignature)) |
||||
.andExpect(status().reason(containsString("invalid_signature"))).andExpect(status().isUnauthorized()); |
||||
} |
||||
|
||||
@Test |
||||
public void saml2LogoutResponseWhenCustomLogoutResponseHandlerThenUses() throws Exception { |
||||
this.spring.configLocations(this.xml("CustomComponents")).autowire(); |
||||
RelyingPartyRegistration registration = this.repository.findByRegistrationId("get"); |
||||
Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration) |
||||
.samlRequest(this.rpLogoutRequest).id(this.rpLogoutRequestId).relayState(this.rpLogoutRequestRelayState) |
||||
.parameters((params) -> params.put("Signature", this.rpLogoutRequestSignature)).build(); |
||||
given(getBean(Saml2LogoutRequestRepository.class).removeLogoutRequest(any(), any())).willReturn(logoutRequest); |
||||
given(getBean(Saml2LogoutResponseValidator.class).validate(any())) |
||||
.willReturn(Saml2LogoutValidatorResult.success()); |
||||
this.mvc.perform(get("/logout/saml2/slo").param("SAMLResponse", "samlResponse")).andReturn(); |
||||
verify(getBean(Saml2LogoutResponseValidator.class)).validate(any()); |
||||
} |
||||
|
||||
private <T> T getBean(Class<T> clazz) { |
||||
return this.spring.getContext().getBean(clazz); |
||||
} |
||||
|
||||
private String xml(String configName) { |
||||
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright 2002-2022 the original author or authors. |
||||
~ |
||||
~ 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 |
||||
~ |
||||
~ https://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. |
||||
--> |
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns="http://www.springframework.org/schema/security" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/security |
||||
https://www.springframework.org/schema/security/spring-security.xsd |
||||
http://www.springframework.org/schema/beans |
||||
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||
|
||||
<http auto-config="true"> |
||||
<csrf disabled="true"/> |
||||
<intercept-url pattern="/**" access="authenticated"/> |
||||
<logout success-handler-ref="logoutSuccessHandler"/> |
||||
<saml2-login/> |
||||
<saml2-logout/> |
||||
</http> |
||||
|
||||
<b:bean id="logoutSuccessHandler" class="org.mockito.Mockito" factory-method="mock"> |
||||
<b:constructor-arg value="org.springframework.security.web.authentication.logout.LogoutSuccessHandler"/> |
||||
</b:bean> |
||||
|
||||
<b:import resource="userservice.xml"/> |
||||
<b:import resource="../saml2/logout-registrations.xml"/> |
||||
</b:beans> |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright 2002-2022 the original author or authors. |
||||
~ |
||||
~ 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 |
||||
~ |
||||
~ https://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. |
||||
--> |
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns="http://www.springframework.org/schema/security" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/security |
||||
https://www.springframework.org/schema/security/spring-security.xsd |
||||
http://www.springframework.org/schema/beans |
||||
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||
|
||||
<http auto-config="true"> |
||||
<intercept-url pattern="/**" access="authenticated"/> |
||||
<saml2-login/> |
||||
<saml2-logout logout-request-resolver-ref="logoutRequestResolver" logout-request-repository-ref="logoutRequestRepository" |
||||
logout-request-validator-ref="logoutRequestValidator" logout-response-validator-ref="logoutResponseValidator" logout-response-resolver-ref="logoutResponseResolver"/> |
||||
</http> |
||||
|
||||
<b:bean id="logoutRequestResolver" class="org.mockito.Mockito" factory-method="mock"> |
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver"/> |
||||
</b:bean> |
||||
|
||||
<b:bean id="logoutRequestRepository" class="org.mockito.Mockito" factory-method="mock"> |
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository"/> |
||||
</b:bean> |
||||
|
||||
<b:bean id="logoutRequestValidator" class="org.mockito.Mockito" factory-method="mock"> |
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator"/> |
||||
</b:bean> |
||||
|
||||
<b:bean id="logoutResponseValidator" class="org.mockito.Mockito" factory-method="mock"> |
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponseValidator"/> |
||||
</b:bean> |
||||
|
||||
<b:bean id="logoutResponseResolver" class="org.mockito.Mockito" factory-method="mock"> |
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseResolver"/> |
||||
</b:bean> |
||||
|
||||
<b:import resource="userservice.xml"/> |
||||
<b:import resource="../saml2/logout-registrations.xml"/> |
||||
</b:beans> |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright 2002-2022 the original author or authors. |
||||
~ |
||||
~ 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 |
||||
~ |
||||
~ https://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. |
||||
--> |
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns="http://www.springframework.org/schema/security" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/security |
||||
https://www.springframework.org/schema/security/spring-security.xsd |
||||
http://www.springframework.org/schema/beans |
||||
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||
|
||||
<http auto-config="true"> |
||||
<intercept-url pattern="/**" access="authenticated"/> |
||||
<saml2-login/> |
||||
<saml2-logout/> |
||||
</http> |
||||
|
||||
<b:import resource="userservice.xml"/> |
||||
<b:import resource="../saml2/logout-registrations.xml"/> |
||||
</b:beans> |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright 2002-2022 the original author or authors. |
||||
~ |
||||
~ 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 |
||||
~ |
||||
~ https://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. |
||||
--> |
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns="http://www.springframework.org/schema/security" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/security |
||||
https://www.springframework.org/schema/security/spring-security.xsd |
||||
http://www.springframework.org/schema/beans |
||||
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||
|
||||
<http auto-config="true"> |
||||
<intercept-url pattern="/**" access="authenticated"/> |
||||
<logout success-handler-ref="logoutSuccessEndpoint"/> |
||||
<saml2-login/> |
||||
<saml2-logout/> |
||||
</http> |
||||
|
||||
<b:bean name="logoutSuccessEndpoint" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler"> |
||||
<b:property name="defaultTargetUrl" value="/logoutSuccessEndpoint"/> |
||||
</b:bean> |
||||
|
||||
<b:import resource="userservice.xml"/> |
||||
<b:import resource="../saml2/logout-registrations.xml"/> |
||||
</b:beans> |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright 2002-2021 the original author or authors. |
||||
~ |
||||
~ 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 |
||||
~ |
||||
~ https://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. |
||||
--> |
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns="http://www.springframework.org/schema/security" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/security |
||||
https://www.springframework.org/schema/security/spring-security.xsd |
||||
http://www.springframework.org/schema/beans |
||||
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||
<relying-party-registrations> |
||||
<relying-party-registration registration-id="registration-id" |
||||
entity-id="rp-entity-id" |
||||
assertion-consumer-service-location="https://rp.example.org/acs" |
||||
assertion-consumer-service-binding="REDIRECT" |
||||
single-logout-service-location="https://rp.example.org/logout/saml2/request" |
||||
single-logout-service-response-location="https://rp.example.org/logout/saml2/response" |
||||
asserting-party-id="ap"> |
||||
<signing-credential certificate-location="classpath:org/springframework/security/config/saml2/rp-certificate.crt" |
||||
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/> |
||||
</relying-party-registration> |
||||
|
||||
<relying-party-registration registration-id="get" |
||||
entity-id="rp-entity-id" |
||||
assertion-consumer-service-location="https://rp.example.org/acs" |
||||
assertion-consumer-service-binding="REDIRECT" |
||||
single-logout-service-location="https://rp.example.org/logout/saml2/request" |
||||
single-logout-service-response-location="https://rp.example.org/logout/saml2/response" |
||||
single-logout-service-binding="REDIRECT" |
||||
asserting-party-id="ap"> |
||||
<signing-credential certificate-location="classpath:org/springframework/security/config/saml2/rp-certificate.crt" |
||||
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/> |
||||
</relying-party-registration> |
||||
|
||||
<relying-party-registration registration-id="rp" |
||||
entity-id="ap-entity-id" |
||||
assertion-consumer-service-location="https://rp.example.org/acs" |
||||
assertion-consumer-service-binding="REDIRECT" |
||||
single-logout-service-location="https://rp.example.org/logout/saml2/request" |
||||
single-logout-service-response-location="https://rp.example.org/logout/saml2/response" |
||||
single-logout-service-binding="REDIRECT" |
||||
asserting-party-id="rp"/> |
||||
|
||||
<asserting-party asserting-party-id="ap" entity-id="ap-entity-id" |
||||
single-sign-on-service-location="https://ap.example.org/sso" |
||||
single-logout-service-location="https://ap.example.org/logout/saml2/request" |
||||
single-logout-service-response-location="https://ap.example.org/logout/saml2/response"> |
||||
<verification-credential |
||||
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt" |
||||
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/> |
||||
<encryption-credential |
||||
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt" |
||||
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/> |
||||
</asserting-party> |
||||
|
||||
<asserting-party asserting-party-id="rp" entity-id="ap-entity-id" |
||||
single-sign-on-service-location="https://rp.example.org/sso" |
||||
single-logout-service-location="https://rp.example.org/logout/saml2/request" |
||||
single-logout-service-response-location="https://ap.example.org/logout/saml2/response"> |
||||
<verification-credential |
||||
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt" |
||||
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/> |
||||
<encryption-credential |
||||
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt" |
||||
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/> |
||||
</asserting-party> |
||||
</relying-party-registrations> |
||||
</b:beans> |
||||
Loading…
Reference in new issue