2012-02-20 5 views
2

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

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

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

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

Благодаря

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

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

ответ

3

У меня возникло это решение проблемы.

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

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

(подробнее о добавлении конфигурации в this so question)

Тогда следующий шаг должен был прочитать домен из учетных данных Пользователя в том, как я упоминаю в этом вопросе.Получив домен, я попытаюсь найти соответствующий контроллер домена из значений конфигурации, чтобы получить правильную строку соединения 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

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

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

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

+0

Ограничения безопасности - это мое первое предположение. Однако в более старой реализации метода я использовал это с помощью DirectoryEntry и DirectorySearcher более старых библиотек .NET 2.0. В этом случае мне нужно было передать имя пользователя и пароль, чтобы связать вызов, и это решит проблему с двойным перерывом. Теперь, похоже, я вообще не подключаюсь. Главное отличие теперь в том, что я должен разрешить пользователям указывать домен, к которому они принадлежат, чтобы быть более универсальным. –

+0

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

+0

@NikosSteiakakis Если вы выясните решение, напишите его здесь. – gizgok

Смежные вопросы