java 使用 spring security 找不到 AuthenticationProvider
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14823504/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
No AuthenticationProvider found using spring security
提问by James
I have been trying to authenticate a user via LDAP using their x509 certificate and cannot seem to get it working. I have an authentication provider declared, but I am still getting an error thrown saying there is no provider.
我一直在尝试使用他们的 x509 证书通过 LDAP 对用户进行身份验证,但似乎无法使其正常工作。我声明了一个身份验证提供程序,但我仍然收到一条错误消息,指出没有提供程序。
Here is my debugged output:
这是我的调试输出:
INFO: Initiating Jersey application, version 'Jersey: 1.12 02/15/2012 04:51 PM'
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 1 of 8 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
DEBUG: o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 2 of 8 in additional filter chain; firing Filter: 'customX509AuthenticationFilter'
DEBUG: m.d.CustomX509AuthenticationFilter - Checking secure context token: null
DEBUG: m.d.CustomX509AuthenticationFilter - X.509 client authentication certificate: [removed to save space]
DEBUG: m.d.CustomX509PrincipalExtractor - Subject DN is 'CN=Last.First.M.1234567890, OU=GROUP1, O=ORG, C=US'
DEBUG: m.d.CustomX509PrincipalExtractor - Extracted Principal name is '1234567890'
DEBUG: m.d.CustomX509AuthenticationFilter - X.509 client authentication certificate: [removed to save space]
DEBUG: m.d.CustomX509AuthenticationFilter - preAuthenticatedPrincipal = 1234567890, trying to authenticate
DEBUG: m.d.CustomX509AuthenticationFilter - Cleared security context due to exception
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:196) ~[spring-security-core-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:115) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:85) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:184) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:155) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) [catalina.jar:6.0.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:6.0.29]
at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:205) [cors-filter-1.3.2.jar:na]
at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:266) [cors-filter-1.3.2.jar:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) [catalina.jar:6.0.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:6.0.29]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) [catalina.jar:6.0.29]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [catalina.jar:6.0.29]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [catalina.jar:6.0.29]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [catalina.jar:6.0.29]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [catalina.jar:6.0.29]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) [catalina.jar:6.0.29]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) [tomcat-coyote.jar:6.0.29]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) [tomcat-coyote.jar:6.0.29]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) [tomcat-coyote.jar:6.0.29]
at java.lang.Thread.run(Thread.java:679) [na:1.6.0_22]
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 3 of 8 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 4 of 8 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 5 of 8 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 6 of 8 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: o.s.s.w.s.SessionManagementFilter - Requested session ID E34E30E0411B02EFA37B41BCBA282041 is invalid.
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 7 of 8 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: o.s.security.web.FilterChainProxy - /x509 at position 8 of 8 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /x509; Attributes: [hasRole('user')]
DEBUG: o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG: o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@6b207925, returned: -1
DEBUG: o.s.s.w.a.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-3.1.1.RELEASE.jar:3.1.1.RELEASE]
...
DEBUG: o.s.s.w.s.HttpSessionRequestCache - DefaultSavedRequest added to Session: DefaultSavedRequest[https://192.168.56.67/cert/x509]
DEBUG: o.s.s.w.a.ExceptionTranslationFilter - Calling Authentication entry point.
DEBUG: o.s.s.w.a.Http403ForbiddenEntryPoint - Pre-authenticated entry point called. Rejecting access
DEBUG: o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG: o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Here is my spring-security.xml:
这是我的 spring-security.xml:
<http entry-point-ref="http403" use-expressions="true">
<intercept-url pattern="/**" access="hasRole('user')" />
<custom-filter position="PRE_AUTH_FILTER" ref="x509Filter" />
</http>
<global-method-security secured-annotations="enabled" />
<authentication-manager alias="authManager">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<beans:bean id="http403" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<beans:bean id="x509Filter" class="CustomX509AuthenticationFilter">
<beans:property name="authenticationManager" ref="authManager" />
<beans:property name="principalExtractor">
<beans:bean class="CustomX509PrincipalExtractor" />
</beans:property>
</beans:bean>
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg>
<beans:ref bean="authenticator" />
</beans:constructor-arg>
<beans:constructor-arg>
<beans:ref local="populator" />
</beans:constructor-arg>
<beans:property name="hideUserNotFoundExceptions" value="false" />
</beans:bean>
<beans:bean id="authenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator">
<beans:constructor-arg>
<beans:ref local="contextSource" />
</beans:constructor-arg>
<beans:property name="userSearch">
<beans:ref local="userSearch" />
</beans:property>
</beans:bean>
<beans:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<beans:constructor-arg value="ldap://localhost:389/dc=my,dc=domain" />
<beans:property name="userDn" value="cn=manager,dc=my,dc=domain" />
<beans:property name="password" value="password" />
</beans:bean>
<beans:bean id="populator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<beans:constructor-arg index="0">
<beans:ref local="contextSource" />
</beans:constructor-arg>
<beans:constructor-arg index="1" value="ou=roles" />
<beans:property name="groupRoleAttribute" value="cn" />
<beans:property name="groupSearchFilter" value="(member={0})" />
<beans:property name="rolePrefix" value="none" />
<beans:property name="convertToUpperCase" value="false" />
<beans:property name="searchSubtree" value="false" />
</beans:bean>
<beans:bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg index="0" value="ou=people" />
<beans:constructor-arg index="1" value="(uid={0})" />
<beans:constructor-arg index="2">
<beans:ref local="contextSource" />
</beans:constructor-arg>
</beans:bean>
<beans:bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
<beans:constructor-arg>
<beans:ref local="userSearch" />
</beans:constructor-arg>
<beans:constructor-arg>
<beans:ref local="populator" />
</beans:constructor-arg>
</beans:bean>
I cannot figure out why the error is being thrown and have done a lot of research trying to get to the root of the problem. Any help would be greatly appreciated.
我无法弄清楚为什么会抛出错误,并且已经做了大量研究试图找到问题的根源。任何帮助将不胜感激。
Thanks, James
谢谢,詹姆斯
回答by zagyi
At a techical level the problem is that your authentication filter is incompatible with your authentication provider: your CustomX509AuthenticationFilter
creates a PreAuthenticatedAuthenticationToken
, and sends it to the configured LdapAuthenticationProvider
to be processed, but that provider only supports UsernamePasswordAuthenticationToken
s.
在技术层面,问题在于您的身份验证过滤器与您的身份验证提供程序不兼容:您CustomX509AuthenticationFilter
创建了一个PreAuthenticatedAuthenticationToken
,并将其发送到配置LdapAuthenticationProvider
以进行处理,但该提供程序仅支持UsernamePasswordAuthenticationToken
s。
You might be able to solve the problem by making your CustomX509AuthenticationFilter
create a UsernamePasswordAuthenticationToken
instead, but there seems to be some conceptual problem here, I guess.
您也许可以通过CustomX509AuthenticationFilter
创建一个来解决问题UsernamePasswordAuthenticationToken
,但我想这里似乎存在一些概念上的问题。
If a client provides a valid x509 certificate shouldn't you just trust it without further LDAP authentication? Even if you wanted this additional step, where do you get the password for the LDAP bind operation? Do you extract that from the certificate? If so, this won't give you any additional security, because if someone has the certificate, they will get authenticated anyway with or without LDAP.
如果客户端提供有效的 x509 证书,您是否应该在没有进一步 LDAP 身份验证的情况下信任它?即使您想要这个额外的步骤,您从哪里获得 LDAP 绑定操作的密码?你是从证书中提取的吗?如果是这样,这不会给您任何额外的安全性,因为如果有人拥有证书,无论是否使用 LDAP,他们都将获得身份验证。
Update after the comment from James:
在詹姆斯评论后更新:
It seems that all you need from LDAP is role information for the user identified by the certificate, in which case you don't need to authenticate it against LDAP. You only need to load user details using the LDAP manager account already configured in your contextSource
. Try the following:
似乎您需要从 LDAP 获得的只是证书标识的用户的角色信息,在这种情况下,您不需要针对 LDAP 对其进行身份验证。您只需要使用已在您的contextSource
. 请尝试以下操作:
- Wrap your
LdapUserDetailsService
in aUserDetailsByNameServiceWrapper
- Instead of the
LdapAuthenticationProvider
configure aPreAuthenticatedAuthenticationProvider
that will be able to process thePreAuthenticatedAuthenticationToken
issued by yourCustomX509AuthenticationFilter
. - Inject the wrapped
LdapUserDetailsService
into thePreAuthenticatedAuthenticationProvider
.
- 把你
LdapUserDetailsService
的UserDetailsByNameServiceWrapper
- 而不是
LdapAuthenticationProvider
configure aPreAuthenticatedAuthenticationProvider
将能够处理PreAuthenticatedAuthenticationToken
由您发出的CustomX509AuthenticationFilter
. - 将包裹
LdapUserDetailsService
注入PreAuthenticatedAuthenticationProvider
.
This will make sure that the Authentication object gets populated with all information available from LDAP. Then subsequent filters can authorize the request based on the user's granted authorities (group memberships defined in LDAP).
这将确保使用 LDAP 提供的所有信息填充 Authentication 对象。然后,后续过滤器可以根据用户授予的权限(LDAP 中定义的组成员身份)对请求进行授权。