In my application I use LDAP authentication (called ldap ). For one of my pages I need my own authentication with basic html popup (called internal ). I get BeanCreationException
:
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 <security:http> namespace or FilterChainProxy bean configuration
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spring-context-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) ~[spring-context-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) ~[spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) ~[spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973) [catalina.jar:7.0.52]
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467) [catalina.jar:7.0.52]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.52]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) [catalina.jar:7.0.52]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) [catalina.jar:7.0.52]
at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.7.0_51]
at java.lang.Thread.run(Unknown Source) [na:1.7.0_51]
Here is my configuration:
<http authentication-manager-ref="internal">
<intercept-url pattern="/monitoring" access="ROLE_USER" />
<http-basic />
</http>
<http authentication-manager-ref="ldap" auto-config='true' use-expressions="true">
<intercept-url pattern="/**" access="permitAll" />
<form-login login-page='/' default-target-url='/login_ok'
always-use-default-target='true' authentication-failure-url="/login_failed" />
<logout logout-success-url="/" />
</http>
<authentication-manager id="internal">
<authentication-provider>
<user-service>
<user name="monitoring" password="monitoring" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<authentication-manager erase-credentials="false" id="ldap">
<ldap-authentication-provider
group-search-filter="${ldap.group-search-filter}" server-ref="ldapServer"
group-search-base="${ldap.group-search-base}" user-search-filter="${ldap.user-search-filter}"
user-search-base="${ldap.user-search-base}" group-role-attribute="${ldap.group-role-attribute}"
role-prefix="${ldap.role-prefix}">
</ldap-authentication-provider>
<authentication-provider user-service-ref="userService" />
</authentication-manager>
I understand why the exception was thrown and know that patterns order and scopes are important, but have no idea how to do it correctly. All I want, is that every user has access to "/**", but only monitoring user has access to /monitoring (authenticated with basic). Everything worked just fine, before I wanted to add this internal authentication.
The changes you need to make are:
<http>
. This is the heart of your issue right now. Both <http>
match every request, so the second <http>
is never considered. To fix this, add the pattern attribute. <http>
to match on every URL. This is not necessary since the first <http>
is only used for the /monitoring URL in the first place, but it is a bit safer if someone updated the pattern attribute later on. An example of the changes can be seen below:
<http authentication-manager-ref="internal" pattern="/monitoring">
<intercept-url pattern="/**" access="ROLE_MONITORING" />
<http-basic />
</http>
<http authentication-manager-ref="ldap" auto-config='true' use-expressions="true">
<intercept-url pattern="/**" access="permitAll" />
<form-login login-page='/' default-target-url='/login_ok'
always-use-default-target='true' authentication-failure-url="/login_failed" />
<logout logout-success-url="/" />
</http>
<authentication-manager id="internal">
<authentication-provider>
<user-service>
<user name="monitoring" password="monitoring" authorities="ROLE_MONITORING" />
</user-service>
</authentication-provider>
</authentication-manager>
<authentication-manager erase-credentials="false" id="ldap">
<ldap-authentication-provider
group-search-filter="${ldap.group-search-filter}" server-ref="ldapServer"
group-search-base="${ldap.group-search-base}" user-search-filter="${ldap.user-search-filter}"
user-search-base="${ldap.user-search-base}" group-role-attribute="${ldap.group-role-attribute}"
role-prefix="${ldap.role-prefix}">
</ldap-authentication-provider>
<authentication-provider user-service-ref="userService" />
</authentication-manager>
One thing I would consider is moving the monitoring user into LDAP. Placing this user in an in memory instance encourages that user to no longer be maintained (ie password should be rotated regularly). This would also ensure you don't get any collisions between your LDAP users and the internal users (ie how do you know there isn't a user named "monitoring" in the ldap authentication?). Last it simplifies your configuration, you only need the single <http>
configuration. If the HTTP Basic header is present, it will still authenticate using it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.