SEC-1133: Support for setting of authenticationDetailsSource property for form-login, openid-login, http-basic and x509 namespace elements. These elements now support an additional 'authentication-details-source-ref' attribute.
This commit is contained in:
parent
992566b6cb
commit
4bd41cbf72
|
@ -16,7 +16,7 @@ dependencies {
|
|||
|
||||
provided "javax.servlet:servlet-api:2.5"
|
||||
|
||||
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.3'
|
||||
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.4'
|
||||
|
||||
testCompile project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
|
|
|
@ -64,6 +64,8 @@ final class AuthenticationConfigBuilder {
|
|||
private static final String OPEN_ID_ATTRIBUTE_FACTORY_CLASS = "org.springframework.security.openid.RegexBasedAxFetchListFactory";
|
||||
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";
|
||||
|
||||
static final String ATT_AUTH_DETAILS_SOURCE_REF = "authentication-details-source-ref";
|
||||
|
||||
private static final String ATT_AUTO_CONFIG = "auto-config";
|
||||
|
||||
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
|
@ -72,6 +74,7 @@ final class AuthenticationConfigBuilder {
|
|||
|
||||
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
|
||||
private final Element httpElt;
|
||||
private final ParserContext pc;
|
||||
|
||||
|
@ -148,7 +151,7 @@ final class AuthenticationConfigBuilder {
|
|||
key = DEF_KEY;
|
||||
}
|
||||
|
||||
rememberMeFilter = (RootBeanDefinition) new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
|
||||
rememberMeFilter = new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
|
||||
rememberMeFilter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
|
||||
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
|
||||
createRememberMeProvider(key);
|
||||
|
@ -291,35 +294,41 @@ final class AuthenticationConfigBuilder {
|
|||
void createBasicFilter(BeanReference authManager) {
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt, Elements.BASIC_AUTH);
|
||||
|
||||
if (basicAuthElt == null && !autoConfig) {
|
||||
// No basic auth, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
String realm = httpElt.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
|
||||
RootBeanDefinition filter = null;
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||
String entryPointId;
|
||||
|
||||
String entryPointId;
|
||||
|
||||
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||
if (basicAuthElt != null) {
|
||||
if (StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
|
||||
} else {
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(httpElt));
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
injectAuthenticationDetailsSource(basicAuthElt, filterBuilder);
|
||||
|
||||
}
|
||||
|
||||
basicFilter = filter;
|
||||
if (basicEntryPoint == null) {
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(httpElt));
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||
basicFilter = filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
void createX509Filter(BeanReference authManager) {
|
||||
|
@ -339,6 +348,9 @@ final class AuthenticationConfigBuilder {
|
|||
|
||||
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
|
||||
}
|
||||
|
||||
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
|
||||
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
createPrauthEntryPoint(x509Elt);
|
||||
|
||||
|
@ -348,6 +360,14 @@ final class AuthenticationConfigBuilder {
|
|||
x509Filter = filter;
|
||||
}
|
||||
|
||||
private void injectAuthenticationDetailsSource(Element elt, BeanDefinitionBuilder filterBuilder) {
|
||||
String authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
|
||||
|
||||
if (StringUtils.hasText(authDetailsSourceRef)) {
|
||||
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
|
||||
}
|
||||
}
|
||||
|
||||
private void createX509Provider() {
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
|
|
|
@ -68,6 +68,7 @@ public class FormLoginBeanDefinitionParser {
|
|||
// Only available with form-login
|
||||
String usernameParameter = null;
|
||||
String passwordParameter = null;
|
||||
String authDetailsSourceRef = null;
|
||||
|
||||
Object source = null;
|
||||
|
||||
|
@ -83,6 +84,8 @@ public class FormLoginBeanDefinitionParser {
|
|||
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
|
||||
successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
|
||||
failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF);
|
||||
authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
|
||||
|
||||
|
||||
if (!StringUtils.hasText(loginPage)) {
|
||||
loginPage = null;
|
||||
|
@ -93,7 +96,7 @@ public class FormLoginBeanDefinitionParser {
|
|||
}
|
||||
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl,
|
||||
successHandlerRef, failureHandlerRef);
|
||||
successHandlerRef, failureHandlerRef, authDetailsSourceRef);
|
||||
|
||||
if (StringUtils.hasText(usernameParameter)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("usernameParameter", usernameParameter);
|
||||
|
@ -114,7 +117,8 @@ public class FormLoginBeanDefinitionParser {
|
|||
}
|
||||
|
||||
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault,
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef) {
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef,
|
||||
String authDetailsSourceRef) {
|
||||
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
|
||||
|
||||
|
@ -136,6 +140,10 @@ public class FormLoginBeanDefinitionParser {
|
|||
filterBuilder.addPropertyValue("authenticationSuccessHandler", successHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(authDetailsSourceRef)) {
|
||||
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
|
||||
}
|
||||
|
||||
if (sessionStrategy != null) {
|
||||
filterBuilder.addPropertyValue("sessionAuthenticationStrategy", sessionStrategy);
|
||||
}
|
||||
|
|
|
@ -187,10 +187,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
logger.info("Checking sorted filter chain: " + filters);
|
||||
|
||||
for(int i=0; i < filters.size(); i++) {
|
||||
OrderDecorator filter = (OrderDecorator)filters.get(i);
|
||||
OrderDecorator filter = filters.get(i);
|
||||
|
||||
if (i > 0) {
|
||||
OrderDecorator previous = (OrderDecorator)filters.get(i-1);
|
||||
OrderDecorator previous = filters.get(i-1);
|
||||
if (filter.getOrder() == previous.getOrder()) {
|
||||
pc.getReaderContext().error("Filter beans '" + filter.bean + "' and '" +
|
||||
previous.bean + "' have the same 'order' value. When using custom filters, " +
|
||||
|
|
|
@ -381,6 +381,10 @@ form-login.attlist &=
|
|||
form-login.attlist &=
|
||||
## Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination
|
||||
attribute authentication-failure-handler-ref {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## Reference to an AuthenticationDetailsSource which will be used by the authentication filter
|
||||
attribute authentication-details-source-ref {xsd:token}?
|
||||
|
||||
|
||||
openid-login =
|
||||
## Sets up form login for authentication with an Open ID identity
|
||||
|
@ -451,6 +455,9 @@ http-basic =
|
|||
http-basic.attlist &=
|
||||
## Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter.
|
||||
attribute entry-point-ref {xsd:token}?
|
||||
http-basic.attlist &=
|
||||
## Reference to an AuthenticationDetailsSource which will be used by the authentication filter
|
||||
attribute authentication-details-source-ref {xsd:token}?
|
||||
|
||||
session-management =
|
||||
element session-management {session-management.attlist, concurrency-control?}
|
||||
|
@ -565,6 +572,8 @@ x509.attlist &=
|
|||
x509.attlist &=
|
||||
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
|
||||
user-service-ref?
|
||||
x509.attlist &=
|
||||
attribute authentication-details-source-ref {xsd:token}?
|
||||
|
||||
jee =
|
||||
## Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication.
|
||||
|
|
|
@ -926,6 +926,11 @@
|
|||
<xs:documentation>Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-details-source-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to an AuthenticationDetailsSource which will be used by the authentication filter</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:element name="attribute-exchange"><xs:annotation>
|
||||
|
@ -1059,6 +1064,11 @@
|
|||
<xs:documentation>Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-details-source-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to an AuthenticationDetailsSource which will be used by the authentication filter</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:attributeGroup name="session-management.attlist">
|
||||
|
@ -1167,7 +1177,7 @@
|
|||
<xs:attributeGroup name="remember-me-services-ref">
|
||||
<xs:attribute name="services-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.</xs:documentation>
|
||||
<xs:documentation>Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider. It should also implement the LogoutHandler interface, which will be invoked when a user logs out. Typically the remember-me cookie would be removed on logout.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
@ -1217,6 +1227,7 @@
|
|||
<xs:documentation>A reference to a user-service (or UserDetailsService bean) Id</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-details-source-ref" type="xs:token"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="jee"><xs:annotation>
|
||||
<xs:documentation>Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication.</xs:documentation>
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
package org.springframework.security.config.http
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.xml.MarkupBuilder
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import javax.servlet.Filter
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.config.AbstractXmlConfigTests
|
||||
import org.springframework.security.config.BeanIds
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.FilterInvocation
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
|||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.Closure
|
||||
import org.springframework.security.openid.OpenIDAuthenticationFilter;
|
||||
|
||||
class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
||||
def 'Minimal configuration parses'() {
|
||||
|
@ -502,6 +503,23 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
|||
roles.contains 'ROLE_user'
|
||||
roles.contains 'ROLE_c'
|
||||
}
|
||||
|
||||
def authenticationDetailsSourceInjectionSucceeds() {
|
||||
xml.http() {
|
||||
'form-login'('authentication-details-source-ref' : 'adsr')
|
||||
'openid-login' ('authentication-details-source-ref' : 'adsr')
|
||||
'http-basic' ('authentication-details-source-ref' : 'adsr')
|
||||
'x509' ('authentication-details-source-ref' : 'adsr')
|
||||
}
|
||||
bean('adsr', 'org.springframework.security.web.authentication.WebAuthenticationDetailsSource')
|
||||
createAppContext()
|
||||
def adsr = appContext.getBean('adsr')
|
||||
expect:
|
||||
getFilter(UsernamePasswordAuthenticationFilter).authenticationDetailsSource == adsr
|
||||
getFilter(OpenIDAuthenticationFilter).authenticationDetailsSource == adsr
|
||||
getFilter(BasicAuthenticationFilter).authenticationDetailsSource == adsr
|
||||
getFilter(X509AuthenticationFilter).authenticationDetailsSource == adsr
|
||||
}
|
||||
}
|
||||
|
||||
class MockEntryPoint extends LoginUrlAuthenticationEntryPoint {
|
||||
|
|
|
@ -196,6 +196,10 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
|||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
|
||||
protected AuthenticationDetailsSource<HttpServletRequest, ?> getAuthenticationDetailsSource() {
|
||||
return authenticationDetailsSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authenticationManager
|
||||
* The AuthenticationManager to use
|
||||
|
|
Loading…
Reference in New Issue