Spring Security 4.0.2 - Диспетчер множественной аутентификации - Ошибка при создании bean-компонента с именем 'org.springframework.security.filterChainProxy'

В течение некоторого времени мы работали с одним диспетчером аутентификации (LDAP) в Spring Security, теперь нам требуются два диспетчера аутентификации: один для входа в систему - LDAP, а другой - для безопасности на основе IP. Поскольку безопасность на основе IP используется как глобальный фильтр, а LDAP только для входа в систему. Отсюда два менеджера аутентификации. Мы пробовали решение в аналогичных вопросах, но по-прежнему сталкивались с той же проблемой.

Код ошибки:

org.springframework.beans.factory.BeanCreationException: ошибка создания bean-компонента с именем org.springframework.security.filterChainProxy: не удалось вызвать метод инициализации; вложенное исключение - java.lang.IllegalArgumentException: универсальный шаблон соответствия ('/ **') ** определяется перед другими шаблонами в цепочке фильтров, что приводит к их игнорированию. Пожалуйста, проверьте порядок в вашем пространстве имен или конфигурации bean-компонента FilterChainProxy.

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
<?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>
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>

Пожалуйста, дайте нам знать, как решить эту проблему, мы застряли в течение нескольких дней :-)


person nocon    schedule 13.12.2016    source источник


Ответы (1)


Что вам говорит, так это то, что у вас есть более одного универсального шаблона, соответствующего http-разделам в вашей конфигурации безопасности:

<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:http /> элемента, вы должны применить шаблон ко всем из них, кроме последнего. Например:

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

Согласно вашей конфигурации, в вашем первом элементе security:http у вас есть два шаблона intercept-url (/appointmens/**, /schedule/**). Вы можете попробовать применить сопоставление регулярных выражений к первому элементу security:http (на основе ​​этого ответа):

<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>
  • Пожалуйста, проверьте регулярное выражение, чтобы избежать опечаток или ошибок, которые я мог допустить.

Заглянув глубже в вашу конфигурацию, я вижу, что единственная разница между ними заключается в использовании разных authentication-manager. Возможно, вы могли бы попробовать смешать два authentication-providers в одном диспетчере, поскольку spring -security может управлять более чем одним провайдером аутентификации одновременно. Он может проверять запрос входа в систему к одному провайдеру, а затем к другому (или другим), а затем действовать соответствующим образом.

Это было бы примерно так:

<?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>

Обратите внимание, что я объединил ваших двух менеджеров в один с обоими поставщиками аутентификации внутри него. Затем я также объединил элементы <security:http /> только в один (чтобы больше не было необходимости применять к нему какое-либо регулярное выражение или какой-либо другой шаблон), и теперь есть три элемента <security:intercept-url />, два из первого исходного <security:http> и один из второй.

person jlumietu    schedule 13.12.2016
comment
Спасибо за помощь .. Мы попробовали вариант <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>, но похоже, что он пропускает Auth-провайдеров .. он вообще не обращается к customAuthenticationProvider ... Еще раз спасибо за вашу помощь. - person nocon; 14.12.2016