Подключение к LDAPS с помощью GSS и привязки каналов

Я пытаюсь подключиться к серверу Active Directory с помощью GSS на компьютере с Windows, который вошел в систему как пользователь домена. Обычно это нормально работает. Но когда подписание и привязка выполняется

(см. https://support.microsoft.com/en-us/help/4520412/2020-ldap-channel-binding-and-ldap-signing-requirements-for-windows)

GSS не может выполнить привязку. Согласно https://bugs.openjdk.java.net/browse/JDK-8245527, эта функция была добавлена ​​в JDK 16 (b18), но мне не удалось успешно выполнить привязку с сообщением об ошибке

javax.naming.AuthenticationException: [LDAP: error code 49 - 80090346: LdapErr: DSID-0C090595, comment: AcceptSecurityContext error, data 80090346, v3839

Другие важные детали:

  • В моей компании 3 контроллера домена, и каждый из них возвращает одну и ту же ошибку. В настоящее время для них установлено значение =1 (если поддерживается), хотя значение =2 (всегда) имеет тот же эффект.

  • Я почти уверен, что в моем проекте используется JDK 16 build 20.

  • При привязке с именем пользователя и паролем все работает как положено.

  • Кроме того, привязка через LDAP (не LDAPS) работает с GSS.

  • Критическая комбинация - GSS + LDAPS.

ИЗМЕНИТЬ Я получаю такое же поведение в JDK 15.0.1.9, как и в JDK 16. Это заставляет меня думать, что функциональность не полностью реализована в JDK16b20, однако после проверки включенного исходного кода я могу увидеть, где был добавлен код.

Ниже приведен код, используемый для подключения к серверу:

public class ActiveDirectory {

    public LdapContext getConnection(boolean ssl) throws NamingException {
        return getConnection(null, null, ssl);
    }
    public LdapContext getConnection(String username, String password, boolean ssl) throws NamingException {
        String domainName = "";
        try {
            String fqdn = java.net.InetAddress.getLocalHost().getCanonicalHostName(); //lookup the domain
            if (fqdn.split("\\.").length > 1) {
                domainName = fqdn.substring(fqdn.indexOf(".") + 1);
            }
        } catch (java.net.UnknownHostException e) {
        }
        Hashtable props = new Hashtable();
        if (password != null) { 
            password = password.trim();
            if (password.length() == 0) { //the password was blank. Bind with GSS anyway
                password = null;
            }
        }
        if (password != null) { // a password was provided. Bind as that user
            String principalName = username + "@" + domainName;
            props.put(Context.SECURITY_PRINCIPAL, principalName);
            props.put(Context.SECURITY_AUTHENTICATION, "simple");
            props.put(Context.SECURITY_CREDENTIALS, password);
        } else { //no password. Bind with GSS
            String principalName = System.getProperty("user.name")  + "@" + domainName;
            username=System.getProperty("user.name");
            props.put(Context.SECURITY_PRINCIPAL, principalName);
            props.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
            System.setProperty("sun.security.jgss.native", "true");
        }
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        String ldapURL = "";
        for (String server : domainControllers) {
            if (ssl) { //use SSL to bind
                ldapURL = "ldaps://" + server + "." + domainName + "/";
                props.put(Context.SECURITY_PROTOCOL, "ssl");
                props.put("com.sun.jndi.ldap.tls.cbtype", "tls-server-end-point"); //use channel binding !!! DOESNT WORK WITH GSS. See https://bugs.openjdk.java.net/browse/JDK-8245527?attachmentViewMode=gallery
                props.put("com.sun.jndi.ldap.connect.timeout", "2000");
            } else { //dont use ssl to bind
                ldapURL = "ldap://" + server + "." + domainName + '/';
                props.put(Context.SECURITY_PROTOCOL, "");
            }
            props.put(Context.PROVIDER_URL,ldapURL);
            try {
                return connect(props);
            } catch (NamingException e) {
                System.out.println(e.toString());
            }
        }
        throw new NamingException("Failed to authenticate " + username + "@" + domainName);
    }

    private LdapContext connect(Hashtable props) throws NamingException {
        return new InitialLdapContext(props, null);
    }

Если кто-то может заметить, что я делаю не так, я был бы очень признателен. Благодаря!

0 ответов

Другие вопросы по тегам