Есть ли способ заставить вызовы UserPrincipal.GetGroups () и UserPrincipal.GetAuthorizationGroups () использовать LDAPS (порт 636) вместо LDAP (порт 389)? - PullRequest
1 голос
/ 12 февраля 2020

Мы готовимся к обновлению Microsoft AD в марте, чтобы разрешить только безопасные вызовы с использованием 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 Ответ

0 голосов
/ 12 февраля 2020

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

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

Я написал статью о поиске всех групп пользователей , в которой есть пример кода для разных сценариев ios. Вам придется изменить любой случай, когда вы создаете новый 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.

...