簡體   English   中英

使用 Spring Security 使用 Active Directory LDAP 進行身份驗證時出現錯誤憑據

[英]Bad Credentials when authenticating with active directory LDAP with Spring Security

我正在嘗試使用 Spring Security 在我的 REST 控制器前執行身份驗證和授權,該控制器也使用 SSL 進行保護。 我擁有的代碼主要來自https://spring.io/guides/gs/authenticating-ldap/ 上的示例

該應用程序使用嵌入式 LDAP 服務器正常工作,如鏈接中所示。 我連接到我的主頁 https://localhost:9000/training/trackerHome 並使用用戶“ben”和密碼“benspassword”(如鏈接中指定的)登錄。 一切安好。

但是,當我更新我的屬性並嘗試連接到真正的 LDAP 服務器時,我總是在登錄頁面上收到顯示“Bad Credentials”的錯誤消息。 錯誤日志如下所示:

training-server_1    | 2020-11-10 17:07:23.728 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
training-server_1    | 2020-11-10 17:07:23.728 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
training-server_1    | 2020-11-10 17:07:23.729 DEBUG 1 --- [nio-8443-exec-2] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
training-server_1    | 2020-11-10 17:07:23.729 DEBUG 1 --- [nio-8443-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1b6d157. A new one will be created.
training-server_1    | 2020-11-10 17:07:23.730 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
training-server_1    | 2020-11-10 17:07:23.730 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
training-server_1    | 2020-11-10 17:07:23.740 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
training-server_1    | 2020-11-10 17:07:23.740 DEBUG 1 --- [nio-8443-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/logout'
training-server_1    | 2020-11-10 17:07:23.741 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
training-server_1    | 2020-11-10 17:07:23.741 DEBUG 1 --- [nio-8443-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/login'
training-server_1    | 2020-11-10 17:07:23.742 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
training-server_1    | 2020-11-10 17:07:23.743 DEBUG 1 --- [nio-8443-exec-2] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
training-server_1    | 2020-11-10 17:07:23.744 DEBUG 1 --- [nio-8443-exec-2] o.s.s.l.a.LdapAuthenticationProvider     : **Processing authentication request for user: john.doe**
training-server_1    | 2020-11-10 17:07:23.784 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.**BadCredentialsException: Bad credentials**
training-server_1    |
training-server_1    | org.springframework.security.authentication.BadCredentialsException: Bad credentials
training-server_1    |  at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:197) ~[spring-security-ldap-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:85) ~[spring-security-ldap-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) ~[spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_212]
training-server_1    |  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_212]
training-server_1    |  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]
training-server_1    |
training-server_1    | 2020-11-10 17:07:23.785 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Updated SecurityContextHolder to contain null Authentication
training-server_1    | 2020-11-10 17:07:23.786 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@63d9b403
training-server_1    | 2020-11-10 17:07:23.786 DEBUG 1 --- [nio-8443-exec-2] .a.SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error
training-server_1    | 2020-11-10 17:07:23.786 DEBUG 1 --- [nio-8443-exec-2] o.s.s.web.DefaultRedirectStrategy        : Redirecting to '/login?error'
training-server_1    | 2020-11-10 17:07:23.787 DEBUG 1 --- [nio-8443-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
training-server_1    | 2020-11-10 17:07:23.787 DEBUG 1 --- [nio-8443-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

我的部分困惑是密碼的處理。 我不確定要為密碼編碼器指定什么(如果有)? 我擔心我可能正在對已經編碼的密碼進行編碼。 我已經嘗試了所有可能的密碼編碼器類型,而且根本沒有使用密碼編碼器。 仍然收到錯誤憑據錯誤。

使用嵌入式 LDAP 服務器時的 application.properties:

ldap.server.url=ldap://localhost:8389/dc=springframework,dc=org
spring.ldap.username=
spring.ldap.password=
ldap.password.encoder=bcrypt
ldap.user.dn.pattern="uid={0},ou=people"
ldap.group.search.base="ou=groups"


# Configuration of Spring's embedded LDAP server (used for development and testing)
spring.ldap.embedded.ldif=classpath:test-server.ldif
spring.ldap.embedded.port=8389
spring.ldap.embedded.base-dn=dc=springframework,dc=org

test-server.ldif 摘錄顯示用戶“ben”的定義

dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: $2a$10$c6bSeWPhg06xB1lvmaWNNe4NROmZiSpYhlocU/98HNr2MhIOiSt36

使用實際 LDAP 服務器時的 application.properties:

ldap.server.url=ldap://125.126.127.128:389/DC=MY-LAB,DC=MY-COMPANY,dc=local
spring.ldap.username=MY-Lab\manager.doe
spring.ldap.password=validpassword
ldap.password.encoder=none
ldap.user.dn.pattern="uid={0},ou=MY-LAB"
ldap.group.search.base="ou=MY-LAB"

實際的 LDAP 服務器結構:

DC=MY-LAB,DC=MY-COMPANY,DC=local[125.126.127.128]
    OU=Domain Controllers
    OU=MY-LAB
        OU=Users
            OU=Outside Users
                CN=Manager Doe
                      (User principal name = manager.doe)
                CN=John Doe
                      (User principal name = john.doe)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);

  @Value("${ldap.server.url}")
  private String ldapServerUrl;

  @Value("${spring.ldap.username}")
  private String ldapManagerDn;

  @Value("${spring.ldap.password}")
  private String ldapManagerPassword;

  @Value("${ldap.password.encoder}")
  private String ldapPasswordEncoder;

  @Value("${ldap.user.dn.pattern}")
  private String ldapUserDnPattern;

  @Value("${ldap.group.search.base}")
  private String ldapGroupSearchBase;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin();
  }


  @Override
  @SuppressWarnings("deprecation")
  public void configure(AuthenticationManagerBuilder auth) throws Exception {

    PasswordEncoder passwordEncoder;
    switch(ldapPasswordEncoder) {
      case "none":
        passwordEncoder = null;
        break;
      case "bcrypt":
        passwordEncoder = new BCryptPasswordEncoder();
        break;
      case "ldap":
        passwordEncoder = new LdapShaPasswordEncoder();
        break;
      case "MD4":
        passwordEncoder = new Md4PasswordEncoder();
        break;
      case "MD5":
        passwordEncoder = new MessageDigestPasswordEncoder("MD5");
        break;
      case "pbkdf2":
        passwordEncoder = new Pbkdf2PasswordEncoder();
        break;
      case "scrypt":
        passwordEncoder = new SCryptPasswordEncoder();
        break;
      case "SHA-1":
        passwordEncoder = new MessageDigestPasswordEncoder("SHA-1");
        break;
      case "SHA-256":
        passwordEncoder = new MessageDigestPasswordEncoder("SHA-256");
        break;
      case "sha256":
        passwordEncoder = new StandardPasswordEncoder();
        break;
      default:
        log.warn("password encoder property not specified. Using default value.");
        passwordEncoder = new BCryptPasswordEncoder();
    }

    if(passwordEncoder != null) {
      auth.ldapAuthentication().userDnPatterns(ldapUserDnPattern).groupSearchBase(ldapGroupSearchBase).contextSource().url(
          ldapServerUrl).managerDn(ldapManagerDn).managerPassword(ldapManagerPassword).and().passwordCompare().passwordEncoder(
              passwordEncoder).passwordAttribute("userPassword");
    } else {
      
auth.ldapAuthentication().userDnPatterns(ldapUserDnPattern).groupSearchBase(ldapGroupSearchBase).contextSource().url(
          ldapServerUrl).managerDn(ldapManagerDn).managerPassword(ldapManagerPassword).and().passwordCompare().passwordAttribute(
              "userPassword");
    }
  }
}

任何想法我做錯了什么,使與真正的 LDAP 服務器的身份驗證總是返回“錯誤的憑據”?

實際 LDAP 中的密碼編碼器是什么? 你確定 ldap.password.encoder 等於它。 例如,如果是 sha1,則 ldap.password.encoder 的值將是 SHA-1。 如果您不想對密碼進行編碼。 請按如下方式修復它。 希望對你有用。

import org.springframework.security.crypto.password.NoOpPasswordEncoder;

    switch(ldapPasswordEncoder) {
      case "none":
        passwordEncoder = NoOpPasswordEncoder.getInstance();
        break;
     ....
   }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM