0
votes

We have been working with a single Authentication Manager (LDAP) in spring security for some time, now we require two Authentication Managers one for Login- LDAP and other for IP based security. As IP based security is used as a global filter and LDAP only for login. Hence the two Authentication Managers. We tried the solution in similar questions, however still facing the same problem.

The error code is :

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChainProxy': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: A universal match pattern ('/**') **is defined before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your namespace or FilterChainProxy bean configuration

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- needed for ContextLoaderListener -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring/application-context.xml
        /WEB-INF/spring/security-context.xml
    </param-value>
</context-param>

<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
    <servlet-name>dispatcher-servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>  
        <param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher-servlet</servlet-name> 
    <url-pattern>/</url-pattern>
</servlet-mapping>

Application Context.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

        <tx:annotation-driven/>

    <jdbc:embedded-database id="datasource" type="H2">
        <jdbc:script location="classpath:init.sql"/>    
    </jdbc:embedded-database>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="datasource"/>  
        <property name="persistenceUnitName" value="autoservice"/>
    </bean> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <jpa:repositories base-package="com.oreilly.security.domain.repositories"/> 

Security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <context:component-scan base-package="com.oreilly.security"/>
    <bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />

        <security:http use-expressions="false" authentication-manager-ref="LDAPAuth">
        <security:form-login login-page="/login"
            login-processing-url="/login" username-parameter="custom_username"
            password-parameter="custom_password" default-target-url="/appointments/"
            always-use-default-target="true" authentication-failure-url="/login?error=true" />

        <security:logout logout-url="/logout"
            logout-success-url="/login?logout=true" />

        <security:intercept-url pattern="/appointments/*"
            access="ROLE_USER,ROLE_ADMIN" />
        <security:intercept-url pattern="/schedule/*"
            access="ROLE_ADMIN" />

    </security:http>

    <security:http use-expressions="false" authentication-manager-ref="IpAuth">
        <security:form-login login-page="/login"
            login-processing-url="/login" username-parameter="custom_username"
            password-parameter="custom_password" default-target-url="/appointments/"
            always-use-default-target="true" authentication-failure-url="/login?error=true" />

        <security:logout logout-url="/logout"
            logout-success-url="/login?logout=true" />

        <security:intercept-url pattern="/**"
            access="ROLE_USER,ROLE_ADMIN" />    
    </security:http>



    <security:authentication-manager id ="IpAuth"> 
        <security:authentication-provider ref="customAuthenticationProvider"/>  
    </security:authentication-manager>

    <security:authentication-manager id = "LDAPAuth"> 
        <security:ldap-authentication-provider user-search-filter="(uid={0})" 
            group-search-base="ou=groups" group-search-filter="(uniqueMember={0})" 
            server-ref="ldapServer" user-context-mapper-ref="contextMapper" role-prefix="ROLE_" 
            group-role-attribute="cn"/>
    </security:authentication-manager>

    <security:ldap-server id="ldapServer" url="ldap://localhost:10389/dc=oreilly,dc=com"
        manager-dn="uid=admin,ou=system" manager-password="secret"/>

</beans>

Kindly let us know how to get about solving this problem , have been stuck for days :-)

1

1 Answers

0
votes

What is telling you is that you have more than one universal pattern matching http sections in your security-config:

<security:http use-expressions="false" authentication-manager-ref="LDAPAuth">
        <security:form-login login-page="/login"
                login-processing-url="/login" username-parameter="custom_username"
                password-parameter="custom_password" default-target-url="/appointments/"
                always-use-default-target="true" authentication-failure-url="/login?error=true" />

          <security:logout logout-url="/logout"
                logout-success-url="/login?logout=true" />

          <security:intercept-url pattern="/appointments/*"
                access="ROLE_USER,ROLE_ADMIN" />
          <security:intercept-url pattern="/schedule/*"
                access="ROLE_ADMIN" />

</security:http>

<security:http use-expressions="false" authentication-manager-ref="IpAuth">
          <security:form-login login-page="/login"
                login-processing-url="/login" username-parameter="custom_username"
                password-parameter="custom_password" default-target-url="/appointments/"
                always-use-default-target="true" authentication-failure-url="/login?error=true" />

          <security:logout logout-url="/logout"
                logout-success-url="/login?logout=true" />

          <security:intercept-url pattern="/**"
                access="ROLE_USER,ROLE_ADMIN" />    
</security:http>

If you want to have more than one <security:http /> elements, you must apply a pattern to all of them except the last. For example:

<security:http pattern="/zone1/*" ... />
<security:http pattern="/zone2/*" ... />
...
<security:http ... /> <!-- the last one does not need to apply a pattern -->

According to your config, in your first security:http element you have two intercept-url patterns (/appointmens/**, /schedule/**). You could try to apply a regex matcher to the first security:http element (based in this answer):

<security:http request-matcher="regex" pattern="^/(appointments|schedule)(/(\S)+)+$" 
               use-expressions="false" authentication-manager-ref="LDAPAuth" >
...
</security:http>
<security:http use-expressions="false" authentication-manager-ref="IpAuth">
...
</security>
  • Please check the regex to avoid any typo or error I could made.

Looking deeper in your config, I see that the only difference from one to each other is the use of a different authentication-manager. Maybe you could try mixing the two authentication-providers in the same manager, as spring-security is capable of managing more than one authentication provider at the same time. It is able to check the login request to one provider and then to the other (or others) and then act accordingly.

It would be more or less like that:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <context:component-scan base-package="com.oreilly.security"/>
    <bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />

    <security:http use-expressions="false" authentication-manager-ref="authenticationManager">
        <security:form-login login-page="/login"
            login-processing-url="/login" username-parameter="custom_username"
            password-parameter="custom_password" default-target-url="/appointments/"
            always-use-default-target="true" authentication-failure-url="/login?error=true" />

        <security:logout logout-url="/logout"
            logout-success-url="/login?logout=true" />

        <security:intercept-url pattern="/appointments/*"
            access="ROLE_USER,ROLE_ADMIN" />
        <security:intercept-url pattern="/schedule/*"
            access="ROLE_ADMIN" />


        <security:intercept-url pattern="/**"
            access="ROLE_USER,ROLE_ADMIN" />    
    </security:http>



    <security:authentication-manager id ="authenticationManager"> 
        <security:authentication-provider ref="customAuthenticationProvider"/>
        <security:ldap-authentication-provider user-search-filter="(uid={0})" 
            group-search-base="ou=groups" group-search-filter="(uniqueMember={0})" 
            server-ref="ldapServer" user-context-mapper-ref="contextMapper" role-prefix="ROLE_" 
            group-role-attribute="cn"/>
    </security:authentication-manager>

    <security:ldap-server id="ldapServer" url="ldap://localhost:10389/dc=oreilly,dc=com"
        manager-dn="uid=admin,ou=system" manager-password="secret"/>

</beans>

Note I merged your two managers in just one with both authentication providers inside it. Then, I merged too the <security:http /> elements in just one (so that it is not longer necessary to apply any regex nor any other pattern to it) and now there are three <security:intercept-url /> elements, the two from the first original <security:http> and the one from the second.