Междоменная аутентификация с использованием DirectoryServices - PullRequest
2 голосов
/ 20 февраля 2012

Мне нужно создать метод для моего веб-приложения в интрасети, который будет аутентифицировать пользователя, используя DirectoryServices, либо для домена по умолчанию, либо для указанного пользователем.

В моей форме входа в систему пользователь сможет указать учетные данные в виде "username" и "password "или "domain\username" и "password". Первый случай можно использовать, когда пользовательв том же домене, что и веб-сервер, и довольно прост. Код, который я использую:

 string domain = "";
 // Code to check if the username is in form of "domain\user" or "user"
 string username = ParseUsername(username, out domain);
 if(domain == "")
    domain = defaultDomain;

 PrincipalContext context = new PrincipalContext(ContextType.Domain, domain, username, password); 
 bool IsAuthenticated = context.ValidateCredentials(username, password)

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

Для локального домена код работает нормально. Однако, когда я пытаюсь проверить другой домен, указанный через имя пользователя, я получаю сообщение об ошибке «С сервером невозможно связаться».

Я также пытался использовать разные ContextOptions, такие как ContextOptions.SimpleBind или ContextOptions.Negotiate, но мне всегда кажется, что я получаю один и тот же результат.

Мне нужно реализовать это, так как приложение поставляетсядля разных клиентов, с одним доменом или несколькими доменами. Есть ли что-то еще, что я должен указать в случае «удаленных» доменов?o быть гибким, так как это будет развернуто в различных средах.

Спасибо

EDIT : я должен указать, что я предпочитаю делать это, используя DirectoryServices.AccountManagement и PrincipalContext, чтобы использовать и другие функциональные возможности, которые он предоставляет.

Кроме того, я должен отметить, что для моих тестов моя машина Dev находится в сети 10.0.0. * И второй домен, с которым я тестируюнаходится на 10.0.1. *.У меня есть маршрут и все, и я могу успешно подключиться с помощью клиента ldap, поэтому вопрос заключается в том, почему я не могу подключиться к домену через приложение asp.net.

Ответы [ 2 ]

3 голосов
/ 23 февраля 2012

Я придумал это решение проблемы.

Для поддержки нескольких доменов, как в доверительных отношениях, так и даже в изолированных сетях, в первую очередь я добавил NameValueCollection в мой web.config, чтобы вывести список доменов и их контроллеров доменов.

  <domains>
    <add key="domain1" value="10.0.0.1"/>
    <add key="domain2" value="10.0.1.11"/>
  </domains>

(более подробная информация о конфигурации добавлена ​​в , поэтому вопрос )

Затем следующим шагом было чтение домена из учетных данных пользователя, как я упомянул в вопросе. Получив домен, я пытаюсь найти соответствующий контроллер домена по значениям конфигурации, чтобы получить правильную строку подключения LDAP. Итак, мой метод таков:

private string GetLDAPConnection(string a_Domain, string a_Username, string a_Password)
{
    // Get the domain controller server for the specified domain
    NameValueCollection domains = (NameValueCollection)ConfigurationManager.GetSection("domains");
    string domainController = domains[a_Domain.ToLower()];

    string ldapConn = string.Format("LDAP://{0}/rootDSE", domainController);

    DirectoryEntry root = new DirectoryEntry(ldapConn, a_Username, a_Password);
    string serverName = root.Properties["defaultNamingContext"].Value.ToString();
    return string.Format("LDAP://{0}/{1}", domainController, serverName);
}

Как только я получаю правильную строку подключения, я делаю новый вызов для аутентификации пользователя, обращаясь к соответствующему LDAP

    ...
    string ldapConn = GetLDAPConnection(domain, username, a_Password);                             
    DirectoryEntry entry = new DirectoryEntry(ldapConn, username, a_Password);        

    try
    {
        try
        {
            object obj = entry.NativeObject;
        }
        catch(DirectoryServicesCOMException comExc)
        {
            LogException(comExc);
            return false;
        }

        DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = string.Format("(SAMAccountName={0})", username);
        search.PropertiesToLoad.Add("cn");
        SearchResult result = search.FindOne();

С этого момента я также могу выполнять все остальные запросы, такие как членство пользователя в группе и т. Д.

Поскольку вызов к удаленным доменам должен быть привязан к пользователю, я использую учетные данные «вызывающих» пользователей. Таким образом, пользователь получает аутентификацию, и вызов привязывается к конкретному пользователю. Кроме того, я указываю домен по умолчанию для случаев, когда пользователи предоставляют свои учетные данные без указания домена.

Мне не удалось этого, однако, используя PrincipalContext, как я хотел, но, с другой стороны, это решение применимо и к более старым приложениям .NET 2.0.

Я не уверен, что это лучшее решение проблемы, однако, похоже, оно работает в тестах, которые мы до сих пор проводили.

1 голос
/ 20 февраля 2012

Я не знаю, почему я получил отрицательное голосование, но вот, что я думаю, может быть неправильно: уровень доверия между сервером / доменом, на котором размещен ваш код, и доменом, с которым вы пытаетесь установить связь, могут быть не установлены. Я не могу предоставить вам причины, по которым это может происходить.

[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]

Вы можете попробовать добавить это выше своей функции и посмотреть, поможет ли это вам пройти, но кроме этого я не понимаю, почему было бы неправильно искать в домене WinNT всех возможных пользователей. Надеюсь, это поможет

...