Есть ли способ заставить вызовы UserPrincipal.GetGroups () и UserPrincipal.GetAuthorizationGroups () использовать LDAPS (порт 636) вместо LDAP (порт 389)?

Мы готовимся к мартовскому обновлению AD для Microsoft, чтобы разрешать только безопасные вызовы с использованием LDAPS, и, проверяя наш код .Net, я обнаружил, что вызовы UserPrincipal.GetGroups () и UserPrincipal.GetAuthorizationGroups (), по-видимому, используют LDAP (порт 389), а не LDAPS (порт 636), даже если объект UserPrincipal был создан с PrincipalContext, установленным поверх LDAPS, например:

    // Explicitly using LDAPS (port 636)
    PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, "our.corpdomain.com:636", "DC=our,DC=corpdomain,DC=com", ContextOptions.Negotiate);
    UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, "someuser");

    // These calls still use LDAP (port 389)
    var groups = userPrincipal.GetAuthorizationGroups();
    var groups2 = userPrincipal.GetGroups();

Кто-нибудь знает, почему это может произойти и, если да, как заставить эти вызовы использовать LDAPS? Если их нельзя заставить, есть ли обходные пути для них?

Всего 1 ответ


Это, безусловно, ошибка в коде .NET, и я отвечу на ваш вопрос, но, как я уже упоминал в вашем другом вопросе, мартовское обновление не будет «разрешать только безопасные вызовы с использованием LDAPS». Обычный порт LDAP 389 все еще будет работать после этого обновления. Я не видел доказательств того, что они когда-либо планируют его отключить.

Но если вы хотите убедиться, что он никогда не использует порт 389, вам не следует использовать UserPrincipal . Используйте DirectoryEntry и / или DirectorySearcher напрямую, что в любом случае использует UserPrincipal в фоновом режиме. Это не первая ошибка, которую я обнаружил в пространстве имен AccountManagement .

Я написал статью о поиске всех групп пользователей , в которой приведен пример кода для различных сценариев. Вам придется изменить любой случай, когда вы создаете новый объект DirectoryEntry и указываете порт 636, например:

new DirectoryEntry("LDAP://example.com:636/CN=whatever,DC=example,DC=com")

Вы можете опустить доменное имя, если хотите (просто :636 вместо example.com:636 ).

Один случай, который я не рассмотрел в этой статье, - это эквивалент GetAuthorizationGroups , то есть чтение атрибута tokenGroups . Это дает вам список идентификаторов безопасности групп, которые вы затем можете найти, чтобы найти название группы. Вот метод, который сделает это:

private static IEnumerable<string> GetTokenGroups(DirectoryEntry de) {
    var groupsFound = 0;

    //retrieve only the tokenGroups attribute from the user
    de.RefreshCache(new[] {"tokenGroups"});

    while (true) {
        var tokenGroups = de.Properties["tokenGroups"];
        foreach (byte[] groupSidByte in tokenGroups) {
            groupsFound++;
            var groupSid = new SecurityIdentifier(groupSidByte, 0);
            var groupDe = new DirectoryEntry($"LDAP://:{de.Options.PasswordPort}/<SID={groupSid}>");

            groupDe.RefreshCache(new[] {"cn"});
            yield return (string) groupDe.Properties["cn"].Value;
        }

        //AD only gives us 1000 or 1500 at a time (depending on the server version)
        //so if we've hit that, go see if there are more
        if (tokenGroups.Count != 1500 && tokenGroups.Count != 1000) break;

        try {
            de.RefreshCache(new[] {$"memberOf;range={groupsFound}-*"});
        } catch (COMException e) {
            if (e.ErrorCode == unchecked((int) 0x80072020)) break; //no more results

            throw;
        }
    }
}

При этом будет использоваться любой порт, который вы использовали для создания объекта DirectoryEntry который вы передаете. Однако это ломается, если в вашей среде более одного домена. В этом случае все может быть сложно, если вы хотите всегда использовать порт 636.


Есть идеи?

10000