【问题标题】:Spring Security for Active Directory searches by 'userPrincipalName' -- is there a way to change this?通过“userPrincipalName”搜索 Active Directory 的 Spring Security——有没有办法改变它?
【发布时间】:2014-08-16 14:57:43
【问题描述】:

我仍在学习 LDAP / Active Directory,如果我的术语完全错误,请纠正我 :)

在我们的 Java Web 应用程序中,我尝试使用 Spring Security LDAP 来保护它。我设法让 Spring Security 使用内存身份验证,但我们需要将它绑定到我们的 AD 服务器。

我将使用 com.test

来掩盖我们的实际域

这是我尝试从我的应用程序登录时收到的错误

13:39:55,701 错误 ActiveDirectoryLdapAuthenticationProvider:133 - 无法找到经过身份验证的用户的目录条目:johnsmit javax.naming.NameNotFoundException:[LDAP:错误代码 32 - 0000208D: NameErr: DSID-0310020A, 问题 2001 (NO_OBJECT), 数据 0, 最佳匹配 of: 'CN=Users,DC=ad,DC=test,DC=com'

我在 Spring 中使用基于类的配置 这是我的 SecurityConfiguration 类

@Configuration
@EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
          provider = new ActiveDirectoryLdapAuthenticationProvider("ad.test.com", "ldap://servername.ad.test.com:389/cn=Users,dc=ad,dc=test,dc=com");

        provider.setUseAuthenticationRequestCredentials(true);


        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().failureUrl("/login?error")
                .loginPage("/login")
                .permitAll()
                .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
                .permitAll()
                .and()
                .httpBasic();

    }
}

所以这就是问题所在(至少我认为)... 在我们的 AD 服务器中,我们有我们的 cnnamesAMAccountNameuid 作为我们登录时使用的用户名,johnsmit 在我上面的例子中。

我们的 userPrincipalName(在我们的 AD 服务器中)是我们的电子邮件地址,所以 john.smith@test.com

我正在查看 ActiveDirectoryLdapAuthenticationProvider 类,它说它使用 userPrincipalName。查看代码here on github 它表明它正在使用userPrincipalName。我检查了尚未通用的 Spring Security 的较新版本,但它是同一件事。

必须以某种方式让我可以使用用户名“johnsmit”而不是“john.smith@test.com”来搜索 AD...

如果 searchFilter 是 String searchFilter = "(&(objectClass=user)(sAMAccountName={0}))"; 那将是理想的情况,但我不知道这是否可以在任何地方覆盖并且我找不到任何文档?

【问题讨论】:

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


    【解决方案1】:

    我想我会用这张 Jira 票回答我自己的问题

    https://jira.spring.io/browse/SEC-1915

    看起来它根本没有被合并。不过,这张票中的补丁将是我需要的答案。

    【讨论】:

      【解决方案2】:

      三年后,我也在努力解决这个问题。由于建议将 userPrincipalName 更改为 Office365 的邮件地址(请参阅Office 365 – Why Your UPN Should Match Your Primary SMTP Address),我认为其他人可能也有问题 - 所以这是我的解决方案。

      github上有一个讨论是在讨论这个问题: https://github.com/spring-projects/spring-security/issues/2448

      用户 gkibilov 的回答解决了我的问题。想法是更改 ActiveDirectoryLdapAuthenticationProvider 类中的“searchForUser”方法,以便不仅传递 bindprincipal (=USERNAME@DOMAIN) 还传递用户名。

      之后可以使用以下 searchFilter 来查找 sAMAccountName 而不是 userPrincipalName:

      "(&(objectClass=user)(sAMAccountName={1}))"
      

      以下是我执行的单个步骤:

      1. 复制ActiveDirectoryAuthenticationException类的源代码 到一个新类并将其重命名(即“MyActiveDirectoryAuthenticationException”):SourceLink

      2. 复制ActiveDirectoryLdapAuthenticationProvider 的来源 类为一个新类并重命名它(即 “MyActiveDirectoryLdapAuthenticationProvider”):SourceLink

      3. MyActiveDirectoryLdapAuthenticationProvider 中的 ActiveDirectoryAuthenticationException 类替换为新的异常类 (MyActiveDirectoryAuthenticationException)

      4. 更改MyActiveDirectoryAuthenticationException 类中的方法也传递用户名:

        private DirContextOperations searchForUser(DirContext context, String username)
            throws NamingException {
             SearchControls searchControls = new SearchControls();
             searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        
             String bindPrincipal = createBindPrincipal(username);
             String searchRoot = rootDn != null ? rootDn
                     : searchRootFromPrincipal(bindPrincipal);
        
             try {
                 return SpringSecurityLdapTemplate.searchForSingleEntryInternal(context,
                    searchControls, searchRoot, searchFilter,
                    new Object[] { bindPrincipal, username});
             }
             ...
        }
        
      5. 更改 searchFilter 以查找 sAMAccountName 属性。在您的情况下,bean 应如下所示:

        @Bean
        public MyActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
            provider = new MyActiveDirectoryLdapAuthenticationProvider("ad.test.com", "ldap://servername.ad.test.com:389/cn=Users,dc=ad,dc=test,dc=com");
            provider.setSearchFilter("(&(objectClass=user)(sAMAccountName={1}))");
            provider.setUseAuthenticationRequestCredentials(true);
            return provider;
        }
        

      我不得不承认,复制一个类并不是最好的解决方案,但由于原始类是“最终的”,我找不到更好的方法来解决这个问题。

      【讨论】:

        【解决方案3】:

        因为我发现这对解决我自己的问题非常有帮助,所以我想补充一点,@JanTheGun 建议的更改似乎已合并到 Spring Security 5.0.8.RELEASE / Spring Boot 2.0.5

        ActiveDirectoryLdapAuthenticationProvider.setSearchFilter(String) 的 JavaDoc 内容如下:

        用于搜索正在验证的用户的 LDAP 过滤器字符串。 {0} 的出现被替换为 username@domain{1} 的出现仅替换为用户名。

        默认为:(&(objectClass=user)(userPrincipalName={0})))

        因此,在 Spring Security 5.0.8.RELEASE 中,可以使用建议的搜索过滤器更改,而不必复制任何 Spring Security 类!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-10
          • 2016-03-27
          • 1970-01-01
          • 2020-03-16
          • 2015-09-11
          • 2019-01-15
          相关资源
          最近更新 更多