Проверка подлинности LDAP AD Spring Security завершается неудачно, когда домен не совпадает с окончанием userPrincipalName - PullRequest
0 голосов
/ 02 ноября 2019

Я использую ActiveDirectoryLdapAuthenticationProvider для аутентификации на сервере AD. Он отлично работает в большинстве сред, но есть проблема, когда имя домена не совпадает с окончанием userPrincipalName отдельных пользователей.

Я настроил следующие свойства:

xxx.api.auth.ad.domain:foo.bar.com
xxx.api.auth.ad.url:ldaps://yyy.foo.bar.com:636

А для пользователей userPrincipalName установлено как john.doe@bar.com. Обратите внимание на разницу с доменным именем

Тогда в моем LoginService у меня есть это:

private AuthResultDto loginAD(LoginDto login) {

    String adDomain = env.getProperty("xxx.api.auth.ad.domain");
    String adUrl = env.getProperty("xxx.api.auth.ad.url");

    ActiveDirectoryLdapAuthenticationProvider provider = 
            new ActiveDirectoryLdapAuthenticationProvider(adDomain, adUrl);
    provider.setConvertSubErrorCodesToExceptions(true);
    provider.setUseAuthenticationRequestCredentials(true);
    provider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());

    Authentication auth = provider
            .authenticate(new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword()));

    if (!auth.isAuthenticated())
        throw new CustomMessageException("Invalid Login");
...
}

В этом случае аутентификация завершается неудачно с сообщением Active Directory authentication failed: Supplied password was invalid.

spring-ldap-core: 2.3.2.RELEASE
spring-security-ldap: 5.0.3.RELEASE

1 Ответ

0 голосов
/ 04 ноября 2019

Кажется, проблема в том, что createBindPrincipal() внутри ActiveDirectoryLdapAuthenticationProvider проверяет, заканчивается ли username на domain, а если нет, то добавляет его . Это приводит к тому, что имя пользователя становится john.doe@bar.com@foo.bar.com

К сожалению, ActiveDirectoryLdapAuthenticationProvider является окончательным, поэтому не может его переопределить. Решение, которое мы использовали, заключается в том, чтобы не передавать domain, а вместо rootDN (созданный путем копирования кода из ActiveDirectoryLdapAuthenticationProvider)

private AuthResultDto loginAD(LoginDto login) {

    String adDomain = env.getProperty("xxx.api.auth.ad.domain");
    String adUrl = env.getProperty("xxx.api.auth.ad.url");

    ActiveDirectoryLdapAuthenticationProvider provider = 
            new ActiveDirectoryLdapAuthenticationProvider(null, adUrl, rootDnFromDomain(adDomain));
    provider.setConvertSubErrorCodesToExceptions(true);
    provider.setUseAuthenticationRequestCredentials(true);
    provider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());

    Authentication auth = provider
            .authenticate(new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword()));

    if (!auth.isAuthenticated())
        throw new CustomMessageException("Invalid Login");
...
}

// copied from ActiveDirectoryLdapAuthenticationProvider
private String rootDnFromDomain(String domain) {
    String[] tokens = StringUtils.tokenizeToStringArray(domain, ".");
    StringBuilder root = new StringBuilder();

    for (String token : tokens) {
        if (root.length() > 0) {
            root.append(',');
        }
        root.append("dc=").append(token);
    }

    return root.toString();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...