parent
aa0005b1e1
commit
1cbe7a75d3
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* 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.
|
||||
|
@ -132,4 +132,8 @@ public abstract class Elements {
|
|||
|
||||
public static final String PASSWORD_MANAGEMENT = "password-management";
|
||||
|
||||
public static final String RELYING_PARTY_REGISTRATIONS = "relying-party-registrations";
|
||||
|
||||
public static final String SAML2_LOGIN = "saml2-login";
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2009-2020 the original author or authors.
|
||||
* Copyright 2009-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.
|
||||
|
@ -47,6 +47,7 @@ import org.springframework.security.config.method.InterceptMethodsBeanDefinition
|
|||
import org.springframework.security.config.method.MethodSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
|
||||
import org.springframework.security.config.oauth2.client.ClientRegistrationsBeanDefinitionParser;
|
||||
import org.springframework.security.config.saml2.RelyingPartyRegistrationsBeanDefinitionParser;
|
||||
import org.springframework.security.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
@ -190,6 +191,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||
this.parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
|
||||
this.filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
||||
this.parsers.put(Elements.CLIENT_REGISTRATIONS, new ClientRegistrationsBeanDefinitionParser());
|
||||
this.parsers.put(Elements.RELYING_PARTY_REGISTRATIONS, new RelyingPartyRegistrationsBeanDefinitionParser());
|
||||
}
|
||||
|
||||
private void loadWebSocketParsers() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
|
@ -182,6 +182,14 @@ final class AuthenticationConfigBuilder {
|
|||
|
||||
private BeanDefinition oauth2LoginLinks;
|
||||
|
||||
private BeanDefinition saml2AuthenticationUrlToProviderName;
|
||||
|
||||
private BeanDefinition saml2AuthorizationRequestFilter;
|
||||
|
||||
private String saml2AuthenticationFilterId;
|
||||
|
||||
private String saml2AuthenticationRequestFilterId;
|
||||
|
||||
private boolean oauth2ClientEnabled;
|
||||
|
||||
private BeanDefinition authorizationRequestRedirectFilter;
|
||||
|
@ -217,6 +225,7 @@ final class AuthenticationConfigBuilder {
|
|||
createBearerTokenAuthenticationFilter(authenticationManager);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager);
|
||||
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager);
|
||||
createSaml2LoginFilter(authenticationManager);
|
||||
createX509Filter(authenticationManager);
|
||||
createJeeFilter(authenticationManager);
|
||||
createLogoutFilter();
|
||||
|
@ -374,6 +383,29 @@ final class AuthenticationConfigBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private void createSaml2LoginFilter(BeanReference authenticationManager) {
|
||||
Element saml2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.SAML2_LOGIN);
|
||||
if (saml2LoginElt == null) {
|
||||
return;
|
||||
}
|
||||
Saml2LoginBeanDefinitionParser parser = new Saml2LoginBeanDefinitionParser(this.csrfIgnoreRequestMatchers,
|
||||
this.portMapper, this.portResolver, this.requestCache, this.allowSessionCreation, authenticationManager,
|
||||
this.authenticationProviders, this.defaultEntryPointMappings);
|
||||
BeanDefinition saml2WebSsoAuthenticationFilter = parser.parse(saml2LoginElt, this.pc);
|
||||
this.saml2AuthorizationRequestFilter = parser.getSaml2WebSsoAuthenticationRequestFilter();
|
||||
|
||||
this.saml2AuthenticationFilterId = this.pc.getReaderContext().generateBeanName(saml2WebSsoAuthenticationFilter);
|
||||
this.saml2AuthenticationRequestFilterId = this.pc.getReaderContext()
|
||||
.generateBeanName(this.saml2AuthorizationRequestFilter);
|
||||
this.saml2AuthenticationUrlToProviderName = parser.getSaml2AuthenticationUrlToProviderName();
|
||||
|
||||
// register the component
|
||||
this.pc.registerBeanComponent(
|
||||
new BeanComponentDefinition(saml2WebSsoAuthenticationFilter, this.saml2AuthenticationFilterId));
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(this.saml2AuthorizationRequestFilter,
|
||||
this.saml2AuthenticationRequestFilterId));
|
||||
}
|
||||
|
||||
private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) {
|
||||
if (rememberMeServicesId != null) {
|
||||
bean.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
|
@ -539,6 +571,11 @@ final class AuthenticationConfigBuilder {
|
|||
loginPageFilter.addPropertyValue("Oauth2LoginEnabled", true);
|
||||
loginPageFilter.addPropertyValue("Oauth2AuthenticationUrlToClientName", this.oauth2LoginLinks);
|
||||
}
|
||||
if (this.saml2AuthenticationFilterId != null) {
|
||||
loginPageFilter.addPropertyValue("saml2LoginEnabled", true);
|
||||
loginPageFilter.addPropertyValue("saml2AuthenticationUrlToProviderName",
|
||||
this.saml2AuthenticationUrlToProviderName);
|
||||
}
|
||||
this.loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
|
||||
this.logoutPageGenerationFilter = logoutPageFilter.getBeanDefinition();
|
||||
}
|
||||
|
@ -703,7 +740,8 @@ final class AuthenticationConfigBuilder {
|
|||
if (formLoginElt != null && this.oauth2LoginEntryPoint != null) {
|
||||
return this.formEntryPoint;
|
||||
}
|
||||
// If form login was enabled through auto-config, and Oauth2 login was not
|
||||
// If form login was enabled through auto-config, and Oauth2 login & Saml2
|
||||
// login was not
|
||||
// enabled then use form login
|
||||
if (this.oauth2LoginEntryPoint == null) {
|
||||
return this.formEntryPoint;
|
||||
|
@ -778,6 +816,12 @@ final class AuthenticationConfigBuilder {
|
|||
filters.add(new OrderDecorator(this.authorizationCodeGrantFilter,
|
||||
SecurityFilters.OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER));
|
||||
}
|
||||
if (this.saml2AuthenticationFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2AuthenticationFilterId),
|
||||
SecurityFilters.SAML2_AUTHENTICATION_FILTER));
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2AuthenticationRequestFilterId),
|
||||
SecurityFilters.SAML2_AUTHENTICATION_REQUEST_FILTER));
|
||||
}
|
||||
filters.add(new OrderDecorator(this.etf, SecurityFilters.EXCEPTION_TRANSLATION_FILTER));
|
||||
return filters;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* 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.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.security.config.Elements;
|
||||
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.servlet.filter.Saml2WebSsoAuthenticationFilter;
|
||||
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* SAML 2.0 Login {@link BeanDefinitionParser}
|
||||
*
|
||||
* @author Marcus da Coregio
|
||||
* @since 5.7
|
||||
*/
|
||||
final class Saml2LoginBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String DEFAULT_LOGIN_URI = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
|
||||
|
||||
private static final String DEFAULT_AUTHENTICATION_REQUEST_PROCESSING_URL = "/saml2/authenticate/{registrationId}";
|
||||
|
||||
private static final String ATT_LOGIN_PROCESSING_URL = "login-processing-url";
|
||||
|
||||
private static final String ATT_LOGIN_PAGE = "login-page";
|
||||
|
||||
private static final String ELT_RELYING_PARTY_REGISTRATION = "relying-party-registration";
|
||||
|
||||
private static final String ELT_REGISTRATION_ID = "registration-id";
|
||||
|
||||
private static final String ATT_AUTHENTICATION_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
||||
|
||||
private static final String ATT_AUTHENTICATION_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
||||
|
||||
private static final String ATT_AUTHENTICATION_MANAGER_REF = "authentication-manager-ref";
|
||||
|
||||
private final List<BeanDefinition> csrfIgnoreRequestMatchers;
|
||||
|
||||
private final BeanReference portMapper;
|
||||
|
||||
private final BeanReference portResolver;
|
||||
|
||||
private final BeanReference requestCache;
|
||||
|
||||
private final boolean allowSessionCreation;
|
||||
|
||||
private final BeanReference authenticationManager;
|
||||
|
||||
private final List<BeanReference> authenticationProviders;
|
||||
|
||||
private final Map<BeanDefinition, BeanMetadataElement> entryPoints;
|
||||
|
||||
private String loginProcessingUrl = Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
|
||||
private BeanDefinition saml2WebSsoAuthenticationRequestFilter;
|
||||
|
||||
private BeanDefinition saml2AuthenticationUrlToProviderName;
|
||||
|
||||
Saml2LoginBeanDefinitionParser(List<BeanDefinition> csrfIgnoreRequestMatchers, BeanReference portMapper,
|
||||
BeanReference portResolver, BeanReference requestCache, boolean allowSessionCreation,
|
||||
BeanReference authenticationManager, List<BeanReference> authenticationProviders,
|
||||
Map<BeanDefinition, BeanMetadataElement> entryPoints) {
|
||||
this.csrfIgnoreRequestMatchers = csrfIgnoreRequestMatchers;
|
||||
this.portMapper = portMapper;
|
||||
this.portResolver = portResolver;
|
||||
this.requestCache = requestCache;
|
||||
this.allowSessionCreation = allowSessionCreation;
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.authenticationProviders = authenticationProviders;
|
||||
this.entryPoints = entryPoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
String loginProcessingUrl = element.getAttribute(ATT_LOGIN_PROCESSING_URL);
|
||||
if (StringUtils.hasText(loginProcessingUrl)) {
|
||||
this.loginProcessingUrl = loginProcessingUrl;
|
||||
}
|
||||
BeanDefinition saml2LoginBeanConfig = BeanDefinitionBuilder.rootBeanDefinition(Saml2LoginBeanConfig.class)
|
||||
.getBeanDefinition();
|
||||
String saml2LoginBeanConfigId = pc.getReaderContext().generateBeanName(saml2LoginBeanConfig);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(saml2LoginBeanConfig, saml2LoginBeanConfigId));
|
||||
registerDefaultCsrfOverride();
|
||||
BeanMetadataElement relyingPartyRegistrationRepository = Saml2LoginBeanDefinitionParserUtils
|
||||
.getRelyingPartyRegistrationRepository(element);
|
||||
BeanMetadataElement authenticationRequestRepository = Saml2LoginBeanDefinitionParserUtils
|
||||
.getAuthenticationRequestRepository(element);
|
||||
BeanMetadataElement authenticationRequestResolver = Saml2LoginBeanDefinitionParserUtils
|
||||
.getAuthenticationRequestResolver(element);
|
||||
if (authenticationRequestResolver == null) {
|
||||
authenticationRequestResolver = Saml2LoginBeanDefinitionParserUtils
|
||||
.createDefaultAuthenticationRequestResolver(relyingPartyRegistrationRepository);
|
||||
}
|
||||
BeanMetadataElement authenticationConverter = Saml2LoginBeanDefinitionParserUtils
|
||||
.getAuthenticationConverter(element);
|
||||
if (authenticationConverter == null) {
|
||||
if (!this.loginProcessingUrl.contains("{registrationId}")) {
|
||||
pc.getReaderContext().error("loginProcessingUrl must contain {registrationId} path variable", element);
|
||||
}
|
||||
authenticationConverter = Saml2LoginBeanDefinitionParserUtils
|
||||
.createDefaultAuthenticationConverter(relyingPartyRegistrationRepository);
|
||||
}
|
||||
// Configure the Saml2WebSsoAuthenticationFilter
|
||||
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(Saml2WebSsoAuthenticationFilter.class)
|
||||
.addConstructorArgValue(authenticationConverter).addConstructorArgValue(this.loginProcessingUrl)
|
||||
.addPropertyValue("authenticationRequestRepository", authenticationRequestRepository);
|
||||
resolveLoginPage(element, pc);
|
||||
resolveAuthenticationSuccessHandler(element, saml2WebSsoAuthenticationFilterBuilder);
|
||||
resolveAuthenticationFailureHandler(element, saml2WebSsoAuthenticationFilterBuilder);
|
||||
resolveAuthenticationManager(element, saml2WebSsoAuthenticationFilterBuilder);
|
||||
// Configure the Saml2WebSsoAuthenticationRequestFilter
|
||||
this.saml2WebSsoAuthenticationRequestFilter = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(Saml2WebSsoAuthenticationRequestFilter.class)
|
||||
.addConstructorArgValue(authenticationRequestResolver)
|
||||
.addPropertyValue("authenticationRequestRepository", authenticationRequestRepository)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition saml2AuthenticationProvider = Saml2LoginBeanDefinitionParserUtils.createAuthenticationProvider();
|
||||
this.authenticationProviders.add(
|
||||
new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(saml2AuthenticationProvider)));
|
||||
this.saml2AuthenticationUrlToProviderName = BeanDefinitionBuilder.rootBeanDefinition(Map.class)
|
||||
.setFactoryMethodOnBean("getAuthenticationUrlToProviderName", saml2LoginBeanConfigId)
|
||||
.getBeanDefinition();
|
||||
return saml2WebSsoAuthenticationFilterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void resolveAuthenticationManager(Element element,
|
||||
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
|
||||
String authenticationManagerRef = element.getAttribute(ATT_AUTHENTICATION_MANAGER_REF);
|
||||
if (StringUtils.hasText(authenticationManagerRef)) {
|
||||
saml2WebSsoAuthenticationFilterBuilder.addPropertyReference("authenticationManager",
|
||||
authenticationManagerRef);
|
||||
}
|
||||
else {
|
||||
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("authenticationManager",
|
||||
this.authenticationManager);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveLoginPage(Element element, ParserContext parserContext) {
|
||||
String loginPage = element.getAttribute(ATT_LOGIN_PAGE);
|
||||
Object source = parserContext.extractSource(element);
|
||||
BeanDefinition saml2LoginAuthenticationEntryPoint = null;
|
||||
if (StringUtils.hasText(loginPage)) {
|
||||
WebConfigUtils.validateHttpRedirect(loginPage, parserContext, source);
|
||||
saml2LoginAuthenticationEntryPoint = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class).addConstructorArgValue(loginPage)
|
||||
.addPropertyValue("portMapper", this.portMapper).addPropertyValue("portResolver", this.portResolver)
|
||||
.getBeanDefinition();
|
||||
}
|
||||
else {
|
||||
Map<String, String> identityProviderUrlMap = getIdentityProviderUrlMap(element);
|
||||
if (identityProviderUrlMap.size() == 1) {
|
||||
String loginUrl = identityProviderUrlMap.entrySet().iterator().next().getKey();
|
||||
saml2LoginAuthenticationEntryPoint = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class).addConstructorArgValue(loginUrl)
|
||||
.addPropertyValue("portMapper", this.portMapper)
|
||||
.addPropertyValue("portResolver", this.portResolver).getBeanDefinition();
|
||||
}
|
||||
}
|
||||
if (saml2LoginAuthenticationEntryPoint != null) {
|
||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(AntPathRequestMatcher.class);
|
||||
requestMatcherBuilder.addConstructorArgValue(this.loginProcessingUrl);
|
||||
BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
|
||||
this.entryPoints.put(requestMatcher, saml2LoginAuthenticationEntryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveAuthenticationFailureHandler(Element element,
|
||||
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
|
||||
String authenticationFailureHandlerRef = element.getAttribute(ATT_AUTHENTICATION_FAILURE_HANDLER_REF);
|
||||
if (StringUtils.hasText(authenticationFailureHandlerRef)) {
|
||||
saml2WebSsoAuthenticationFilterBuilder.addPropertyReference("authenticationFailureHandler",
|
||||
authenticationFailureHandlerRef);
|
||||
}
|
||||
else {
|
||||
BeanDefinitionBuilder failureHandlerBuilder = BeanDefinitionBuilder.rootBeanDefinition(
|
||||
"org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler");
|
||||
failureHandlerBuilder.addConstructorArgValue(
|
||||
DEFAULT_LOGIN_URI + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME);
|
||||
failureHandlerBuilder.addPropertyValue("allowSessionCreation", this.allowSessionCreation);
|
||||
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("authenticationFailureHandler",
|
||||
failureHandlerBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveAuthenticationSuccessHandler(Element element,
|
||||
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
|
||||
String authenticationSuccessHandlerRef = element.getAttribute(ATT_AUTHENTICATION_SUCCESS_HANDLER_REF);
|
||||
if (StringUtils.hasText(authenticationSuccessHandlerRef)) {
|
||||
saml2WebSsoAuthenticationFilterBuilder.addPropertyReference("authenticationSuccessHandler",
|
||||
authenticationSuccessHandlerRef);
|
||||
}
|
||||
else {
|
||||
BeanDefinitionBuilder successHandlerBuilder = BeanDefinitionBuilder.rootBeanDefinition(
|
||||
"org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler")
|
||||
.addPropertyValue("requestCache", this.requestCache);
|
||||
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("authenticationSuccessHandler",
|
||||
successHandlerBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDefaultCsrfOverride() {
|
||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(AntPathRequestMatcher.class);
|
||||
requestMatcherBuilder.addConstructorArgValue(this.loginProcessingUrl);
|
||||
BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
|
||||
this.csrfIgnoreRequestMatchers.add(requestMatcher);
|
||||
}
|
||||
|
||||
private Map<String, String> getIdentityProviderUrlMap(Element element) {
|
||||
Map<String, String> idps = new LinkedHashMap<>();
|
||||
Element relyingPartyRegistrationsElt = DomUtils.getChildElementByTagName(
|
||||
element.getOwnerDocument().getDocumentElement(), Elements.RELYING_PARTY_REGISTRATIONS);
|
||||
String authenticationRequestProcessingUrl = DEFAULT_AUTHENTICATION_REQUEST_PROCESSING_URL;
|
||||
if (relyingPartyRegistrationsElt != null) {
|
||||
List<Element> relyingPartyRegList = DomUtils.getChildElementsByTagName(relyingPartyRegistrationsElt,
|
||||
ELT_RELYING_PARTY_REGISTRATION);
|
||||
for (Element relyingPartyReg : relyingPartyRegList) {
|
||||
String registrationId = relyingPartyReg.getAttribute(ELT_REGISTRATION_ID);
|
||||
idps.put(authenticationRequestProcessingUrl.replace("{registrationId}", registrationId),
|
||||
registrationId);
|
||||
}
|
||||
}
|
||||
return idps;
|
||||
}
|
||||
|
||||
BeanDefinition getSaml2WebSsoAuthenticationRequestFilter() {
|
||||
return this.saml2WebSsoAuthenticationRequestFilter;
|
||||
}
|
||||
|
||||
BeanDefinition getSaml2AuthenticationUrlToProviderName() {
|
||||
return this.saml2AuthenticationUrlToProviderName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper bean class to provide configuration from applicationContext
|
||||
*/
|
||||
public static class Saml2LoginBeanConfig implements ApplicationContextAware {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
Map<String, String> getAuthenticationUrlToProviderName() {
|
||||
Iterable<RelyingPartyRegistration> relyingPartyRegistrations = null;
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository = this.context
|
||||
.getBean(RelyingPartyRegistrationRepository.class);
|
||||
ResolvableType type = ResolvableType.forInstance(relyingPartyRegistrationRepository).as(Iterable.class);
|
||||
if (type != ResolvableType.NONE
|
||||
&& RelyingPartyRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
|
||||
relyingPartyRegistrations = (Iterable<RelyingPartyRegistration>) relyingPartyRegistrationRepository;
|
||||
}
|
||||
if (relyingPartyRegistrations == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
String authenticationRequestProcessingUrl = DEFAULT_AUTHENTICATION_REQUEST_PROCESSING_URL;
|
||||
Map<String, String> saml2AuthenticationUrlToProviderName = new HashMap<>();
|
||||
relyingPartyRegistrations.forEach((registration) -> saml2AuthenticationUrlToProviderName.put(
|
||||
authenticationRequestProcessingUrl.replace("{registrationId}", registration.getRegistrationId()),
|
||||
registration.getRegistrationId()));
|
||||
return saml2AuthenticationUrlToProviderName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Marcus da Coregio
|
||||
* @since 5.7
|
||||
*/
|
||||
final class Saml2LoginBeanDefinitionParserUtils {
|
||||
|
||||
private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";
|
||||
|
||||
private static final String ATT_AUTHENTICATION_REQUEST_REPOSITORY_REF = "authentication-request-repository-ref";
|
||||
|
||||
private static final String ATT_AUTHENTICATION_REQUEST_RESOLVER_REF = "authentication-request-resolver-ref";
|
||||
|
||||
private static final String ATT_AUTHENTICATION_CONVERTER = "authentication-converter-ref";
|
||||
|
||||
private Saml2LoginBeanDefinitionParserUtils() {
|
||||
}
|
||||
|
||||
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 getAuthenticationRequestRepository(Element element) {
|
||||
String authenticationRequestRepositoryRef = element.getAttribute(ATT_AUTHENTICATION_REQUEST_REPOSITORY_REF);
|
||||
if (StringUtils.hasText(authenticationRequestRepositoryRef)) {
|
||||
return new RuntimeBeanReference(authenticationRequestRepositoryRef);
|
||||
}
|
||||
return BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSaml2AuthenticationRequestRepository.class)
|
||||
.getBeanDefinition();
|
||||
}
|
||||
|
||||
static BeanMetadataElement getAuthenticationRequestResolver(Element element) {
|
||||
String authenticationRequestContextResolver = element.getAttribute(ATT_AUTHENTICATION_REQUEST_RESOLVER_REF);
|
||||
if (StringUtils.hasText(authenticationRequestContextResolver)) {
|
||||
return new RuntimeBeanReference(authenticationRequestContextResolver);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static BeanMetadataElement createDefaultAuthenticationRequestResolver(
|
||||
BeanMetadataElement relyingPartyRegistrationRepository) {
|
||||
BeanMetadataElement defaultRelyingPartyRegistrationResolver = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class)
|
||||
.addConstructorArgValue(relyingPartyRegistrationRepository).getBeanDefinition();
|
||||
return BeanDefinitionBuilder.rootBeanDefinition(
|
||||
"org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver")
|
||||
.addConstructorArgValue(defaultRelyingPartyRegistrationResolver).getBeanDefinition();
|
||||
}
|
||||
|
||||
static BeanDefinition createAuthenticationProvider() {
|
||||
return BeanDefinitionBuilder.rootBeanDefinition(
|
||||
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider")
|
||||
.getBeanDefinition();
|
||||
}
|
||||
|
||||
static BeanMetadataElement getAuthenticationConverter(Element element) {
|
||||
String authenticationConverter = element.getAttribute(ATT_AUTHENTICATION_CONVERTER);
|
||||
if (StringUtils.hasText(authenticationConverter)) {
|
||||
return new RuntimeBeanReference(authenticationConverter);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static BeanDefinition createDefaultAuthenticationConverter(BeanMetadataElement relyingPartyRegistrationRepository) {
|
||||
AbstractBeanDefinition resolver = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class)
|
||||
.addConstructorArgValue(relyingPartyRegistrationRepository).getBeanDefinition();
|
||||
return BeanDefinitionBuilder.rootBeanDefinition(Saml2AuthenticationTokenConverter.class)
|
||||
.addConstructorArgValue(resolver).getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* 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.
|
||||
|
@ -47,6 +47,8 @@ enum SecurityFilters {
|
|||
|
||||
OAUTH2_AUTHORIZATION_REQUEST_FILTER,
|
||||
|
||||
SAML2_AUTHENTICATION_REQUEST_FILTER,
|
||||
|
||||
X509_FILTER,
|
||||
|
||||
PRE_AUTH_FILTER,
|
||||
|
@ -55,6 +57,8 @@ enum SecurityFilters {
|
|||
|
||||
OAUTH2_LOGIN_FILTER,
|
||||
|
||||
SAML2_AUTHENTICATION_FILTER,
|
||||
|
||||
FORM_LOGIN_FILTER,
|
||||
|
||||
LOGIN_PAGE_FILTER,
|
||||
|
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* 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.saml2;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.converter.RsaKeyConverters;
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
|
||||
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* @author Marcus da Coregio
|
||||
* @since 5.7
|
||||
*/
|
||||
public final class RelyingPartyRegistrationsBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String ELT_RELYING_PARTY_REGISTRATION = "relying-party-registration";
|
||||
|
||||
private static final String ELT_SIGNING_CREDENTIAL = "signing-credential";
|
||||
|
||||
private static final String ELT_DECRYPTION_CREDENTIAL = "decryption-credential";
|
||||
|
||||
private static final String ELT_ASSERTING_PARTY = "asserting-party";
|
||||
|
||||
private static final String ELT_VERIFICATION_CREDENTIAL = "verification-credential";
|
||||
|
||||
private static final String ELT_ENCRYPTION_CREDENTIAL = "encryption-credential";
|
||||
|
||||
private static final String ATT_REGISTRATION_ID = "registration-id";
|
||||
|
||||
private static final String ATT_ASSERTING_PARTY_ID = "asserting-party-id";
|
||||
|
||||
private static final String ATT_ENTITY_ID = "entity-id";
|
||||
|
||||
private static final String ATT_METADATA_LOCATION = "metadata-location";
|
||||
|
||||
private static final String ATT_ASSERTION_CONSUMER_SERVICE_LOCATION = "assertion-consumer-service-location";
|
||||
|
||||
private static final String ATT_ASSERTION_CONSUMER_SERVICE_BINDING = "assertion-consumer-service-binding";
|
||||
|
||||
private static final String ATT_PRIVATE_KEY_LOCATION = "private-key-location";
|
||||
|
||||
private static final String ATT_CERTIFICATE_LOCATION = "certificate-location";
|
||||
|
||||
private static final String ATT_WANT_AUTHN_REQUESTS_SIGNED = "want-authn-requests-signed";
|
||||
|
||||
private static final String ATT_SINGLE_SIGN_ON_SERVICE_LOCATION = "single-sign-on-service-location";
|
||||
|
||||
private static final String ATT_SINGLE_SIGN_ON_SERVICE_BINDING = "single-sign-on-service-binding";
|
||||
|
||||
private static final String ATT_SIGNING_ALGORITHMS = "signing-algorithms";
|
||||
|
||||
private static final ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
|
||||
parserContext.extractSource(element));
|
||||
parserContext.pushContainingComponent(compositeDef);
|
||||
Map<String, Map<String, Object>> assertingParties = getAssertingParties(element);
|
||||
List<RelyingPartyRegistration> relyingPartyRegistrations = getRelyingPartyRegistrations(element,
|
||||
assertingParties, parserContext);
|
||||
BeanDefinition relyingPartyRegistrationRepositoryBean = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(InMemoryRelyingPartyRegistrationRepository.class)
|
||||
.addConstructorArgValue(relyingPartyRegistrations).getBeanDefinition();
|
||||
String relyingPartyRegistrationRepositoryId = parserContext.getReaderContext()
|
||||
.generateBeanName(relyingPartyRegistrationRepositoryBean);
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(relyingPartyRegistrationRepositoryBean,
|
||||
relyingPartyRegistrationRepositoryId));
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Map<String, Object>> getAssertingParties(Element element) {
|
||||
List<Element> assertingPartyElts = DomUtils.getChildElementsByTagName(element, ELT_ASSERTING_PARTY);
|
||||
Map<String, Map<String, Object>> providers = new HashMap<>();
|
||||
for (Element assertingPartyElt : assertingPartyElts) {
|
||||
Map<String, Object> assertingParty = new HashMap<>();
|
||||
String assertingPartyId = assertingPartyElt.getAttribute(ATT_ASSERTING_PARTY_ID);
|
||||
String entityId = assertingPartyElt.getAttribute(ATT_ENTITY_ID);
|
||||
String wantAuthnRequestsSigned = assertingPartyElt.getAttribute(ATT_WANT_AUTHN_REQUESTS_SIGNED);
|
||||
String singleSignOnServiceLocation = assertingPartyElt.getAttribute(ATT_SINGLE_SIGN_ON_SERVICE_LOCATION);
|
||||
String singleSignOnServiceBinding = assertingPartyElt.getAttribute(ATT_SINGLE_SIGN_ON_SERVICE_BINDING);
|
||||
String signingAlgorithms = assertingPartyElt.getAttribute(ATT_SIGNING_ALGORITHMS);
|
||||
assertingParty.put(ATT_ASSERTING_PARTY_ID, assertingPartyId);
|
||||
assertingParty.put(ATT_ENTITY_ID, entityId);
|
||||
assertingParty.put(ATT_WANT_AUTHN_REQUESTS_SIGNED, wantAuthnRequestsSigned);
|
||||
assertingParty.put(ATT_SINGLE_SIGN_ON_SERVICE_LOCATION, singleSignOnServiceLocation);
|
||||
assertingParty.put(ATT_SINGLE_SIGN_ON_SERVICE_BINDING, singleSignOnServiceBinding);
|
||||
assertingParty.put(ATT_SIGNING_ALGORITHMS, signingAlgorithms);
|
||||
addVerificationCredentials(assertingPartyElt, assertingParty);
|
||||
addEncryptionCredentials(assertingPartyElt, assertingParty);
|
||||
providers.put(assertingPartyId, assertingParty);
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
|
||||
private static void addVerificationCredentials(Map<String, Object> assertingParty,
|
||||
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
|
||||
List<String> verificationCertificateLocations = (List<String>) assertingParty.get(ELT_VERIFICATION_CREDENTIAL);
|
||||
List<Saml2X509Credential> verificationCredentials = new ArrayList<>();
|
||||
for (String certificateLocation : verificationCertificateLocations) {
|
||||
verificationCredentials.add(getSaml2VerificationCredential(certificateLocation));
|
||||
}
|
||||
builder.verificationX509Credentials((credentials) -> credentials.addAll(verificationCredentials));
|
||||
}
|
||||
|
||||
private static void addEncryptionCredentials(Map<String, Object> assertingParty,
|
||||
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
|
||||
List<String> encryptionCertificateLocations = (List<String>) assertingParty.get(ELT_ENCRYPTION_CREDENTIAL);
|
||||
List<Saml2X509Credential> encryptionCredentials = new ArrayList<>();
|
||||
for (String certificateLocation : encryptionCertificateLocations) {
|
||||
encryptionCredentials.add(getSaml2EncryptionCredential(certificateLocation));
|
||||
}
|
||||
builder.encryptionX509Credentials((credentials) -> credentials.addAll(encryptionCredentials));
|
||||
}
|
||||
|
||||
private static void addVerificationCredentials(Element assertingPartyElt, Map<String, Object> assertingParty) {
|
||||
List<String> verificationCertificateLocations = new ArrayList<>();
|
||||
List<Element> verificationCredentialElts = DomUtils.getChildElementsByTagName(assertingPartyElt,
|
||||
ELT_VERIFICATION_CREDENTIAL);
|
||||
for (Element verificationCredentialElt : verificationCredentialElts) {
|
||||
String certificateLocation = verificationCredentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
|
||||
verificationCertificateLocations.add(certificateLocation);
|
||||
}
|
||||
assertingParty.put(ELT_VERIFICATION_CREDENTIAL, verificationCertificateLocations);
|
||||
}
|
||||
|
||||
private static void addEncryptionCredentials(Element assertingPartyElt, Map<String, Object> assertingParty) {
|
||||
List<String> encryptionCertificateLocations = new ArrayList<>();
|
||||
List<Element> encryptionCredentialElts = DomUtils.getChildElementsByTagName(assertingPartyElt,
|
||||
ELT_VERIFICATION_CREDENTIAL);
|
||||
for (Element encryptionCredentialElt : encryptionCredentialElts) {
|
||||
String certificateLocation = encryptionCredentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
|
||||
encryptionCertificateLocations.add(certificateLocation);
|
||||
}
|
||||
assertingParty.put(ELT_ENCRYPTION_CREDENTIAL, encryptionCertificateLocations);
|
||||
}
|
||||
|
||||
private List<RelyingPartyRegistration> getRelyingPartyRegistrations(Element element,
|
||||
Map<String, Map<String, Object>> assertingParties, ParserContext parserContext) {
|
||||
List<Element> relyingPartyRegistrationElts = DomUtils.getChildElementsByTagName(element,
|
||||
ELT_RELYING_PARTY_REGISTRATION);
|
||||
List<RelyingPartyRegistration> relyingPartyRegistrations = new ArrayList<>();
|
||||
for (Element relyingPartyRegistrationElt : relyingPartyRegistrationElts) {
|
||||
RelyingPartyRegistration.Builder builder = getBuilderFromMetadataLocationIfPossible(
|
||||
relyingPartyRegistrationElt, assertingParties, parserContext);
|
||||
addSigningCredentials(relyingPartyRegistrationElt, builder);
|
||||
addDecryptionCredentials(relyingPartyRegistrationElt, builder);
|
||||
relyingPartyRegistrations.add(builder.build());
|
||||
}
|
||||
return relyingPartyRegistrations;
|
||||
}
|
||||
|
||||
private static RelyingPartyRegistration.Builder getBuilderFromMetadataLocationIfPossible(
|
||||
Element relyingPartyRegistrationElt, Map<String, Map<String, Object>> assertingParties,
|
||||
ParserContext parserContext) {
|
||||
String registrationId = relyingPartyRegistrationElt.getAttribute(ATT_REGISTRATION_ID);
|
||||
String metadataLocation = relyingPartyRegistrationElt.getAttribute(ATT_METADATA_LOCATION);
|
||||
if (StringUtils.hasText(metadataLocation)) {
|
||||
return RelyingPartyRegistrations.fromMetadataLocation(metadataLocation).registrationId(registrationId);
|
||||
}
|
||||
String entityId = relyingPartyRegistrationElt.getAttribute(ATT_ENTITY_ID);
|
||||
String assertionConsumerServiceLocation = relyingPartyRegistrationElt
|
||||
.getAttribute(ATT_ASSERTION_CONSUMER_SERVICE_LOCATION);
|
||||
Saml2MessageBinding assertionConsumerServiceBinding = getAssertionConsumerServiceBinding(
|
||||
relyingPartyRegistrationElt);
|
||||
return RelyingPartyRegistration.withRegistrationId(registrationId).entityId(entityId)
|
||||
.assertionConsumerServiceLocation(assertionConsumerServiceLocation)
|
||||
.assertionConsumerServiceBinding(assertionConsumerServiceBinding)
|
||||
.assertingPartyDetails((builder) -> buildAssertingParty(relyingPartyRegistrationElt, assertingParties,
|
||||
builder, parserContext));
|
||||
}
|
||||
|
||||
private static void buildAssertingParty(Element relyingPartyElt, Map<String, Map<String, Object>> assertingParties,
|
||||
RelyingPartyRegistration.AssertingPartyDetails.Builder builder, ParserContext parserContext) {
|
||||
String assertingPartyId = relyingPartyElt.getAttribute(ATT_ASSERTING_PARTY_ID);
|
||||
if (!assertingParties.containsKey(assertingPartyId)) {
|
||||
Object source = parserContext.extractSource(relyingPartyElt);
|
||||
parserContext.getReaderContext()
|
||||
.error(String.format("Could not find asserting party with id %s", assertingPartyId), source);
|
||||
}
|
||||
Map<String, Object> assertingParty = assertingParties.get(assertingPartyId);
|
||||
String entityId = getAsString(assertingParty, ATT_ENTITY_ID);
|
||||
String wantAuthnRequestsSigned = getAsString(assertingParty, ATT_WANT_AUTHN_REQUESTS_SIGNED);
|
||||
String singleSignOnServiceLocation = getAsString(assertingParty, ATT_SINGLE_SIGN_ON_SERVICE_LOCATION);
|
||||
String singleSignOnServiceBinding = getAsString(assertingParty, ATT_SINGLE_SIGN_ON_SERVICE_BINDING);
|
||||
Saml2MessageBinding saml2MessageBinding = StringUtils.hasText(singleSignOnServiceBinding)
|
||||
? Saml2MessageBinding.valueOf(singleSignOnServiceBinding) : Saml2MessageBinding.REDIRECT;
|
||||
builder.entityId(entityId).wantAuthnRequestsSigned(Boolean.parseBoolean(wantAuthnRequestsSigned))
|
||||
.singleSignOnServiceLocation(singleSignOnServiceLocation)
|
||||
.singleSignOnServiceBinding(saml2MessageBinding);
|
||||
addSigningAlgorithms(assertingParty, builder);
|
||||
addVerificationCredentials(assertingParty, builder);
|
||||
addEncryptionCredentials(assertingParty, builder);
|
||||
}
|
||||
|
||||
private static void addSigningAlgorithms(Map<String, Object> assertingParty,
|
||||
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
|
||||
String signingAlgorithmsAttr = getAsString(assertingParty, ATT_SIGNING_ALGORITHMS);
|
||||
if (StringUtils.hasText(signingAlgorithmsAttr)) {
|
||||
List<String> signingAlgorithms = Arrays.asList(signingAlgorithmsAttr.split(","));
|
||||
builder.signingAlgorithms((s) -> s.addAll(signingAlgorithms));
|
||||
}
|
||||
}
|
||||
|
||||
private static void addSigningCredentials(Element relyingPartyRegistrationElt,
|
||||
RelyingPartyRegistration.Builder builder) {
|
||||
List<Element> credentialElts = DomUtils.getChildElementsByTagName(relyingPartyRegistrationElt,
|
||||
ELT_SIGNING_CREDENTIAL);
|
||||
for (Element credentialElt : credentialElts) {
|
||||
String privateKeyLocation = credentialElt.getAttribute(ATT_PRIVATE_KEY_LOCATION);
|
||||
String certificateLocation = credentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
|
||||
builder.signingX509Credentials(
|
||||
(c) -> c.add(getSaml2SigningCredential(privateKeyLocation, certificateLocation)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void addDecryptionCredentials(Element relyingPartyRegistrationElt,
|
||||
RelyingPartyRegistration.Builder builder) {
|
||||
List<Element> credentialElts = DomUtils.getChildElementsByTagName(relyingPartyRegistrationElt,
|
||||
ELT_DECRYPTION_CREDENTIAL);
|
||||
for (Element credentialElt : credentialElts) {
|
||||
String privateKeyLocation = credentialElt.getAttribute(ATT_PRIVATE_KEY_LOCATION);
|
||||
String certificateLocation = credentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
|
||||
Saml2X509Credential credential = getSaml2DecryptionCredential(privateKeyLocation, certificateLocation);
|
||||
builder.decryptionX509Credentials((c) -> c.add(credential));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getAsString(Map<String, Object> assertingParty, String key) {
|
||||
return (String) assertingParty.get(key);
|
||||
}
|
||||
|
||||
private static Saml2MessageBinding getAssertionConsumerServiceBinding(Element relyingPartyRegistrationElt) {
|
||||
String assertionConsumerServiceBinding = relyingPartyRegistrationElt
|
||||
.getAttribute(ATT_ASSERTION_CONSUMER_SERVICE_BINDING);
|
||||
if (StringUtils.hasText(assertionConsumerServiceBinding)) {
|
||||
return Saml2MessageBinding.valueOf(assertionConsumerServiceBinding);
|
||||
}
|
||||
return Saml2MessageBinding.REDIRECT;
|
||||
}
|
||||
|
||||
private static Saml2X509Credential getSaml2VerificationCredential(String certificateLocation) {
|
||||
return getSaml2Credential(certificateLocation, Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
|
||||
}
|
||||
|
||||
private static Saml2X509Credential getSaml2EncryptionCredential(String certificateLocation) {
|
||||
return getSaml2Credential(certificateLocation, Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
|
||||
}
|
||||
|
||||
private static Saml2X509Credential getSaml2SigningCredential(String privateKeyLocation,
|
||||
String certificateLocation) {
|
||||
return getSaml2Credential(privateKeyLocation, certificateLocation,
|
||||
Saml2X509Credential.Saml2X509CredentialType.SIGNING);
|
||||
}
|
||||
|
||||
private static Saml2X509Credential getSaml2DecryptionCredential(String privateKeyLocation,
|
||||
String certificateLocation) {
|
||||
return getSaml2Credential(privateKeyLocation, certificateLocation,
|
||||
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
|
||||
}
|
||||
|
||||
private static Saml2X509Credential getSaml2Credential(String privateKeyLocation, String certificateLocation,
|
||||
Saml2X509Credential.Saml2X509CredentialType credentialType) {
|
||||
RSAPrivateKey privateKey = readPrivateKey(privateKeyLocation);
|
||||
X509Certificate certificate = readCertificate(certificateLocation);
|
||||
return new Saml2X509Credential(privateKey, certificate, credentialType);
|
||||
}
|
||||
|
||||
private static Saml2X509Credential getSaml2Credential(String certificateLocation,
|
||||
Saml2X509Credential.Saml2X509CredentialType credentialType) {
|
||||
X509Certificate certificate = readCertificate(certificateLocation);
|
||||
return new Saml2X509Credential(certificate, credentialType);
|
||||
}
|
||||
|
||||
private static RSAPrivateKey readPrivateKey(String privateKeyLocation) {
|
||||
Resource privateKey = resourceLoader.getResource(privateKeyLocation);
|
||||
try (InputStream inputStream = privateKey.getInputStream()) {
|
||||
return RsaKeyConverters.pkcs8().convert(inputStream);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate readCertificate(String certificateLocation) {
|
||||
Resource certificate = resourceLoader.getResource(certificateLocation);
|
||||
try (InputStream inputStream = certificate.getInputStream()) {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(inputStream);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -312,7 +312,7 @@ http-firewall =
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & oauth2-login? & oauth2-client? & oauth2-resource-server? & x509? & jee? & http-basic? & logout? & password-management? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) }
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & oauth2-login? & oauth2-client? & oauth2-resource-server? & saml2-login? & x509? & jee? & http-basic? & logout? & password-management? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) }
|
||||
http.attlist &=
|
||||
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
|
||||
attribute pattern {xsd:token}?
|
||||
|
@ -630,6 +630,126 @@ opaque-token.attlist &=
|
|||
## Reference to an OpaqueTokenIntrospector
|
||||
attribute introspector-ref {xsd:token}?
|
||||
|
||||
saml2-login =
|
||||
## Configures authentication support for SAML 2.0 Login
|
||||
element saml2-login {saml2-login.attlist}
|
||||
saml2-login.attlist &=
|
||||
## Reference to the RelyingPartyRegistrationRepository
|
||||
attribute relying-party-registration-repository-ref {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## Reference to the Saml2AuthenticationRequestRepository
|
||||
attribute authentication-request-repository-ref {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## Reference to the Saml2AuthenticationRequestResolver
|
||||
attribute authentication-request-resolver-ref {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## Reference to the AuthenticationConverter
|
||||
attribute authentication-converter-ref {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## The URI where the filter processes authentication requests
|
||||
attribute login-processing-url {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## The URI to send users to login
|
||||
attribute login-page {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## Reference to the AuthenticationSuccessHandler
|
||||
attribute authentication-success-handler-ref {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## Reference to the AuthenticationFailureHandler
|
||||
attribute authentication-failure-handler-ref {xsd:token}?
|
||||
saml2-login.attlist &=
|
||||
## Reference to the AuthenticationManager
|
||||
attribute authentication-manager-ref {xsd:token}?
|
||||
|
||||
relying-party-registrations =
|
||||
## Container element for relying party(ies) registered with a SAML 2.0 identity provider
|
||||
element relying-party-registrations {relying-party-registration+, asserting-party*}
|
||||
|
||||
relying-party-registration =
|
||||
## Represents a relying party registered with a SAML 2.0 identity provider
|
||||
element relying-party-registration {relying-party-registration.attlist, signing-credential*, decryption-credential*}
|
||||
relying-party-registration.attlist &=
|
||||
## The ID that uniquely identifies the relying party registration.
|
||||
attribute registration-id {xsd:token}
|
||||
relying-party-registration.attlist &=
|
||||
## The location of the Identity Provider's metadata.
|
||||
attribute metadata-location {xsd:token}?
|
||||
relying-party-registration.attlist &=
|
||||
## The relying party's EntityID
|
||||
attribute entity-id {xsd:token}?
|
||||
relying-party-registration.attlist &=
|
||||
## The Assertion Consumer Service Location
|
||||
attribute assertion-consumer-service-location {xsd:token}?
|
||||
relying-party-registration.attlist &=
|
||||
## The Assertion Consumer Service Binding
|
||||
attribute assertion-consumer-service-binding {xsd:token}?
|
||||
relying-party-registration.attlist &=
|
||||
## A reference to the associated asserting party.
|
||||
attribute asserting-party-id {xsd:token}?
|
||||
|
||||
signing-credential =
|
||||
## The relying party's signing credential
|
||||
element signing-credential {signing-credential.attlist}
|
||||
signing-credential.attlist &=
|
||||
## The private key location
|
||||
attribute private-key-location {xsd:token}
|
||||
signing-credential.attlist &=
|
||||
## The certificate location
|
||||
attribute certificate-location {xsd:token}
|
||||
|
||||
decryption-credential =
|
||||
## The relying party's decryption credential
|
||||
element decryption-credential {decryption-credential.attlist}
|
||||
decryption-credential.attlist &=
|
||||
## The private key location
|
||||
attribute private-key-location {xsd:token}
|
||||
decryption-credential.attlist &=
|
||||
## The certificate location
|
||||
attribute certificate-location {xsd:token}
|
||||
|
||||
asserting-party =
|
||||
## The configuration metadata of the Asserting party
|
||||
element asserting-party {asserting-party.attlist, verification-credential*, encryption-credential*}
|
||||
asserting-party.attlist &=
|
||||
## A unique identifier of the asserting party.
|
||||
attribute asserting-party-id {xsd:token}
|
||||
asserting-party.attlist &=
|
||||
## The asserting party's EntityID.
|
||||
attribute entity-id {xsd:token}
|
||||
asserting-party.attlist &=
|
||||
## Indicates the asserting party's preference that relying parties should sign the AuthnRequest before sending
|
||||
attribute want-authn-requests-signed {xsd:token}?
|
||||
asserting-party.attlist &=
|
||||
## The <a href="https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint">SingleSignOnService</a> Location.
|
||||
attribute single-sign-on-service-location {xsd:token}
|
||||
asserting-party.attlist &=
|
||||
## The <a href="https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint">SingleSignOnService</a> Binding.
|
||||
attribute single-sign-on-service-binding {xsd:token}?
|
||||
asserting-party.attlist &=
|
||||
## A comma separated list of org.opensaml.saml.ext.saml2alg.SigningMethod Algorithms for this asserting party, in preference order.
|
||||
attribute signing-algorithms {xsd:token}?
|
||||
|
||||
verification-credential =
|
||||
## The relying party's verification credential
|
||||
element verification-credential {verification-credential.attlist}
|
||||
verification-credential.attlist &=
|
||||
## The private key location
|
||||
attribute private-key-location {xsd:token}
|
||||
verification-credential.attlist &=
|
||||
## The certificate location
|
||||
attribute certificate-location {xsd:token}
|
||||
|
||||
encryption-credential =
|
||||
## The asserting party's encryption credential
|
||||
element encryption-credential {encryption-credential.attlist}
|
||||
encryption-credential.attlist &=
|
||||
## The private key location
|
||||
attribute private-key-location {xsd:token}
|
||||
encryption-credential.attlist &=
|
||||
## The certificate location
|
||||
attribute certificate-location {xsd:token}
|
||||
|
||||
|
||||
filter-chain-map =
|
||||
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
|
||||
element filter-chain-map {filter-chain-map.attlist, filter-chain+}
|
||||
|
@ -1118,4 +1238,4 @@ position =
|
|||
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
|
||||
attribute position {named-security-filter}
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "FORM_LOGIN_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "SAML2_AUTHENTICATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "SAML2_AUTHENTICATION_FILTER" | "FORM_LOGIN_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
|
|
|
@ -1015,6 +1015,15 @@
|
|||
<xs:element ref="security:oauth2-login"/>
|
||||
<xs:element ref="security:oauth2-client"/>
|
||||
<xs:element ref="security:oauth2-resource-server"/>
|
||||
<xs:element name="saml2-login">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Configures authentication support for SAML 2.0 Login
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:saml2-login.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="x509">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Adds support for X.509 client authentication.
|
||||
|
@ -1920,6 +1929,275 @@
|
|||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:attributeGroup name="saml2-login.attlist">
|
||||
<xs:attribute name="relying-party-registration-repository-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the RelyingPartyRegistrationRepository
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-request-repository-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the Saml2AuthenticationRequestRepository
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-request-resolver-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the Saml2AuthenticationRequestResolver
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-converter-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the AuthenticationConverter
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="login-processing-url" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The URI where the filter processes authentication requests
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="login-page" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The URI to send users to login
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-success-handler-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the AuthenticationSuccessHandler
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-failure-handler-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the AuthenticationFailureHandler
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-manager-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to the AuthenticationManager
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="relying-party-registrations">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Container element for relying party(ies) registered with a SAML 2.0 identity provider
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" ref="security:relying-party-registration"/>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:asserting-party"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="relying-party-registration">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Represents a relying party registered with a SAML 2.0 identity provider
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:signing-credential"/>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:decryption-credential"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="security:relying-party-registration.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="relying-party-registration.attlist">
|
||||
<xs:attribute name="registration-id" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The ID that uniquely identifies the relying party registration.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="metadata-location" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The location of the Identity Provider's metadata.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="entity-id" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The relying party's EntityID
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="assertion-consumer-service-location" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The Assertion Consumer Service Location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="assertion-consumer-service-binding" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The Assertion Consumer Service Binding
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="asserting-party-id" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to the associated asserting party.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="signing-credential">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The relying party's signing credential
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:signing-credential.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="signing-credential.attlist">
|
||||
<xs:attribute name="private-key-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The private key location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="certificate-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The certificate location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="decryption-credential">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The relying party's decryption credential
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:decryption-credential.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="decryption-credential.attlist">
|
||||
<xs:attribute name="private-key-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The private key location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="certificate-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The certificate location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="asserting-party">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The configuration metadata of the Asserting party
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:verification-credential"/>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:encryption-credential"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="security:asserting-party.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="asserting-party.attlist">
|
||||
<xs:attribute name="asserting-party-id" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A unique identifier of the asserting party.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="entity-id" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The asserting party's EntityID.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="want-authn-requests-signed" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates the asserting party's preference that relying parties should sign the
|
||||
AuthnRequest before sending
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="single-sign-on-service-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The <a
|
||||
href="https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint">SingleSignOnService</a>
|
||||
Location.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="single-sign-on-service-binding" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The <a
|
||||
href="https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint">SingleSignOnService</a>
|
||||
Binding.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="signing-algorithms" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma separated list of org.opensaml.saml.ext.saml2alg.SigningMethod Algorithms for this
|
||||
asserting party, in preference order.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="verification-credential">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The relying party's verification credential
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:verification-credential.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="verification-credential.attlist">
|
||||
<xs:attribute name="private-key-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The private key location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="certificate-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The certificate location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="encryption-credential">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The asserting party's encryption credential
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:encryption-credential.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="encryption-credential.attlist">
|
||||
<xs:attribute name="private-key-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The private key location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="certificate-location" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The certificate location
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="filter-chain-map">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
|
||||
|
@ -3241,10 +3519,12 @@
|
|||
<xs:enumeration value="CSRF_FILTER"/>
|
||||
<xs:enumeration value="LOGOUT_FILTER"/>
|
||||
<xs:enumeration value="OAUTH2_AUTHORIZATION_REQUEST_FILTER"/>
|
||||
<xs:enumeration value="SAML2_AUTHENTICATION_REQUEST_FILTER"/>
|
||||
<xs:enumeration value="X509_FILTER"/>
|
||||
<xs:enumeration value="PRE_AUTH_FILTER"/>
|
||||
<xs:enumeration value="CAS_FILTER"/>
|
||||
<xs:enumeration value="OAUTH2_LOGIN_FILTER"/>
|
||||
<xs:enumeration value="SAML2_AUTHENTICATION_FILTER"/>
|
||||
<xs:enumeration value="FORM_LOGIN_FILTER"/>
|
||||
<xs:enumeration value="LOGIN_PAGE_FILTER"/>
|
||||
<xs:enumeration value="LOGOUT_PAGE_FILTER"/>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:variable name="elts-to-inline">
|
||||
<xsl:text>,access-denied-handler,anonymous,session-management,concurrency-control,after-invocation-provider,authentication-provider,ldap-authentication-provider,user,port-mapping,openid-login,expression-handler,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,add-headers,</xsl:text>
|
||||
<xsl:text>,access-denied-handler,anonymous,session-management,concurrency-control,after-invocation-provider,authentication-provider,ldap-authentication-provider,user,port-mapping,openid-login,saml2-login,expression-handler,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,add-headers,</xsl:text>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:template match="xs:element">
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* 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 jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
||||
import org.springframework.security.saml2.core.Saml2Utils;
|
||||
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
||||
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
|
||||
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationRequestContexts;
|
||||
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.registration.TestRelyingPartyRegistrations;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
|
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
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.result.MockMvcResultMatchers.redirectedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link Saml2LoginBeanDefinitionParser}
|
||||
*
|
||||
* @author Marcus da Coregio
|
||||
*/
|
||||
@ExtendWith({ SpringExtension.class, SpringTestContextExtension.class })
|
||||
@SecurityTestExecutionListeners
|
||||
public class Saml2LoginBeanDefinitionParserTests {
|
||||
|
||||
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/http/Saml2LoginBeanDefinitionParserTests";
|
||||
|
||||
private static final String SIGNED_RESPONSE = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9ycC5leGFtcGxlLm9yZy9hY3MiIElEPSJfYzE3MzM2YTAtNTM1My00MTQ5LWI3MmMtMDNkOWY5YWYzMDdlIiBJc3N1ZUluc3RhbnQ9IjIwMjAtMDgtMDRUMjI6MDQ6NDUuMDE2WiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj5hcC1lbnRpdHktaWQ8L3NhbWwyOklzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj4KPGRzOlNpZ25lZEluZm8+CjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+CjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+CjxkczpSZWZlcmVuY2UgVVJJPSIjX2MxNzMzNmEwLTUzNTMtNDE0OS1iNzJjLTAzZDlmOWFmMzA3ZSI+CjxkczpUcmFuc2Zvcm1zPgo8ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz4KPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPgo8L2RzOlRyYW5zZm9ybXM+CjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz4KPGRzOkRpZ2VzdFZhbHVlPjYzTmlyenFzaDVVa0h1a3NuRWUrM0hWWU5aYWFsQW1OQXFMc1lGMlRuRDA9PC9kczpEaWdlc3RWYWx1ZT4KPC9kczpSZWZlcmVuY2U+CjwvZHM6U2lnbmVkSW5mbz4KPGRzOlNpZ25hdHVyZVZhbHVlPgpLMVlvWWJVUjBTclY4RTdVMkhxTTIvZUNTOTNoV25mOExnNnozeGZWMUlyalgzSXhWYkNvMVlYcnRBSGRwRVdvYTJKKzVOMmFNbFBHJiMxMzsKN2VpbDBZRC9xdUVRamRYbTNwQTBjZmEvY25pa2RuKzVhbnM0ZWQwanU1amo2dkpvZ2w2Smt4Q25LWUpwTU9HNzhtampmb0phengrWCYjMTM7CkM2NktQVStBYUdxeGVwUEQ1ZlhRdTFKSy9Jb3lBaitaa3k4Z2Jwc3VyZHFCSEJLRWxjdnVOWS92UGY0OGtBeFZBKzdtRGhNNUMvL1AmIzEzOwp0L084Y3NZYXB2UjZjdjZrdk45QXZ1N3FRdm9qVk1McHVxZWNJZDJwTUVYb0NSSnE2Nkd4MStNTUVPeHVpMWZZQlRoMEhhYjRmK3JyJiMxMzsKOEY2V1NFRC8xZllVeHliRkJqZ1Q4d2lEWHFBRU8wSVY4ZWRQeEE9PQo8L2RzOlNpZ25hdHVyZVZhbHVlPgo8L2RzOlNpZ25hdHVyZT48c2FtbDI6QXNzZXJ0aW9uIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iQWUzZjQ5OGI4LTliMTctNDA3OC05ZDM1LTg2YTA4NDA4NDk5NSIgSXNzdWVJbnN0YW50PSIyMDIwLTA4LTA0VDIyOjA0OjQ1LjA3N1oiIFZlcnNpb249IjIuMCI+PHNhbWwyOklzc3Vlcj5hcC1lbnRpdHktaWQ8L3NhbWwyOklzc3Vlcj48c2FtbDI6U3ViamVjdD48c2FtbDI6TmFtZUlEPnRlc3RAc2FtbC51c2VyPC9zYW1sMjpOYW1lSUQ+PHNhbWwyOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDI6U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgTm90QmVmb3JlPSIyMDIwLTA4LTA0VDIxOjU5OjQ1LjA5MFoiIE5vdE9uT3JBZnRlcj0iMjA0MC0wNy0zMFQyMjowNTowNi4wODhaIiBSZWNpcGllbnQ9Imh0dHBzOi8vcnAuZXhhbXBsZS5vcmcvYWNzIi8+PC9zYW1sMjpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDI6U3ViamVjdD48c2FtbDI6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjAtMDgtMDRUMjE6NTk6NDUuMDgwWiIgTm90T25PckFmdGVyPSIyMDQwLTA3LTMwVDIyOjA1OjA2LjA4N1oiLz48L3NhbWwyOkFzc2VydGlvbj48L3NhbWwycDpSZXNwb25zZT4=";
|
||||
|
||||
private static final String IDP_SSO_URL = "https://sso-url.example.com/IDP/SSO";
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired(required = false)
|
||||
private RequestCache requestCache;
|
||||
|
||||
@Autowired(required = false)
|
||||
private AuthenticationFailureHandler authenticationFailureHandler;
|
||||
|
||||
@Autowired(required = false)
|
||||
private AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||
|
||||
@Autowired(required = false)
|
||||
private RelyingPartyRegistrationRepository repository;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ApplicationListener<AuthenticationSuccessEvent> authenticationSuccessListener;
|
||||
|
||||
@Autowired(required = false)
|
||||
private AuthenticationConverter authenticationConverter;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Saml2AuthenticationRequestResolver authenticationRequestResolver;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void requestWhenSingleRelyingPartyRegistrationThenAutoRedirect() throws Exception {
|
||||
this.spring.configLocations(this.xml("SingleRelyingPartyRegistration")).autowire();
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrl("http://localhost/saml2/authenticate/one"));
|
||||
// @formatter:on
|
||||
verify(this.requestCache).saveRequest(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenMultiRelyingPartyRegistrationThenRedirectToLoginWithRelyingParties() throws Exception {
|
||||
this.spring.configLocations(this.xml("MultiRelyingPartyRegistration")).autowire();
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrl("http://localhost/login"));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestLoginWhenMultiRelyingPartyRegistrationThenReturnLoginPageWithRelyingParties() throws Exception {
|
||||
this.spring.configLocations(this.xml("MultiRelyingPartyRegistration")).autowire();
|
||||
// @formatter:off
|
||||
MvcResult mvcResult = this.mvc.perform(get("/login"))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
String pageContent = mvcResult.getResponse().getContentAsString();
|
||||
assertThat(pageContent).contains("<a href=\"/saml2/authenticate/two\">two</a>");
|
||||
assertThat(pageContent).contains("<a href=\"/saml2/authenticate/one\">one</a>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenAuthenticationResponseNotValidThenThrowAuthenticationException() throws Exception {
|
||||
this.spring.configLocations(this.xml("SingleRelyingPartyRegistration-WithCustomAuthenticationFailureHandler"))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/login/saml2/sso/one").param(Saml2ParameterNames.SAML_RESPONSE, "samlResponse123"));
|
||||
ArgumentCaptor<AuthenticationException> exceptionCaptor = ArgumentCaptor
|
||||
.forClass(AuthenticationException.class);
|
||||
verify(this.authenticationFailureHandler).onAuthenticationFailure(any(), any(), exceptionCaptor.capture());
|
||||
AuthenticationException exception = exceptionCaptor.getValue();
|
||||
assertThat(exception).isInstanceOf(Saml2AuthenticationException.class);
|
||||
assertThat(((Saml2AuthenticationException) exception).getSaml2Error().getErrorCode())
|
||||
.isEqualTo("invalid_response");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenAuthenticationResponseValidThenAuthenticate() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomRelyingPartyRepository")).autowire();
|
||||
RelyingPartyRegistration relyingPartyRegistration = relyingPartyRegistrationWithVerifyingCredential();
|
||||
// @formatter:off
|
||||
this.mvc.perform(post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId()).param(Saml2ParameterNames.SAML_RESPONSE, SIGNED_RESPONSE))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().is2xxSuccessful());
|
||||
// @formatter:on
|
||||
ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
|
||||
verify(this.authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
|
||||
Authentication authentication = authenticationCaptor.getValue();
|
||||
assertThat(authentication.getPrincipal()).isInstanceOf(Saml2AuthenticatedPrincipal.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenAuthenticationResponseValidThenAuthenticationSuccessEventPublished() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomRelyingPartyRepository")).autowire();
|
||||
RelyingPartyRegistration relyingPartyRegistration = relyingPartyRegistrationWithVerifyingCredential();
|
||||
// @formatter:off
|
||||
this.mvc.perform(post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId()).param(Saml2ParameterNames.SAML_RESPONSE, SIGNED_RESPONSE))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().is2xxSuccessful());
|
||||
// @formatter:on
|
||||
verify(this.authenticationSuccessListener).onApplicationEvent(any(AuthenticationSuccessEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthenticationConverterThenUses() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthenticationConverter"))
|
||||
.autowire();
|
||||
RelyingPartyRegistration relyingPartyRegistration = relyingPartyRegistrationWithVerifyingCredential();
|
||||
String response = new String(Saml2Utils.samlDecode(SIGNED_RESPONSE));
|
||||
given(this.authenticationConverter.convert(any(HttpServletRequest.class)))
|
||||
.willReturn(new Saml2AuthenticationToken(relyingPartyRegistration, response));
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder request = post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId())
|
||||
.param("SAMLResponse", SIGNED_RESPONSE);
|
||||
// @formatter:on
|
||||
this.mvc.perform(request).andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("/"));
|
||||
verify(this.authenticationConverter).convert(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthenticationManagerThenUses() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthenticationManager"))
|
||||
.autowire();
|
||||
RelyingPartyRegistration relyingPartyRegistration = relyingPartyRegistrationWithVerifyingCredential();
|
||||
AuthenticationManager authenticationManager = this.applicationContext.getBean("customAuthenticationManager",
|
||||
AuthenticationManager.class);
|
||||
String response = new String(Saml2Utils.samlDecode(SIGNED_RESPONSE));
|
||||
given(authenticationManager.authenticate(any()))
|
||||
.willReturn(new Saml2AuthenticationToken(relyingPartyRegistration, response));
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder request = post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId())
|
||||
.param("SAMLResponse", SIGNED_RESPONSE);
|
||||
// @formatter:on
|
||||
this.mvc.perform(request).andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("/"));
|
||||
verify(authenticationManager).authenticate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationRequestWhenCustomAuthenticationRequestContextResolverThenUses() throws Exception {
|
||||
this.spring
|
||||
.configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthenticationRequestResolver"))
|
||||
.autowire();
|
||||
Saml2RedirectAuthenticationRequest request = Saml2RedirectAuthenticationRequest
|
||||
.withAuthenticationRequestContext(
|
||||
TestSaml2AuthenticationRequestContexts.authenticationRequestContext().build())
|
||||
.samlRequest("request").authenticationRequestUri(IDP_SSO_URL).build();
|
||||
given(this.authenticationRequestResolver.resolve(any(HttpServletRequest.class))).willReturn(request);
|
||||
this.mvc.perform(get("/saml2/authenticate/registration-id")).andExpect(status().isFound());
|
||||
verify(this.authenticationRequestResolver).resolve(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationRequestWhenCustomAuthnRequestRepositoryThenUses() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthnRequestRepository"))
|
||||
.autowire();
|
||||
given(this.repository.findByRegistrationId(anyString()))
|
||||
.willReturn(TestRelyingPartyRegistrations.relyingPartyRegistration().build());
|
||||
MockHttpServletRequestBuilder request = get("/saml2/authenticate/registration-id");
|
||||
this.mvc.perform(request).andExpect(status().isFound());
|
||||
verify(this.authenticationRequestRepository).saveAuthenticationRequest(
|
||||
any(AbstractSaml2AuthenticationRequest.class), any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthnRequestRepositoryThenUses() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthnRequestRepository"))
|
||||
.autowire();
|
||||
RelyingPartyRegistrationRepository repository = mock(RelyingPartyRegistrationRepository.class);
|
||||
given(this.repository.findByRegistrationId(anyString()))
|
||||
.willReturn(TestRelyingPartyRegistrations.relyingPartyRegistration().build());
|
||||
MockHttpServletRequestBuilder request = post("/login/saml2/sso/registration-id").param("SAMLResponse",
|
||||
SIGNED_RESPONSE);
|
||||
this.mvc.perform(request);
|
||||
verify(this.authenticationRequestRepository).loadAuthenticationRequest(any(HttpServletRequest.class));
|
||||
verify(this.authenticationRequestRepository).removeAuthenticationRequest(any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saml2LoginWhenLoginProcessingUrlWithoutRegistrationIdAndDefaultAuthenticationConverterThenValidates() {
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> this.spring.configLocations(this.xml("WithCustomLoginProcessingUrl")).autowire())
|
||||
.withMessageContaining("loginProcessingUrl must contain {registrationId} path variable");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomLoginProcessingUrlAndCustomAuthenticationConverterThenAuthenticate()
|
||||
throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomLoginProcessingUrl-WithCustomAuthenticationConverter"))
|
||||
.autowire();
|
||||
RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.noCredentials()
|
||||
.assertingPartyDetails((party) -> party.verificationX509Credentials(
|
||||
(c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())))
|
||||
.build();
|
||||
String response = new String(Saml2Utils.samlDecode(SIGNED_RESPONSE));
|
||||
given(this.authenticationConverter.convert(any(HttpServletRequest.class)))
|
||||
.willReturn(new Saml2AuthenticationToken(relyingPartyRegistration, response));
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder request = post("/my/custom/url").param("SAMLResponse", SIGNED_RESPONSE);
|
||||
// @formatter:on
|
||||
this.mvc.perform(request).andExpect(redirectedUrl("/"));
|
||||
verify(this.authenticationConverter).convert(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
private RelyingPartyRegistration relyingPartyRegistrationWithVerifyingCredential() {
|
||||
RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.noCredentials()
|
||||
.assertingPartyDetails((party) -> party.verificationX509Credentials(
|
||||
(c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())))
|
||||
.build();
|
||||
given(this.repository.findByRegistrationId(anyString())).willReturn(relyingPartyRegistration);
|
||||
return relyingPartyRegistration;
|
||||
}
|
||||
|
||||
private String xml(String configName) {
|
||||
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* 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.saml2;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||
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.registration.Saml2MessageBinding;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RelyingPartyRegistrationsBeanDefinitionParser}.
|
||||
*
|
||||
* @author Marcus da Coregio
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class RelyingPartyRegistrationsBeanDefinitionParserTests {
|
||||
|
||||
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/saml2/RelyingPartyRegistrationsBeanDefinitionParserTests";
|
||||
|
||||
// @formatter:off
|
||||
private static final String METADATA_LOCATION_XML_CONFIG = "<b:beans xmlns:b=\"http://www.springframework.org/schema/beans\"\n" +
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
||||
" xmlns=\"http://www.springframework.org/schema/security\"\n" +
|
||||
" xsi:schemaLocation=\"\n" +
|
||||
"\t\t\thttp://www.springframework.org/schema/security\n" +
|
||||
"\t\t\thttps://www.springframework.org/schema/security/spring-security.xsd\n" +
|
||||
"\t\t\thttp://www.springframework.org/schema/beans\n" +
|
||||
"\t\t\thttps://www.springframework.org/schema/beans/spring-beans.xsd\">\n" +
|
||||
" \n" +
|
||||
" <relying-party-registrations>\n" +
|
||||
" <relying-party-registration registration-id=\"one\"\n" +
|
||||
" metadata-location=\"${metadata-location}\"/>\n" +
|
||||
" </relying-party-registrations>\n" +
|
||||
"\n" +
|
||||
"</b:beans>\n";
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private static final String METADATA_RESPONSE = "<?xml version=\"1.0\"?>\n" +
|
||||
"<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" entityID=\"https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php\" ID=\"_e793a707d3e1a9ee6cbec7454fdad2c7cd793dd3703179a527b9620a6e9682af\"><ds:Signature>\n" +
|
||||
" <ds:SignedInfo><ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\n" +
|
||||
" <ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\"/>\n" +
|
||||
" <ds:Reference URI=\"#_e793a707d3e1a9ee6cbec7454fdad2c7cd793dd3703179a527b9620a6e9682af\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/><ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/></ds:Transforms><ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"/><ds:DigestValue>qIGOB+m2Kuq9Vp6F9qs/EFvFzuo6qEGukjICPyVAkjk=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>NgKak4k9LBAqbi8Za8ALUXW1l4npZ4+MOf8jhmpePDP3msbzjeKkkWFgxx+ILLJYwZzVWd3l028xm2l+SBOwoYRKJ670NgcdSdj6plBTGiZ5NXsXrX5M0zmgvAShREgjth/BKTUct5UVJOTqIxOPwBuCnj+Nn1+QUtY9ekPLrM0O2i+g1wckKaP6D7N+uVBwNgZGoOj5bZ082G7QXRX6Jo0925uKczAIKdIiBbMeKa/0phS2L97AkgQRGi2+j8V66TaDWuDSwd9hA2qzCwjsNui4DVLBwP0/LvgUdcu8g7JBIZ1yTddfByefOTVsU7UuZXkYEn4jU2ouk+u5klSo3Q==</ds:SignatureValue>\n" +
|
||||
"<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>\n" +
|
||||
" <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n" +
|
||||
" <md:KeyDescriptor use=\"signing\">\n" +
|
||||
" <ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
|
||||
" <ds:X509Data>\n" +
|
||||
" <ds:X509Certificate>MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk</ds:X509Certificate>\n" +
|
||||
" </ds:X509Data>\n" +
|
||||
" </ds:KeyInfo>\n" +
|
||||
" </md:KeyDescriptor>\n" +
|
||||
" <md:KeyDescriptor use=\"encryption\">\n" +
|
||||
" <ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
|
||||
" <ds:X509Data>\n" +
|
||||
" <ds:X509Certificate>MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk</ds:X509Certificate>\n" +
|
||||
" </ds:X509Data>\n" +
|
||||
" </ds:KeyInfo>\n" +
|
||||
" </md:KeyDescriptor>\n" +
|
||||
" <md:SingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SingleLogoutService.php\"/>\n" +
|
||||
" <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>\n" +
|
||||
" <md:SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php\"/>\n" +
|
||||
" </md:IDPSSODescriptor>\n" +
|
||||
" <md:ContactPerson contactType=\"technical\">\n" +
|
||||
" <md:GivenName>John</md:GivenName>\n" +
|
||||
" <md:SurName>Doe</md:SurName>\n" +
|
||||
" <md:EmailAddress>john@doe.com</md:EmailAddress>\n" +
|
||||
" </md:ContactPerson>\n" +
|
||||
"</md:EntityDescriptor>\n";
|
||||
// @formatter:on
|
||||
|
||||
@Autowired
|
||||
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
@AfterEach
|
||||
void cleanup() throws Exception {
|
||||
if (this.server != null) {
|
||||
this.server.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseWhenMetadataLocationConfiguredThenRequestMetadataFromLocation() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String serverUrl = this.server.url("/").toString();
|
||||
this.server.enqueue(xmlResponse(METADATA_RESPONSE));
|
||||
String metadataConfig = METADATA_LOCATION_XML_CONFIG.replace("${metadata-location}", serverUrl);
|
||||
this.spring.context(metadataConfig).autowire();
|
||||
assertThat(this.relyingPartyRegistrationRepository)
|
||||
.isInstanceOf(InMemoryRelyingPartyRegistrationRepository.class);
|
||||
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationRepository
|
||||
.findByRegistrationId("one");
|
||||
RelyingPartyRegistration.AssertingPartyDetails assertingPartyDetails = relyingPartyRegistration
|
||||
.getAssertingPartyDetails();
|
||||
assertThat(relyingPartyRegistration).isNotNull();
|
||||
assertThat(relyingPartyRegistration.getRegistrationId()).isEqualTo("one");
|
||||
assertThat(relyingPartyRegistration.getEntityId())
|
||||
.isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceLocation())
|
||||
.isEqualTo("{baseUrl}/login/saml2/sso/{registrationId}");
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(assertingPartyDetails.getEntityId())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php");
|
||||
assertThat(assertingPartyDetails.getWantAuthnRequestsSigned()).isFalse();
|
||||
assertThat(assertingPartyDetails.getVerificationX509Credentials()).hasSize(1);
|
||||
assertThat(assertingPartyDetails.getEncryptionX509Credentials()).hasSize(1);
|
||||
assertThat(assertingPartyDetails.getSingleSignOnServiceLocation())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php");
|
||||
assertThat(assertingPartyDetails.getSingleSignOnServiceBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
|
||||
assertThat(assertingPartyDetails.getSigningAlgorithms())
|
||||
.containsExactly("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseWhenSingleRelyingPartyRegistrationThenAvailableInRepository() {
|
||||
this.spring.configLocations(xml("SingleRegistration")).autowire();
|
||||
assertThat(this.relyingPartyRegistrationRepository)
|
||||
.isInstanceOf(InMemoryRelyingPartyRegistrationRepository.class);
|
||||
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationRepository
|
||||
.findByRegistrationId("one");
|
||||
RelyingPartyRegistration.AssertingPartyDetails assertingPartyDetails = relyingPartyRegistration
|
||||
.getAssertingPartyDetails();
|
||||
assertThat(relyingPartyRegistration).isNotNull();
|
||||
assertThat(relyingPartyRegistration.getRegistrationId()).isEqualTo("one");
|
||||
assertThat(relyingPartyRegistration.getEntityId())
|
||||
.isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceLocation())
|
||||
.isEqualTo("{baseUrl}/login/saml2/sso/{registrationId}");
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceBinding())
|
||||
.isEqualTo(Saml2MessageBinding.REDIRECT);
|
||||
assertThat(assertingPartyDetails.getEntityId()).isEqualTo("https://accounts.google.com/o/saml2/idp/entity-id");
|
||||
assertThat(assertingPartyDetails.getWantAuthnRequestsSigned()).isTrue();
|
||||
assertThat(assertingPartyDetails.getSingleSignOnServiceLocation())
|
||||
.isEqualTo("https://accounts.google.com/o/saml2/idp/sso-url");
|
||||
assertThat(assertingPartyDetails.getSingleSignOnServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(assertingPartyDetails.getVerificationX509Credentials()).hasSize(1);
|
||||
assertThat(assertingPartyDetails.getEncryptionX509Credentials()).hasSize(1);
|
||||
assertThat(assertingPartyDetails.getSigningAlgorithms())
|
||||
.containsExactly("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseWhenMultiRelyingPartyRegistrationThenAvailableInRepository() {
|
||||
this.spring.configLocations(xml("MultiRegistration")).autowire();
|
||||
assertThat(this.relyingPartyRegistrationRepository)
|
||||
.isInstanceOf(InMemoryRelyingPartyRegistrationRepository.class);
|
||||
RelyingPartyRegistration one = this.relyingPartyRegistrationRepository.findByRegistrationId("one");
|
||||
RelyingPartyRegistration.AssertingPartyDetails google = one.getAssertingPartyDetails();
|
||||
RelyingPartyRegistration two = this.relyingPartyRegistrationRepository.findByRegistrationId("two");
|
||||
RelyingPartyRegistration.AssertingPartyDetails simpleSaml = two.getAssertingPartyDetails();
|
||||
assertThat(one).isNotNull();
|
||||
assertThat(one.getRegistrationId()).isEqualTo("one");
|
||||
assertThat(one.getEntityId()).isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
|
||||
assertThat(one.getAssertionConsumerServiceLocation()).isEqualTo("{baseUrl}/login/saml2/sso/{registrationId}");
|
||||
assertThat(one.getAssertionConsumerServiceBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
|
||||
assertThat(google.getEntityId()).isEqualTo("https://accounts.google.com/o/saml2/idp/entity-id");
|
||||
assertThat(google.getWantAuthnRequestsSigned()).isTrue();
|
||||
assertThat(google.getSingleSignOnServiceLocation())
|
||||
.isEqualTo("https://accounts.google.com/o/saml2/idp/sso-url");
|
||||
assertThat(google.getSingleSignOnServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(google.getVerificationX509Credentials()).hasSize(1);
|
||||
assertThat(google.getEncryptionX509Credentials()).hasSize(1);
|
||||
assertThat(google.getSigningAlgorithms()).containsExactly("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
|
||||
assertThat(two).isNotNull();
|
||||
assertThat(two.getRegistrationId()).isEqualTo("two");
|
||||
assertThat(two.getEntityId()).isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
|
||||
assertThat(two.getAssertionConsumerServiceLocation()).isEqualTo("{baseUrl}/login/saml2/sso/{registrationId}");
|
||||
assertThat(two.getAssertionConsumerServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(simpleSaml.getEntityId())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php");
|
||||
assertThat(simpleSaml.getWantAuthnRequestsSigned()).isFalse();
|
||||
assertThat(simpleSaml.getSingleSignOnServiceLocation())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php");
|
||||
assertThat(simpleSaml.getSingleSignOnServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(simpleSaml.getVerificationX509Credentials()).hasSize(1);
|
||||
assertThat(simpleSaml.getEncryptionX509Credentials()).hasSize(1);
|
||||
assertThat(simpleSaml.getSigningAlgorithms()).containsExactly(
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384");
|
||||
}
|
||||
|
||||
private static MockResponse xmlResponse(String xml) {
|
||||
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).setBody(xml);
|
||||
}
|
||||
|
||||
private static String xml(String configName) {
|
||||
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login/>
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="../saml2/google-custom-registration.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,38 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login authentication-failure-handler-ref="authenticationFailureHandler"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="authenticationFailureHandler" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationFailureHandler"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="../saml2/google-registration.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,58 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login/>
|
||||
<request-cache ref="requestCache" />
|
||||
</http>
|
||||
|
||||
<relying-party-registrations>
|
||||
<relying-party-registration registration-id="one"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="REDIRECT"
|
||||
asserting-party-id="google"/>
|
||||
|
||||
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
|
||||
want-authn-requests-signed="true"
|
||||
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
|
||||
single-sign-on-service-binding="POST">
|
||||
<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:bean id="requestCache" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.web.savedrequest.RequestCache"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,38 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login login-processing-url="/my/custom/url" authentication-converter-ref="authenticationConverter"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="authenticationConverter" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationConverter"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="../saml2/google-registration.xml"/>
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,34 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login login-processing-url="/my/custom/url"/>
|
||||
</http>
|
||||
|
||||
<b:import resource="../saml2/google-registration.xml"/>
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,40 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login relying-party-registration-repository-ref="relyingPartyRegistrationRepository" authentication-converter-ref="authenticationConverter"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="relyingPartyRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository"/>
|
||||
</b:bean>
|
||||
<b:bean id="authenticationConverter" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationConverter"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,40 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login relying-party-registration-repository-ref="relyingPartyRegistrationRepository" authentication-manager-ref="customAuthenticationManager"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="relyingPartyRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository"/>
|
||||
</b:bean>
|
||||
<b:bean id="customAuthenticationManager" name="customAuthenticationManager" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.authentication.AuthenticationManager"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,41 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login relying-party-registration-repository-ref="relyingPartyRegistrationRepository"
|
||||
authentication-request-resolver-ref="authenticationRequestResolver"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="relyingPartyRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository"/>
|
||||
</b:bean>
|
||||
<b:bean id="authenticationRequestResolver" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,40 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login relying-party-registration-repository-ref="relyingPartyRegistrationRepository" authentication-request-repository-ref="authenticationRequestRepository"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="relyingPartyRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository"/>
|
||||
</b:bean>
|
||||
<b:bean id="authenticationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,43 @@
|
|||
<?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">
|
||||
|
||||
<http auto-config="true">
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<saml2-login authentication-success-handler-ref="authenticationSuccessHandler" relying-party-registration-repository-ref="relyingPartyRegistrationRepository"/>
|
||||
</http>
|
||||
|
||||
<b:bean id="authenticationSuccessListener" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.context.ApplicationListener"/>
|
||||
</b:bean>
|
||||
<b:bean id="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationSuccessHandler"/>
|
||||
</b:bean>
|
||||
<b:bean id="relyingPartyRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository"/>
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -0,0 +1,66 @@
|
|||
<?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="one"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="REDIRECT"
|
||||
asserting-party-id="google"/>
|
||||
|
||||
<relying-party-registration registration-id="two"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="POST"
|
||||
asserting-party-id="simple-saml"/>
|
||||
|
||||
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
|
||||
want-authn-requests-signed="true"
|
||||
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
|
||||
single-sign-on-service-binding="POST">
|
||||
<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="simple-saml"
|
||||
entity-id="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php"
|
||||
single-sign-on-service-location="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php"
|
||||
single-sign-on-service-binding="POST"
|
||||
signing-algorithms="http://www.w3.org/2001/04/xmldsig-more#rsa-sha224,http://www.w3.org/2001/04/xmldsig-more#rsa-sha256,http://www.w3.org/2001/04/xmldsig-more#rsa-sha384">
|
||||
<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>
|
|
@ -0,0 +1,47 @@
|
|||
<?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="one"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="REDIRECT"
|
||||
asserting-party-id="google"/>
|
||||
|
||||
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
|
||||
want-authn-requests-signed="true"
|
||||
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
|
||||
single-sign-on-service-binding="POST">
|
||||
<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>
|
|
@ -0,0 +1,64 @@
|
|||
<?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="one"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="REDIRECT"
|
||||
asserting-party-id="google"/>
|
||||
|
||||
<relying-party-registration registration-id="two"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="POST"
|
||||
asserting-party-id="simple-saml"/>
|
||||
|
||||
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
|
||||
want-authn-requests-signed="true"
|
||||
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
|
||||
single-sign-on-service-binding="POST">
|
||||
<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="simple-saml"
|
||||
entity-id="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php"
|
||||
single-sign-on-service-location="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php"
|
||||
single-sign-on-service-binding="POST"
|
||||
signing-algorithms="http://www.w3.org/2001/04/xmldsig-more#rsa-sha224,http://www.w3.org/2001/04/xmldsig-more#rsa-sha256,http://www.w3.org/2001/04/xmldsig-more#rsa-sha384">
|
||||
<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>
|
|
@ -0,0 +1,45 @@
|
|||
<?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="one"
|
||||
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
|
||||
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
|
||||
assertion-consumer-service-binding="REDIRECT"
|
||||
asserting-party-id="google"/>
|
||||
|
||||
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
|
||||
want-authn-requests-signed="true"
|
||||
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
|
||||
single-sign-on-service-binding="POST">
|
||||
<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>
|
|
@ -0,0 +1,24 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD
|
||||
VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX
|
||||
c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw
|
||||
aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ
|
||||
BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa
|
||||
BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD
|
||||
DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr
|
||||
QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62
|
||||
E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz
|
||||
2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW
|
||||
RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ
|
||||
nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5
|
||||
cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph
|
||||
iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5
|
||||
ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD
|
||||
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO
|
||||
nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v
|
||||
ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu
|
||||
xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z
|
||||
V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3
|
||||
lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG
|
||||
A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD
|
||||
DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1
|
||||
MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES
|
||||
MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN
|
||||
TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos
|
||||
vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM
|
||||
+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG
|
||||
y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi
|
||||
XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+
|
||||
qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD
|
||||
RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE
|
||||
VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK
|
||||
cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6
|
||||
Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn
|
||||
x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5
|
||||
wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd
|
||||
vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY
|
||||
8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX
|
||||
oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx
|
||||
EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0
|
||||
KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt
|
||||
YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr
|
||||
9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM
|
||||
INrtuLp4YHbgk1mi
|
||||
-----END PRIVATE KEY-----
|
|
@ -163,6 +163,7 @@ The default value is true.
|
|||
* <<nsa-port-mappings,port-mappings>>
|
||||
* <<nsa-remember-me,remember-me>>
|
||||
* <<nsa-request-cache,request-cache>>
|
||||
* <<nsa-saml2-login,saml2-login>>
|
||||
* <<nsa-session-management,session-management>>
|
||||
* <<nsa-x509,x509>>
|
||||
|
||||
|
@ -1289,6 +1290,221 @@ The Client Id to use for client authentication against the provided `introspecti
|
|||
* **client-secret**
|
||||
The Client Secret to use for client authentication against the provided `introspection-uri`.
|
||||
|
||||
|
||||
[[nsa-relying-party-registrations]]
|
||||
== <relying-party-registrations>
|
||||
The container element for relying party(ies) registered (xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistration[ClientRegistration]) with a SAML 2.0 Identity Provider.
|
||||
|
||||
|
||||
[[nsa-relying-party-registrations-children]]
|
||||
=== Child Elements of <relying-party-registrations>
|
||||
|
||||
* <<nsa-asserting-party,asserting-party>>
|
||||
* <<nsa-relying-party-registration,relying-party-registration>>
|
||||
|
||||
|
||||
[[nsa-relying-party-registration]]
|
||||
== <relying-party-registration>
|
||||
Represents a relying party registered with a SAML 2.0 Identity Provider
|
||||
|
||||
|
||||
[[nsa-relying-party-registration-parents]]
|
||||
=== Parent Elements of <relying-party-registration>
|
||||
|
||||
* <<nsa-relying-party-registrations,relying-party-registrations>>
|
||||
|
||||
|
||||
[[nsa-relying-party-registration-attributes]]
|
||||
=== <relying-party-registration> Attributes
|
||||
|
||||
|
||||
[[nsa-relying-party-registration-registration-id]]
|
||||
* **registration-id**
|
||||
The ID that uniquely identifies the `RelyingPartyRegistration`.
|
||||
|
||||
[[nsa-relying-party-registration-metadata-location]]
|
||||
* **metadata-location**
|
||||
The asserting party metadata location.
|
||||
|
||||
[[nsa-relying-party-registration-entity-id]]
|
||||
* **client-id**
|
||||
The relying party's https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.9%20EntityDescriptor[EntityID].
|
||||
|
||||
|
||||
[[nsa-relying-party-registration-assertion-consumer-service-location]]
|
||||
* **assertion-consumer-service-location**
|
||||
The AssertionConsumerService Location. Equivalent to the value found in `<AssertionConsumerService Location="..."/>` in the relying party's `<SPSSODescriptor>`.
|
||||
|
||||
|
||||
[[nsa-relying-party-registration-assertion-consumer-service-binding]]
|
||||
* **assertion-consumer-service-binding**
|
||||
the AssertionConsumerService Binding. Equivalent to the value found in `<AssertionConsumerService Binding="..."/>` in the relying party's `<SPSSODescriptor>`.
|
||||
The supported values are *POST* and *REDIRECT*.
|
||||
|
||||
|
||||
[[nsa-relying-party-registration-asserting-party-id]]
|
||||
* **asserting-party-id**
|
||||
A reference to the associated asserting party. Must reference an `<asserting-party>` element.
|
||||
|
||||
[[nsa-relying-party-registration-children]]
|
||||
=== Child Elements of <relying-party-registration>
|
||||
|
||||
* <<nsa-decryption-credential,decryption-credential>>
|
||||
* <<nsa-signing-credential,signing-credential>>
|
||||
|
||||
|
||||
[[nsa-decryption-credential]]
|
||||
== <decryption-credential>
|
||||
The decryption credentials associated with the relying party.
|
||||
|
||||
|
||||
[[nsa-decryption-credential-parents]]
|
||||
=== Parent Elements of <decryption-credential>
|
||||
|
||||
* <<nsa-relying-party-registration,relying-party-registration>>
|
||||
|
||||
|
||||
[[nsa-decryption-credential-attributes]]
|
||||
=== <decryption-credential> Attributes
|
||||
|
||||
|
||||
[[nsa-decryption-credential-certificate-location]]
|
||||
* **certificate-location**
|
||||
The location to get the certificate
|
||||
|
||||
[[nsa-decryption-credential-private-key-location]]
|
||||
* **private-key-location**
|
||||
The location to get the Relying Party's private key
|
||||
|
||||
|
||||
[[nsa-signing-credential]]
|
||||
== <signing-credential>
|
||||
The signing credentials associated with the relying party.
|
||||
|
||||
|
||||
[[nsa-signing-credential-parents]]
|
||||
=== Parent Elements of <verification-credential>
|
||||
|
||||
* <<nsa-relying-party-registration,relying-party-registration>>
|
||||
|
||||
|
||||
[[nsa-signing-credential-attributes]]
|
||||
=== <verification-credential> Attributes
|
||||
|
||||
|
||||
[[nsa-signing-credential-certificate-location]]
|
||||
* **certificate-location**
|
||||
The location to get this certificate
|
||||
|
||||
[[nsa-signing-credential-private-key-location]]
|
||||
* **private-key-location**
|
||||
The location to get the Relying Party's private key
|
||||
|
||||
|
||||
|
||||
|
||||
[[nsa-asserting-party]]
|
||||
== <asserting-party>
|
||||
The configuration information for a SAML 2.0 Asserting Party.
|
||||
|
||||
|
||||
[[nsa-asserting-party-parents]]
|
||||
=== Parent Elements of <asserting-party>
|
||||
|
||||
* <<nsa-relying-party-registrations,relying-party-registrations>>
|
||||
|
||||
|
||||
[[nsa-asserting-party-attributes]]
|
||||
=== <asserting-party> Attributes
|
||||
|
||||
|
||||
[[nsa-asserting-party-asserting-party-id]]
|
||||
* **asserting-party-id**
|
||||
The ID that uniquely identifies the asserting party.
|
||||
|
||||
|
||||
[[nsa-asserting-party-entity-id]]
|
||||
* **entity-id**
|
||||
The EntityID of the Asserting Party
|
||||
|
||||
|
||||
[[nsa-asserting-party-want-authn-requests-signed]]
|
||||
* **want-authn-requests-signed**
|
||||
The `WantAuthnRequestsSigned` setting, indicating the asserting party's preference that relying parties should sign the `AuthnRequest` before sending.
|
||||
|
||||
|
||||
[[nsa-asserting-party-single-sign-on-service-location]]
|
||||
* **single-sign-on-service-location**
|
||||
The https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint[SingleSignOnService] Location.
|
||||
|
||||
|
||||
[[nsa-asserting-party-single-sign-on-service-binding]]
|
||||
* **single-sign-on-service-binding**
|
||||
The https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint[SingleSignOnService] Binding.
|
||||
The supported values are *POST* and *REDIRECT*.
|
||||
|
||||
|
||||
[[nsa-asserting-party-signing-algorithms]]
|
||||
* **signing-algorithms**
|
||||
The list of `org.opensaml.saml.ext.saml2alg.SigningMethod` Algorithms for this asserting party, in preference order.
|
||||
|
||||
|
||||
[[nsa-asserting-party-children]]
|
||||
=== Child Elements of <asserting-party>
|
||||
|
||||
* <<nsa-encryption-credential,encryption-credential>>
|
||||
* <<nsa-verification-credential,verification-credential>>
|
||||
|
||||
|
||||
[[nsa-encryption-credential]]
|
||||
== <encryption-credential>
|
||||
The encryption credentials associated with the asserting party.
|
||||
|
||||
|
||||
[[nsa-encryption-credential-parents]]
|
||||
=== Parent Elements of <encryption-credential>
|
||||
|
||||
* <<nsa-asserting-party,asserting-party>>
|
||||
|
||||
|
||||
[[nsa-encryption-credential-attributes]]
|
||||
=== <encryption-credential> Attributes
|
||||
|
||||
|
||||
[[nsa-encryption-credential-certificate-location]]
|
||||
* **certificate-location**
|
||||
The location to get the certificate
|
||||
|
||||
[[nsa-encryption-credential-private-key-location]]
|
||||
* **private-key-location**
|
||||
The location to get the Relying Party's private key
|
||||
|
||||
|
||||
[[nsa-verification-credential]]
|
||||
== <verification-credential>
|
||||
The verification credentials associated with the asserting party.
|
||||
|
||||
|
||||
[[nsa-verification-credential-parents]]
|
||||
=== Parent Elements of <verification-credential>
|
||||
|
||||
* <<nsa-asserting-party,asserting-party>>
|
||||
|
||||
|
||||
[[nsa-verification-credential-attributes]]
|
||||
=== <verification-credential> Attributes
|
||||
|
||||
|
||||
[[nsa-verification-credential-certificate-location]]
|
||||
* **certificate-location**
|
||||
The location to get this certificate
|
||||
|
||||
[[nsa-verification-credential-private-key-location]]
|
||||
* **private-key-location**
|
||||
The location to get the Relying Party's private key
|
||||
|
||||
|
||||
|
||||
[[nsa-http-basic]]
|
||||
== <http-basic>
|
||||
Adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration.
|
||||
|
@ -1475,6 +1691,65 @@ Defaults to "/logout".
|
|||
May be used to supply an instance of `LogoutSuccessHandler` which will be invoked to control the navigation after logging out.
|
||||
|
||||
|
||||
[[nsa-saml2-login]]
|
||||
== <saml2-login>
|
||||
The xref:servlet/saml2/login/index.adoc#servlet-saml2login[SAML 2.0 Login] feature configures authentication support using an SAML 2.0 Service Provider.
|
||||
|
||||
|
||||
[[nsa-saml2-login-parents]]
|
||||
=== Parent Elements of <saml2-login>
|
||||
|
||||
* <<nsa-http,http>>
|
||||
|
||||
[[nsa-saml2-login-attributes]]
|
||||
=== <saml2-login> Attributes
|
||||
|
||||
|
||||
[[nsa-saml2-login-relying-party-registration-repository-ref]]
|
||||
* **relying-party-registration-repository-ref**
|
||||
Reference to the `RelyingPartyRegistrationRepository`.
|
||||
|
||||
|
||||
[[nsa-saml2-login-authentication-request-repository-ref]]
|
||||
* **authentication-request-repository-ref**
|
||||
Reference to the `Saml2AuthenticationRequestRepository`.
|
||||
|
||||
|
||||
[[nsa-saml2-login-authentication-request-resolver-ref]]
|
||||
* **authentication-request-context-resolver-ref**
|
||||
Reference to the `Saml2AuthenticationRequestResolver`.
|
||||
|
||||
|
||||
[[nsa-saml2-login-authentication-converter-ref]]
|
||||
* **authentication-converter-ref**
|
||||
Reference to the `AuthenticationConverter`.
|
||||
|
||||
|
||||
[[nsa-saml2-login-login-processing-url]]
|
||||
* **login-processing-url**
|
||||
The URI where the filter processes authentication requests.
|
||||
|
||||
|
||||
[[nsa-saml2-login-login-page]]
|
||||
* **login-page**
|
||||
The URI to send users to login.
|
||||
|
||||
|
||||
[[nsa-saml2-login-authentication-success-handler-ref]]
|
||||
* **authentication-success-handler-ref**
|
||||
Reference to the `AuthenticationSuccessHandler`.
|
||||
|
||||
|
||||
[[nsa-saml2-login-authentication-failure-handler-ref]]
|
||||
* **authentication-failure-handler-ref**
|
||||
Reference to the `AuthenticationFailureHandler`.
|
||||
|
||||
|
||||
[[nsa-saml2-login-authentication-manager-ref]]
|
||||
* **authentication-manager-ref**
|
||||
Reference to the `AuthenticationManager`.
|
||||
|
||||
|
||||
[[nsa-password-management]]
|
||||
== <password-management>
|
||||
This element configures password management.
|
||||
|
|
|
@ -5,3 +5,6 @@
|
|||
^http://lists.webappsec.org/.*
|
||||
^http://webblaze.cs.berkeley.edu/.*
|
||||
^http://www.w3.org/2000/09/xmldsig.*
|
||||
^http://www.w3.org/2001/10/xml-exc-c14n
|
||||
^http://www.w3.org/2001/04/xmldsig-more
|
||||
^http://www.w3.org/2001/04/xmlenc
|
|
@ -111,7 +111,9 @@ public final class RelyingPartyRegistration {
|
|||
Assert.isTrue(singleLogoutServiceLocation == null || singleLogoutServiceBinding != null,
|
||||
"singleLogoutServiceBinding cannot be null when singleLogoutServiceLocation is set");
|
||||
Assert.notNull(providerDetails, "providerDetails cannot be null");
|
||||
Assert.notEmpty(credentials, "credentials cannot be empty");
|
||||
Assert.isTrue(
|
||||
!credentials.isEmpty() || (decryptionX509Credentials.isEmpty() && signingX509Credentials.isEmpty()),
|
||||
"credentials cannot be empty");
|
||||
for (org.springframework.security.saml2.credentials.Saml2X509Credential c : credentials) {
|
||||
Assert.notNull(c, "credentials cannot contain null elements");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue