Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Every XML sec:authentication-manager creates a new global instance of AuthenticationEventPublisher #7282

Closed
djechelon opened this issue Aug 20, 2019 · 4 comments
Assignees
Labels
in: config An issue in spring-security-config status: backported An issue that has been backported to maintenance branches status: ideal-for-contribution An issue that we actively are looking for someone to help us with type: bug A general bug
Milestone

Comments

@djechelon
Copy link
Contributor

djechelon commented Aug 20, 2019

Summary

When you use multiple sec:authentication-managers, 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 for AuthenticationProviders that support UsernamePasswordToken
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

Reference

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

Related

#4400
#4269

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 20, 2019
@djechelon
Copy link
Contributor Author

Anyway, I implemented a workaround by replacing Autowired with XML property injection of a customized event publisher defined as protected bean

    <bean id="usernamePasswordAuthenticationManager" class="it.phoenix.web.security.spring.ExtensibleAuthenticationManager" lazy-init="true">
        <property name="limitToClass" value="org.springframework.security.authentication.UsernamePasswordAuthenticationToken"/>
        <property name="authenticationEventPublisher">
            <bean id="defaultAuthenticationEventPublisher" class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher"/>
        </property>
    </bean>

@rwinch
Copy link
Member

rwinch commented Aug 20, 2019

Thanks for the report @djechelon! Would you be willing to submit a PR to fix this?

@rwinch rwinch added in: config An issue in spring-security-config status: ideal-for-contribution An issue that we actively are looking for someone to help us with type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Aug 20, 2019
@djechelon
Copy link
Contributor Author

djechelon commented Aug 21, 2019

@djechelon created a pull request right now. It is an early proposal, without tests (yet)

@jzheaux
Copy link
Contributor

jzheaux commented Jun 8, 2021

Note that this is the related PR.

@eleftherias eleftherias self-assigned this Jun 28, 2021
@eleftherias eleftherias added this to the 5.6.0-M1 milestone Jun 28, 2021
@eleftherias eleftherias changed the title Every XML sec:authentication-manager creates a new global instance of AuthenticationEventPublisher, cannot autowire Every XML sec:authentication-manager creates a new global instance of AuthenticationEventPublisher Jun 28, 2021
@spring-projects-issues spring-projects-issues added the status: backported An issue that has been backported to maintenance branches label Jun 28, 2021
akohli96 pushed a commit to akohli96/spring-security that referenced this issue Aug 25, 2021
…ge-after-login-based-on-user-role-with-spring-security/67531436#67531436

Closes spring-projectsgh-7282
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: config An issue in spring-security-config status: backported An issue that has been backported to maintenance branches status: ideal-for-contribution An issue that we actively are looking for someone to help us with type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants