【问题标题】:Spring Security Active Directory LDAP Authentication without full name没有全名的 Spring Security Active Directory LDAP 身份验证
【发布时间】:2016-03-27 11:43:55
【问题描述】:

使用 Spring Security 3.2 我已经配置了 ActiveDirectoryLdapAuthenticationProvider。我可以使用全名示例 sharon@mydomain.com 进行身份验证,但是当我尝试仅使用用户名“sharon”进行身份验证时,出现以下错误

   2015-12-21_17:07:00.752 DEBUG o.s.s.l.a.a.ActiveDirectoryLdapAuthenticationProvider - authenticate - Processing authentication request for user: sharon
    2015-12-21_17:07:00.793 DEBUG o.s.s.l.SpringSecurityLdapTemplate - searchForSingleEntryInternal - Searching for entry under DN '', base = 'dc=mydomain,dc=com', filter = '(&(objectClass=user)(userPrincipalName={0}))'
    2015-12-21_17:07:00.793 INFO  o.s.s.l.SpringSecurityLdapTemplate - searchForSingleEntryInternal - Ignoring PartialResultException
    2015-12-21_17:07:00.794 DEBUG o.s.s.l.a.LdapAuthenticationProvider - authenticate - Processing authentication request for user: gdcadmin
    2015-12-21_17:07:00.796 DEBUG o.s.s.l.a.BindAuthenticator - bindWithDn - Attempting to bind as cn=gdcadmin,cn=Users,dc=mydomain,dc=com,dc=springframework,dc=org
    2015-12-21_17:07:00.796 DEBUG o.s.s.l.DefaultSpringSecurityContextSource - setupEnvironment - Removing pooling flag for user cn=gdcadmin,cn=Users,dc=mydomain,dc=com,dc=springframework,dc=org
    2015-12-21_17:07:00.858 DEBUG o.a.m.f.codec.ProtocolCodecFilter - messageReceived - Processing a MESSAGE_RECEIVED for session 1
    2015-12-21_17:07:00.859 DEBUG o.a.d.shared.asn1.ber.Asn1Decoder - decode - >>>==========================================
.....
.....
.....
015-12-21_17:07:00.905 DEBUG o.s.s.l.a.BindAuthenticator - handleBindException - Failed to bind as cn=gdcadmin,CN=Users,DC=mydomain,DC=com: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - cannot bind the principalDn.]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - cannot bind the principalDn.]

根据 spring 安全文档:

例如,名为“Sharon”的用户将能够进行身份验证 通过输入用户名 sharon 或完整的 Active Directory userPrincipalName,即 sharon@mydomain.com

我的配置

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
        auth.eraseCredentials(false);
        auth.ldapAuthentication().userDnPatterns("cn={0},CN=Users,DC=mydomain,DC=com");
    }

    @Bean
    public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(env.getProperty("mydomain.com"),
                env.getProperty("ldap://hmidir01.mydomain.com:389/"));
        provider.setConvertSubErrorCodesToExceptions(true);
        provider.setUseAuthenticationRequestCredentials(true);
        provider.setUserDetailsContextMapper(userDetailsContextMapper);
        return provider;
    }

我的配置有什么错误。

【问题讨论】:

    标签: java spring-security active-directory spring-ldap spring-security-ldap


    【解决方案1】:

    使用 Spring Security 5.2.1: 您可以使用setSearchFilter() 函数。

    LDAP 身份验证过程有两个主要步骤:绑定,它使用来自ActiveDirectoryLdapAuthenticationProvider() 的域参数(第一个)来形成这样的用户名:myUser@sub.domain.com 给定凭据:用户名= myUser;密码 myPassword。 如果这不正确,您将收到错误的凭据错误(AcceptSecurityContext 错误,数据 52e)。

    然后下一步是在 ldap 目录中找到您的用户。 如果您的用户没有名为 username 的属性 = myUser@sub.domain.com,则 ldap 服务器会给您一个未找到的错误(这将在您的日志中弹出为 Ignoring PartialResultException 来自 UsernameNotFoundException: User myUser not found in directory.例外。为此,您可以使用 searchFilter 选项。 提供的用户名将插入到{1} 点。

     @Configuration
     @EnableWebSecurity
     @AllArgsConstructor
     public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception{
        http.cors().and().csrf().disable().authorizeRequests()
                .anyRequest().fullyAuthenticated().and().httpBasic(); //this will invoke an auth popup in browser
        }
    
        @Bean
        public AuthenticationManager authenticationManager() {
            return new ProviderManager(activeDirectoryLdapAuthenticationProvider());
        }
    
        @Bean
        public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
           ActiveDirectoryLdapAuthenticationProvider provider = new 
           ActiveDirectoryLdapAuthenticationProvider("sub.domain.com","ldap://url");
           provider.setSearchFilter("mailNickname={1}"); //here is the trick
           provider.setConvertSubErrorCodesToExceptions(true);
           provider.setUseAuthenticationRequestCredentials(true);
    
        return provider;
        }
    }
    

    【讨论】:

      【解决方案2】:

      你可以通过给定的方式实现

      1) 无需将数据持久化到我们的数据库中

      WebSecurityConfig .java

      @Configuration
      @EnableWebMvcSecurity
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter  {
      
          @Bean
          public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
              ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(<ldap-domain>,<ldap-url>);
                  provider.setConvertSubErrorCodesToExceptions(true);
                  provider.setUseAuthenticationRequestCredentials(true);
              return provider;
          }
      
          @Bean
          public LoggerListener loggerListener() {
              return new LoggerListener();
          }
      
      
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
          }
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
              .authorizeRequests()
                  .antMatchers("/admin/**").hasAnyAuthority("ADMIN")
                  .antMatchers("/user/**").hasAnyAuthority("ADMIN", "USER")
                  .antMatchers("/rest/**", "/css/**", "/fonts/**", "/images/**", "/js/**").permitAll()
                  .anyRequest().authenticated()
              .and()
                  .formLogin()
                  .loginPage("/").failureUrl("/?error").successHandler("/home").permitAll()
                  .usernameParameter("emailId").passwordParameter("password")
              .and()
                  .logout()
                  .logoutUrl("/logout").logoutSuccessUrl("/").permitAll()
              .and()
                  .exceptionHandling().accessDeniedPage("/home")
              .and()
                  .csrf()
              .and()
                  .httpBasic();    
          }
      }
      

      2) 将数据持久化到我们的数据库中

      WebSecurityConfig.java

      @Configuration
      @EnableWebMvcSecurity
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter  {
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
              .authorizeRequests()
                  .antMatchers("/admin/**").hasAnyAuthority("ADMIN")
                  .antMatchers("/user/**").hasAnyAuthority("ADMIN", "USER")
                  .antMatchers("/rest/**", "/css/**", "/fonts/**", "/images/**", "/js/**").permitAll()
                  .anyRequest().authenticated()
              .and()
                  .formLogin()
                  .loginPage("/").failureUrl("/?error").successHandler("/home").permitAll()
                  .usernameParameter("emailId").passwordParameter("password")
              .and()
                  .logout()
                  .logoutUrl("/logout").logoutSuccessUrl("/").permitAll()
              .and()
                  .exceptionHandling().accessDeniedPage("/home")
              .and()
                  .csrf()
              .and()
                  .httpBasic();
          }
      
          @Autowired
          public void configureGlobal(AuthenticationManagerBuilder auth)throws Exception {
              auth
          .authenticationProvider(activeDirectoryLdapAuthenticationProvider());
          }
      
          @Bean
          public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
              ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(<ldap-domain>(null), <ldap-url>);
              provider.setConvertSubErrorCodesToExceptions(true);
              provider.setUseAuthenticationRequestCredentials(true);
              provider.setUserDetailsContextMapper(userDetailsContextMapper());
              return provider;
          }
      
          @Bean
          public UserDetailsContextMapper userDetailsContextMapper() {
              return new AttributesLDAPUserDetailsContextMapper();
          }
      }
      

      AttributesLDAPUserDetailsContextMapper.java

          public class AttributesLDAPUserDetailsContextMapper implements UserDetailsContextMapper {
      
      
              @Autowired
              private UserService service;
      
              private InetOrgPersonContextMapper ldapUserDetailsMapper = new InetOrgPersonContextMapper();
      
              @Override
              public UserDetails mapUserFromContext(DirContextOperations dirContextOperations, String userName, Collection<? extends GrantedAuthority> collection) {
      
                  InetOrgPerson userLdap = (InetOrgPerson) ldapUserDetailsMapper.mapUserFromContext(dirContextOperations, userName, collection);  
      
                  User user = service.findOne(userLdap.getUsername());
                  if (user == null) {
                      user = new Usere();
                      user.setName(StringUtils.defaultString(userLdap.getDisplayName()).trim());
                      user.setEmailId(StringUtils.defaultString(userLdap.getUsername()).trim());
                      user.setdescription(StringUtils.defaultString(userLdap.getDescription()).trim());
                      user.setIsAdmin(false);
                      user.setIsEmployee(true);
                      service.save(user);
                  }
                  return new LdapSecuredUser(user);
              }
      
              @Override
              public void mapUserToContext(UserDetails userDetails, DirContextAdapter dirContextAdapter) {
                  ldapUserDetailsMapper.mapUserToContext(userDetails, dirContextAdapter);
              }
          }
      

      LdapSecuredUser.java

      public class LdapSecuredUser extends User implements LdapUserDetails {
      
          private static final long serialVersionUID = -8997460180274787521L;
      
          public LdapSecuredUser(User user) {
              if (user != null) {
                  this.setId(user.getId());
                  this.setEmailId(user.getEmailId());
                  this.setName(user.getName());
                  this.setdescription(user.getDescription());
                  this.setIsAdmin(user.getIsAdmin());
                  this.setIsEmployee(user.getIsEmployee());
              }
          }
      
          @Override
          public Collection<? extends GrantedAuthority> getAuthorities() {
              Collection<GrantedAuthority> authorities = new ArrayList<>(); 
              authorities.add(new SimpleGrantedAuthority("USER"));
              if(super.getIsAdmin())
                  authorities.add(new SimpleGrantedAuthority("ADMIN"));   
              return authorities;
          }
      
      
          @Override
          public String getUsername() {
              return super.getEmailId();
          }
      
          @Override
          public String getPassword() {
              return null;
          }
      
          @Override
          public String getDn() {
              return null;
          }
      
          @Override
          public boolean isAccountNonExpired() {
              return false;
          }
      
          @Override
          public boolean isAccountNonLocked() {
              return false;
          }
      
          @Override
          public boolean isCredentialsNonExpired() {
              return false;
          }
      
          @Override
          public boolean isEnabled() {
              return false;
          }
      
      }
      

      【讨论】:

      • 你能解释一下吗?我看不出你的代码和我的代码之间的区别。我的要求是使用用户名而不是电子邮件/完整用户名进行身份验证。
      猜你喜欢
      • 2020-04-08
      • 1970-01-01
      • 2011-01-12
      • 2020-02-16
      • 2014-06-11
      • 2015-04-17
      • 1970-01-01
      • 2021-09-11
      • 2019-10-31
      相关资源
      最近更新 更多