Announcement Announcement Module
Collapse
No announcement yet.
Multiple authentication-managers Defined But Only the Last One Is Applied Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple authentication-managers Defined But Only the Last One Is Applied

    With the creation of the authentication-manager-ref attribute of the http element, I assumed that we were free to define multiple authentication managers that could be used by different http definitions.

    However, in practice Spring Security only seems to care about the last authentication-manager definition in the XML config file. Is this correct behavior or a bug?

    To illustrate my point, I created two http blocks:

    Code:
        <http pattern="/remoting/**" use-expressions="true" authentication-manager-ref="remotingAuthenticationManager">
            <intercept-url pattern="/**" access="hasAnyRole('ROLE_LIMITED_REMOTE_USER','ROLE_GODMODE_REMOTE_USER')"/>
            <anonymous enabled="false"/>
            <http-basic/>
        </http>
    
        <http pattern="/**" use-expressions="true" disable-url-rewriting="true" authentication-manager-ref="adminAuthenticationManager">
            <form-login login-page="/login" authentication-failure-url="/failure"/>
            <logout logout-url="/logout" logout-success-url="/login"/>
            <access-denied-handler error-page="/denied"/>
    
            <intercept-url pattern="/denied" access="permitAll"/>
            <intercept-url pattern="/failure" access="permitAll"/>
            <intercept-url pattern="/login" access="permitAll"/>
            <intercept-url pattern="/**" access="hasAnyRole('ROLE_SUPER_USER','ROLE_ADMIN')"/>
        </http>
    As you can see, the first block references an authentication manager bean with an id of remotingAuthenticationManager while the second block references an authentication manager bean with an id of adminAuthenticationManager.

    My authentication managers are defined as follows:

    Code:
        <authentication-manager alias="adminAuthenticationManager">
            <authentication-provider>
                <user-service>
                    <user name="stanFox" password="stan-password" authorities="ROLE_SUPER_USER"/>
                    <user name="marie" password="marie-password" authorities="ROLE_ADMIN"/>
                    <user name="navin" password="navin-password" authorities="ROLE_LOSER_USER"/>
                </user-service>
            </authentication-provider>
        </authentication-manager>
    
        <authentication-manager alias="remotingAuthenticationManager">
            <authentication-provider>
                <user-service>
                    <user name="blair" password="blair-password" authorities="ROLE_LIMITED_REMOTE_USER"/>
                    <user name="clay" password="clay-password" authorities="ROLE_GODMODE_REMOTE_USER"/>
                    <user name="julian" password="julian-password" authorities="ROLE_LOSER_USER"/>
                </user-service>
            </authentication-provider>
        </authentication-manager>
    When I deploy my application with the above configuration, I can authenticate with my services at /remoting/** just fine because the remotingAuthenticationManager is working. However, I cannot log into my admin interface at /** using the credentials defined by the adminAuthenticationManager.

    If I flip the two authentication manager definitions so that the adminAuthenticationManager bean is the last one in the XML config file, then I can log in fine with those credentials into my admin interface at /** but then the credentials defined in the remotingAuthenticationManager bean do not work when I try to authenticate with my services at /remoting/**.

    To prove this further, I have created a simple proof of concept and checked it into Github here: https://github.com/monger/Spring-Sec...h-Manager-Test

    I have created some instructions and some integration tests so you can simply run the following maven goal to see the results:

    mvn integration-test

    If I am misunderstanding the purpose of the authentication-manager-ref attribute, I would love to know. However, if this is a bug I would really love to see a fix because I have an actual use case that requires multiple authentication managers -- a requirement that cannot be satisfied by stacking authentication providers in a single authentication manager.

    Again -- to be clear I just want to know whether I am misunderstanding the purpose of the authentication-manager-ref attribute or whether the behavior I noted above is a bug.

    Thanks!

  • #2
    I think it is more of a misunderstanding with creating two <authentication-manager> elements. If you create two authentication-manager elements the second one overrides the other. You will notice something like the following in your logs when you startup.

    Code:
    WARN  org.springframework.beans.factory.parsing.FailFastProblemReporter - Configuration problem: Overriding globally registered AuthenticationManager
    This is clearly not ideal, so I logged SEC-1937. In the meantime, you can create the second AuthenticationManager using standard spring beans. Something like this should work:

    Code:
    <authentication-manager alias="adminAuthenticationManager">
        <authentication-provider>
            <user-service>
                <user name="stanFox" password="stan-password" authorities="ROLE_SUPER_USER"/>
            </user-service>
        </authentication-provider>
    </authentication-manager>
    
    <user-service id="remotingUds">
        <user name="blair" password="blair-password" authorities="ROLE_LIMITED_REMOTE_USER"/>
    </user-service>
    <beans:bean id="remotingAuthenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <beans:constructor-arg>
            <beans:list>
                <beans:bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"
                    p:userDetailsService-ref="remotingUds"/>
            </beans:list>
        </beans:constructor-arg>
    </beans:bean>
    PS: Thanks for the very thorough write up.

    Cheers,

    Comment


    • #3
      Rob, you made my day! I sincerely appreciate your quick response.

      Your work-around works perfectly in my real-world web app. I thank you and my team thanks you.

      I will be watching SEC-1937.

      Comment


      • #4
        Luke points out on the JIRA that you should be using the id rather than the alias attribute. Can you try that and see if it fixes your problem w/ using multiple AuthenticaitonManager instances.

        Comment


        • #5
          Yeah I just switched the "alias" attributes out for "id" attributes and then ran the integration tests and they all passed.

          Luke was right.

          Thanks to both of you!

          Comment


          • #6
            Originally posted by Monger View Post
            Yeah I just switched the "alias" attributes out for "id" attributes and then ran the integration tests and they all passed.

            Luke was right.

            Thanks to both of you!
            Hi,

            I am new to this forum, please bear with me. In my project i have a requirement to have two authentication mechanisms, one LDAP for internal users and a database authentication for external users, i tried both the solutions that were discussed in this post, but none worked, i am always getting the last authentication manager applied. any help will be greatly appreciated.


            Code:
            <bean name="userService" class="com.samples.spring.struts.service.UserServiceImpl">
            		<property name="systemUsersDao" ref="systemUsersDao"></property>
            	</bean>
            	
            	<security:http pattern="/user/*" auto-config="true" authentication-manager-ref="authenticationManager">
            		<security:intercept-url pattern="/loginAction" access="ROLE_ANONYMOUS"></security:intercept-url>
            		<security:intercept-url pattern="/user/logout" access="ROLE_ANONYMOUS"></security:intercept-url>
            		<security:intercept-url pattern="/user/**" access="ROLE_USER"></security:intercept-url>
            		<security:form-login login-page="/loginAction" default-target-url="/user/userSpringAction" authentication-failure-url="/user/loginFailed"></security:form-login>
            		<security:logout logout-success-url="/user/logout"></security:logout>
            	</security:http>
            	
            	<security:authentication-manager id="authenticationManager">
            	   <security:authentication-provider user-service-ref="userService"></security:authentication-provider>
            	</security:authentication-manager>
            	
            	<!-- Ldap Authenticator -->
            	<security:http auto-config="true" authentication-manager-ref="ldapAuthenticationManager">
            		<security:intercept-url pattern="/adminLoginAction" access="ROLE_ANONYMOUS"></security:intercept-url>
            		<security:intercept-url pattern="/user/logout" access="ROLE_ANONYMOUS"></security:intercept-url>
            		<security:intercept-url pattern="/admin/**" access="ROLE_USER"></security:intercept-url>
            		<security:form-login login-page="/adminLoginAction" default-target-url="/admin/adminSpringAction" authentication-failure-url="/user/loginFailed"></security:form-login>
            		<security:logout logout-success-url="/user/logout"></security:logout>
            	</security:http>
            
            	
            	<security:authentication-manager id="ldapAuthenticationManager">
            	   <security:ldap-authentication-provider>
            	   </security:ldap-authentication-provider>
            	</security:authentication-manager>

            Comment


            • #7
              Hi,

              I am new to this forum, please bear with me. In my project i have a requirement to have two authentication mechanisms, one LDAP for internal users and a database authentication for external users, i tried both the solutions that were discussed in this post, but none worked, i am always getting the last authentication manager applied. any help will be greatly appreciated.

              Version I am using.

              Spring-Security 3.1.4
              Spring-core 3.2.3
              Tomcat 6

              Code:
              <bean name="userService" class="com.samples.spring.struts.service.UserServiceImpl">
              		<property name="systemUsersDao" ref="systemUsersDao"></property>
              	</bean>
              	
              	<security:http pattern="/user/*" auto-config="true" authentication-manager-ref="authenticationManager">
              		<security:intercept-url pattern="/loginAction" access="ROLE_ANONYMOUS"></security:intercept-url>
              		<security:intercept-url pattern="/user/logout" access="ROLE_ANONYMOUS"></security:intercept-url>
              		<security:intercept-url pattern="/user/**" access="ROLE_USER"></security:intercept-url>
              		<security:form-login login-page="/loginAction" default-target-url="/user/userSpringAction" authentication-failure-url="/user/loginFailed"></security:form-login>
              		<security:logout logout-success-url="/user/logout"></security:logout>
              	</security:http>
              	
              	<security:authentication-manager id="authenticationManager">
              	   <security:authentication-provider user-service-ref="userService"></security:authentication-provider>
              	</security:authentication-manager>
              	
              	<!-- Ldap Authenticator -->
              	<security:http auto-config="true" authentication-manager-ref="ldapAuthenticationManager">
              		<security:intercept-url pattern="/adminLoginAction" access="ROLE_ANONYMOUS"></security:intercept-url>
              		<security:intercept-url pattern="/user/logout" access="ROLE_ANONYMOUS"></security:intercept-url>
              		<security:intercept-url pattern="/admin/**" access="ROLE_USER"></security:intercept-url>
              		<security:form-login login-page="/adminLoginAction" default-target-url="/admin/adminSpringAction" authentication-failure-url="/user/loginFailed"></security:form-login>
              		<security:logout logout-success-url="/user/logout"></security:logout>
              	</security:http>
              
              	
              	<security:authentication-manager id="ldapAuthenticationManager">
              	   <security:ldap-authentication-provider>
              	   </security:ldap-authentication-provider>
              	</security:authentication-manager>

              Comment

              Working...
              X