SEC-1847: Add authentication-manager-ref attribute to http and global-method-security namespace elements.
This commit is contained in:
parent
bce4d81142
commit
2f67bb3032
|
@ -38,8 +38,13 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
|||
private static final String ATT_ERASE_CREDENTIALS = "erase-credentials";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
||||
"AuthenticationManager has already been registered!");
|
||||
String id = element.getAttribute("id");
|
||||
|
||||
if (!StringUtils.hasText(id)) {
|
||||
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
||||
"Global AuthenticationManager has already been registered!");
|
||||
id = BeanIds.AUTHENTICATION_MANAGER;
|
||||
}
|
||||
pc.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)));
|
||||
|
||||
BeanDefinitionBuilder providerManagerBldr = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
||||
|
@ -72,9 +77,9 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
|||
} else {
|
||||
BeanDefinition provider = resolver.resolve(providerElt.getNamespaceURI()).parse(providerElt, pc);
|
||||
Assert.notNull(provider, "Parser for " + providerElt.getNodeName() + " returned a null bean definition");
|
||||
String id = pc.getReaderContext().generateBeanName(provider);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(provider, id));
|
||||
providers.add(new RuntimeBeanReference(id));
|
||||
String providerId = pc.getReaderContext().generateBeanName(provider);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(provider, providerId));
|
||||
providers.add(new RuntimeBeanReference(providerId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,16 +96,15 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
|||
|
||||
// Add the default event publisher
|
||||
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
|
||||
String id = pc.getReaderContext().generateBeanName(publisher);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(publisher, id));
|
||||
providerManagerBldr.addPropertyReference("authenticationEventPublisher", id);
|
||||
String pubId = pc.getReaderContext().generateBeanName(publisher);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(publisher, pubId));
|
||||
providerManagerBldr.addPropertyReference("authenticationEventPublisher", pubId);
|
||||
|
||||
pc.registerBeanComponent(
|
||||
new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), BeanIds.AUTHENTICATION_MANAGER));
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), id));
|
||||
|
||||
if (StringUtils.hasText(alias)) {
|
||||
pc.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
|
||||
pc.getReaderContext().fireAliasRegistered(BeanIds.AUTHENTICATION_MANAGER, alias, pc.extractSource(element));
|
||||
pc.getRegistry().registerAlias(id, alias);
|
||||
pc.getReaderContext().fireAliasRegistered(id, alias, pc.extractSource(element));
|
||||
}
|
||||
|
||||
pc.popAndRegisterContainingComponent();
|
||||
|
|
|
@ -19,8 +19,9 @@ import org.springframework.security.config.BeanIds;
|
|||
*/
|
||||
public class AuthenticationManagerFactoryBean implements FactoryBean<AuthenticationManager>, BeanFactoryAware {
|
||||
private BeanFactory bf;
|
||||
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add an <authentication-manager> element " +
|
||||
"to your configuration (with child <authentication-provider> elements) ?";
|
||||
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add a gobal <authentication-manager> element " +
|
||||
"to your configuration (with child <authentication-provider> elements)? Alternatively you can use the " +
|
||||
"authentication-manager-ref attribute on your <http> and <global-method-security> elements.";
|
||||
|
||||
public AuthenticationManager getObject() throws Exception {
|
||||
try {
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.springframework.security.config.Elements;
|
|||
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.AnyRequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
@ -41,6 +40,7 @@ import java.util.*;
|
|||
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
|
||||
|
||||
private static final String ATT_AUTHENTICATION_MANAGER_REF = "authentication-manager-ref";
|
||||
private static final String ATT_REQUEST_MATCHER_REF = "request-matcher-ref";
|
||||
static final String ATT_PATH_PATTERN = "pattern";
|
||||
static final String ATT_HTTP_METHOD = "method";
|
||||
|
@ -190,22 +190,32 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates the internal AuthenticationManager bean which uses the externally registered (global) one as
|
||||
* a parent.
|
||||
* Creates the internal AuthenticationManager bean which uses either the externally registered (global) one as
|
||||
* a parent or the bean specified by "authentication-manager-ref".
|
||||
*
|
||||
* All the providers registered by this <http> block will be registered with the internal
|
||||
* authentication manager.
|
||||
* All the providers registered by this <http> block will be registered with the internal authentication
|
||||
* manager.
|
||||
*/
|
||||
private BeanReference createAuthenticationManager(Element element, ParserContext pc,
|
||||
ManagedList<BeanReference> authenticationProviders) {
|
||||
String parentMgrRef = element.getAttribute(ATT_AUTHENTICATION_MANAGER_REF);
|
||||
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
||||
authManager.addConstructorArgValue(authenticationProviders);
|
||||
authManager.addConstructorArgValue(new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||
|
||||
RootBeanDefinition clearCredentials = new RootBeanDefinition(MethodInvokingFactoryBean.class);
|
||||
clearCredentials.getPropertyValues().addPropertyValue("targetObject", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
|
||||
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
|
||||
if (StringUtils.hasText(parentMgrRef)) {
|
||||
authManager.addConstructorArgValue(new RuntimeBeanReference(parentMgrRef));
|
||||
} else {
|
||||
RootBeanDefinition amfb = new RootBeanDefinition(AuthenticationManagerFactoryBean.class);
|
||||
amfb.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
String amfbId = pc.getReaderContext().generateBeanName(amfb);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(amfb, amfbId));
|
||||
RootBeanDefinition clearCredentials = new RootBeanDefinition(MethodInvokingFactoryBean.class);
|
||||
clearCredentials.getPropertyValues().addPropertyValue("targetObject", new RuntimeBeanReference(amfbId));
|
||||
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
|
||||
|
||||
authManager.addConstructorArgValue(new RuntimeBeanReference(amfbId));
|
||||
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
|
||||
}
|
||||
|
||||
authManager.getRawBeanDefinition().setSource(pc.extractSource(element));
|
||||
BeanDefinition authMgrBean = authManager.getBeanDefinition();
|
||||
|
|
|
@ -69,6 +69,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_AUTHENTICATION_MANAGER_REF = "authentication-manager-ref";
|
||||
private static final String ATT_ACCESS = "access";
|
||||
private static final String ATT_EXPRESSION = "expression";
|
||||
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
|
@ -204,8 +205,10 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||
accessManagerId = registerAccessManager(pc, jsr250Enabled, preInvocationVoter);
|
||||
}
|
||||
|
||||
String authMgrRef = element.getAttribute(ATT_AUTHENTICATION_MANAGER_REF);
|
||||
|
||||
String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
|
||||
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
|
||||
BeanReference interceptor = registerMethodSecurityInterceptor(pc, authMgrRef, accessManagerId, runAsManagerId,
|
||||
metadataSource, afterInvocationProviders, source, useAspectJ);
|
||||
|
||||
if (useAspectJ) {
|
||||
|
@ -307,7 +310,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||
return pointcutMap;
|
||||
}
|
||||
|
||||
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
|
||||
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String authMgrRef, String accessManagerId,
|
||||
String runAsManagerId, BeanReference metadataSource,
|
||||
List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) {
|
||||
BeanDefinitionBuilder bldr =
|
||||
|
@ -315,7 +318,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||
AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class);
|
||||
bldr.getRawBeanDefinition().setSource(source);
|
||||
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
|
||||
RootBeanDefinition authMgr = new RootBeanDefinition(AuthenticationManagerDelegator.class);
|
||||
authMgr.getConstructorArgumentValues().addGenericArgumentValue(authMgrRef);
|
||||
bldr.addPropertyValue("authenticationManager", authMgr);
|
||||
bldr.addPropertyValue("securityMetadataSource", metadataSource);
|
||||
|
||||
if (StringUtils.hasText(runAsManagerId)) {
|
||||
|
@ -367,13 +372,18 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||
private AuthenticationManager delegate;
|
||||
private final Object delegateMonitor = new Object();
|
||||
private BeanFactory beanFactory;
|
||||
private final String authMgrBean;
|
||||
|
||||
AuthenticationManagerDelegator(String authMgrBean) {
|
||||
this.authMgrBean = StringUtils.hasText(authMgrBean) ? authMgrBean : BeanIds.AUTHENTICATION_MANAGER;
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
synchronized(delegateMonitor) {
|
||||
if (delegate == null) {
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + BeanIds.AUTHENTICATION_MANAGER);
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + authMgrBean);
|
||||
try {
|
||||
delegate = beanFactory.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
|
||||
delegate = beanFactory.getBean(authMgrBean, ProviderManager.class);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
|
||||
throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER,
|
||||
|
|
|
@ -40,6 +40,10 @@ user-service-ref =
|
|||
## A reference to a user-service (or UserDetailsService bean) Id
|
||||
attribute user-service-ref {xsd:token}
|
||||
|
||||
authentication-manager-ref =
|
||||
## A reference to an AuthenticationManager bean
|
||||
attribute authentication-manager-ref {xsd:token}
|
||||
|
||||
data-source-ref =
|
||||
## A reference to a DataSource bean
|
||||
attribute data-source-ref {xsd:token}
|
||||
|
@ -228,6 +232,9 @@ global-method-security.attlist &=
|
|||
attribute mode {"aspectj"}?
|
||||
global-method-security.attlist &=
|
||||
attribute metadata-source-ref {xsd:token}?
|
||||
global-method-security.attlist &=
|
||||
authentication-manager-ref?
|
||||
|
||||
|
||||
after-invocation-provider =
|
||||
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
||||
|
@ -319,9 +326,10 @@ http.attlist &=
|
|||
## Prevents the jsessionid parameter from being added to rendered URLs.
|
||||
attribute disable-url-rewriting {xsd:boolean}?
|
||||
http.attlist &=
|
||||
## Exposes the list of filters defined by this configuration under this bean name in the application context. May be used by
|
||||
## Exposes the list of filters defined by this configuration under this bean name in the application context.
|
||||
name?
|
||||
|
||||
http.attlist &=
|
||||
authentication-manager-ref?
|
||||
|
||||
access-denied-handler =
|
||||
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
|
||||
|
@ -618,7 +626,9 @@ authentication-manager =
|
|||
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
|
||||
element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*}
|
||||
authman.attlist &=
|
||||
## The alias you wish to use for the AuthenticationManager bean
|
||||
id?
|
||||
authman.attlist &=
|
||||
## An alias you wish to use for the AuthenticationManager bean (not required it you are using a specific id)
|
||||
attribute alias {xsd:token}?
|
||||
authman.attlist &=
|
||||
## If set to true, the AuthenticationManger will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated.
|
||||
|
|
|
@ -98,6 +98,13 @@
|
|||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:attributeGroup name="authentication-manager-ref">
|
||||
<xs:attribute name="authentication-manager-ref" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to an AuthenticationManager bean</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:attributeGroup name="data-source-ref">
|
||||
<xs:attribute name="data-source-ref" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
|
@ -577,6 +584,11 @@
|
|||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="metadata-source-ref" type="xs:token"/>
|
||||
<xs:attribute name="authentication-manager-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to an AuthenticationManager bean</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
|
||||
|
@ -804,6 +816,11 @@
|
|||
<xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-manager-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to an AuthenticationManager bean</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:attributeGroup name="access-denied-handler.attlist">
|
||||
|
@ -1357,9 +1374,14 @@
|
|||
<xs:attributeGroup ref="security:authman.attlist"/>
|
||||
</xs:complexType></xs:element>
|
||||
<xs:attributeGroup name="authman.attlist">
|
||||
<xs:attribute name="id" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="alias" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The alias you wish to use for the AuthenticationManager bean</xs:documentation>
|
||||
<xs:documentation>An alias you wish to use for the AuthenticationManager bean (not required it you are using a specific id)</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="erase-credentials" type="xs:boolean">
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.springframework.security.access.PermissionEvaluator
|
|||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
|
||||
import org.springframework.security.web.util.AntPathRequestMatcher
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
|
||||
class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
||||
def 'Minimal configuration parses'() {
|
||||
|
@ -679,6 +680,20 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
|||
expect:
|
||||
getFilter(FilterSecurityInterceptor.class).accessDecisionManager.decisionVoters[3] instanceof WebExpressionVoter
|
||||
}
|
||||
|
||||
def customAuthenticationManagerIsSupported() {
|
||||
xml.http('auto-config': 'true', 'authentication-manager-ref': 'am')
|
||||
xml.'b:bean'(id: 'am', 'class': MockAuthenticationManager.class.name)
|
||||
createAppContext("")
|
||||
expect:
|
||||
getFilter(UsernamePasswordAuthenticationFilter.class).authenticationManager.parent instanceof MockAuthenticationManager
|
||||
}
|
||||
}
|
||||
|
||||
class MockAuthenticationManager implements AuthenticationManager {
|
||||
Authentication authenticate(Authentication authentication) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class MockPermissionEvaluator implements PermissionEvaluator {
|
||||
|
|
|
@ -69,10 +69,11 @@ class RememberMeConfigTests extends AbstractHttpConfigTests {
|
|||
|
||||
List logoutHandlers = FieldUtils.getFieldValue(getFilter(LogoutFilter.class), "handlers");
|
||||
Map ams = appContext.getBeansOfType(ProviderManager.class);
|
||||
ams.remove(BeanIds.AUTHENTICATION_MANAGER);
|
||||
RememberMeAuthenticationProvider rmp = (ams.values() as List)[0].providers[1];
|
||||
ProviderManager am = (ams.values() as List).find { it instanceof ProviderManager && it.providers.size() == 2}
|
||||
RememberMeAuthenticationProvider rmp = am.providers.find { it instanceof RememberMeAuthenticationProvider}
|
||||
|
||||
expect:
|
||||
rmp != null
|
||||
5000 == FieldUtils.getFieldValue(rememberMeServices(), "tokenValiditySeconds")
|
||||
// SEC-909
|
||||
logoutHandlers.size() == 2
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.springframework.security.util.FieldUtils;
|
|||
*/
|
||||
public class AuthenticationManagerBeanDefinitionParserTests {
|
||||
private static final String CONTEXT =
|
||||
"<authentication-manager>" +
|
||||
"<authentication-manager id='am'>" +
|
||||
" <authentication-provider>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
|
|
Loading…
Reference in New Issue