Description
Summary
When you use multiple sec:authentication-manager
s, you can't @Autowire
the AuthenticationEventPublisher
because every sec:authentication-manager
will instantiate its own public bean
Detailed explanation
I work on a plugin-based authentication architecture. All plugins must be switched by Spring profiles and should coexist if possible (all active have no effect).
Currently I have two kinds of plugins:
- SSO plugins have their own filter and a dedicated authentication manager, e.g.
- For username-password-based plugins (e.g. Active Directory, database, custom lookup) I had to invent an ExtensibleAuthenticationManager that basically wraps a
ProviderManager
and scans forAuthenticationProvider
s that supportUsernamePasswordToken
public class ExtensibleAuthenticationManager implements AuthenticationManager, InitializingBean
{
private final static Logger log = LogManager.getLogger();
private AuthenticationManager parentAuthenticationManager;
private ProviderManager providerManager;
private Class<? extends Authentication> limitToClass;
@Autowired
private ListableBeanFactory beanFactory;
@Autowired
private MessageSource messageSource;
@Autowired(required = false)
private AuthenticationEventPublisher authenticationEventPublisher;
Actual Behavior
Since Spring Security creates a globally-visible bean of type DefaultAuthenticationEventPublisher
every time it creates an authentication manager, you can autowire it
Expected Behavior
There should be either one globally-visible bean of type AuthenticationEventPublisher
that can be autowired in other beans if required, or the definition of a new AuthenticationManager
should inject an instance of DefaultAuthenticationEventPublisher
that is private to the authentication manager.
I would prefer the latter, because if one writes their own security plugin there will be actually no public AuthenticationEventPublisher to Autowire, and developer is forced to find their own way (i.e. declare explicitly) to autowire into their authenticatio components
Configuration
<beans profile="CEDACRISEC" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd"
>
<sec:authentication-manager id="cedacriAuthenticationManager">
<sec:authentication-provider ref="cedacriAuthenticationProvider"/>
</sec:authentication-manager>
<bean id="formLoginFilter_cedacri" class="it.phoenix.web.security.cedacri.CedacriAuthenticationFilter">
---------------------------
<beans profile="ICCREASEC"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd">
<bean id="preAuthFilter_iccrea" class="it.phoenix.web.security.spring.PreAuthenticatedIccreaProcessingFilter">
<property name="sessionAuthenticationStrategy"
ref="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy#0"/>
<property name="authenticationManager" ref="iccreaAuthenticationManager"/>
<property name="authenticationSuccessHandler" ref="authenticationHandler"/>
<property name="authenticationFailureHandler" ref="authenticationHandler"/>
</bean>
<sec:authentication-manager id="iccreaAuthenticationManager">
<sec:authentication-provider ref="iccreaPreAuthProvider"/>
</sec:authentication-manager>
---------------------------
<beans profile="PREAUTHSEC" xmlns:sec="http://www.springframework.org/schema/security" xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd"
>
<bean id="preAuthFilter_preauthsec" class="it.phoenix.web.security.spring.PreAuthenticatedProcessingFilter">
<property name="sessionAuthenticationStrategy"
ref="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy#0"/>
<property name="authenticationFailureHandler" ref="authenticationHandler" />
<property name="authenticationSuccessHandler" ref="authenticationHandler" />
<property name="authenticationManager" ref="preauthAuthenticationManager"/>
<property name="principalRequestHeader" value="${httpheader.preauth.user:SM_USER}"/>
<property name="rolesRequestHeader" value="${httpheader.preauth.role:SM_ROLES}"/>
<property name="rolesDelimiter" value="${httpheader.preauth.rolesDelimiter:,}"/>
</bean>
<sec:authentication-manager id="preauthAuthenticationManager">
<sec:authentication-provider ref="profilesAuthenticationProvider"/>
</sec:authentication-manager>
</beans>
---------------------------
<sec:http name="httpSecurityContext" auto-config="false" use-expressions="true" access-decision-manager-ref="accessDecisionManager"
authentication-manager-ref="usernamePasswordAuthenticationManager"
entry-point-ref="authenticationEntryPoint"
>
.............
<bean id="usernamePasswordAuthenticationManager" class="it.phoenix.web.security.spring.ExtensibleAuthenticationManager" lazy-init="true">
<property name="limitToClass" value="org.springframework.security.authentication.UsernamePasswordAuthenticationToken" />
</bean>
</sec:http>
Version
Using version 4.2.11 but should affect all 4.2.x