mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-24 04:52:16 +00:00
SEC-2020: Set eraseCredentialsAfterAuthentication when using http@authentication-manager-ref
Previously the namespace configuration did not properly set the eraseCredentialsAfterAuthentication property on the parent AuthenticationProvider when using http@authentication-manager-ref. Now the ProviderManager that is created by the namespace consults the original AuthenticationManager to determine if eraseCredentialsAfterAuthentication should be set on the wrapped instance. If the original is not a ProviderManager the eraseCredentialsAfterAuthentication is set to false since we should not "magically" add behavior to the custom AuthenticationManager without knowing the desired behavior.
This commit is contained in:
parent
d2a5ad6fd1
commit
a19cc8f1c7
@ -32,6 +32,7 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.core.OrderComparator;
|
import org.springframework.core.OrderComparator;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.ProviderManager;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.security.config.Elements;
|
import org.springframework.security.config.Elements;
|
||||||
@ -231,7 +232,13 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
authManager.addConstructorArgValue(authenticationProviders);
|
authManager.addConstructorArgValue(authenticationProviders);
|
||||||
|
|
||||||
if (StringUtils.hasText(parentMgrRef)) {
|
if (StringUtils.hasText(parentMgrRef)) {
|
||||||
authManager.addConstructorArgValue(new RuntimeBeanReference(parentMgrRef));
|
RuntimeBeanReference parentAuthManager = new RuntimeBeanReference(parentMgrRef);
|
||||||
|
authManager.addConstructorArgValue(parentAuthManager);
|
||||||
|
RootBeanDefinition clearCredentials = new RootBeanDefinition(ClearCredentialsMethodInvokingFactoryBean.class);
|
||||||
|
clearCredentials.getPropertyValues().addPropertyValue("targetObject", parentAuthManager);
|
||||||
|
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
|
||||||
|
|
||||||
|
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
|
||||||
} else {
|
} else {
|
||||||
RootBeanDefinition amfb = new RootBeanDefinition(AuthenticationManagerFactoryBean.class);
|
RootBeanDefinition amfb = new RootBeanDefinition(AuthenticationManagerFactoryBean.class);
|
||||||
amfb.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
amfb.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
@ -363,3 +370,33 @@ class OrderDecorator implements Ordered {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom {@link MethodInvokingFactoryBean} that is specifically used for looking up the child {@link ProviderManager}
|
||||||
|
* value for {@link ProviderManager#setEraseCredentialsAfterAuthentication(boolean)} given the parent
|
||||||
|
* {@link AuthenticationManager}. This is necessary because the parent {@link AuthenticationManager} might not be a
|
||||||
|
* {@link ProviderManager}.
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
*/
|
||||||
|
final class ClearCredentialsMethodInvokingFactoryBean extends MethodInvokingFactoryBean {
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
boolean isTargetProviderManager = getTargetObject() instanceof ProviderManager;
|
||||||
|
if(!isTargetProviderManager) {
|
||||||
|
setTargetObject(this);
|
||||||
|
}
|
||||||
|
super.afterPropertiesSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default value if the target object is not a ProviderManager is false. We use false because this feature is
|
||||||
|
* associated with {@link ProviderManager} not {@link AuthenticationManager}. If the user wants to leverage
|
||||||
|
* {@link ProviderManager#setEraseCredentialsAfterAuthentication(boolean)} their original
|
||||||
|
* {@link AuthenticationManager} must be a {@link ProviderManager} (we should not magically add this functionality
|
||||||
|
* to their implementation since we cannot determine if it should be on or off).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isEraseCredentialsAfterAuthentication() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -624,6 +624,29 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
|||||||
!getFilter(UsernamePasswordAuthenticationFilter).authenticationManager.eraseCredentialsAfterAuthentication
|
!getFilter(UsernamePasswordAuthenticationFilter).authenticationManager.eraseCredentialsAfterAuthentication
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def 'SEC-2020 authentication-manager@erase-credentials with http@authentication-manager-ref'() {
|
||||||
|
xml.http('authentication-manager-ref':'authMgr') {
|
||||||
|
'form-login'()
|
||||||
|
}
|
||||||
|
createAppContext("<authentication-manager id='authMgr' erase-credentials='false' />");
|
||||||
|
expect:
|
||||||
|
def authManager = getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||||
|
!authManager.eraseCredentialsAfterAuthentication
|
||||||
|
!authManager.parent.eraseCredentialsAfterAuthentication
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'authentication-manager@erase-credentials with http@authentication-manager-ref not ProviderManager'() {
|
||||||
|
xml.http('authentication-manager-ref':'authMgr') {
|
||||||
|
'form-login'()
|
||||||
|
}
|
||||||
|
xml.'b:bean'(id: 'authMgr', 'class': MockAuthenticationManager.class.name)
|
||||||
|
createAppContext()
|
||||||
|
expect:
|
||||||
|
def authManager = getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||||
|
!authManager.eraseCredentialsAfterAuthentication
|
||||||
|
authManager.parent instanceof MockAuthenticationManager
|
||||||
|
}
|
||||||
|
|
||||||
def jeeFilterExtractsExpectedRoles() {
|
def jeeFilterExtractsExpectedRoles() {
|
||||||
xml.http() {
|
xml.http() {
|
||||||
jee('mappable-roles': 'admin,user,a,b,c')
|
jee('mappable-roles': 'admin,user,a,b,c')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user