Как проверить учетные данные, переданные в PrincipalContext - PullRequest
0 голосов
/ 30 апреля 2018

Это продолжение до моего предыдущего вопроса .

Вопрос

Как правильно проверить учетные данные, переданные PrincipalContext?

Фон

В моем приложении я создаю PrincipalContext, используя PrincipalContext(ContextType, String, String, String). У меня есть ряд интеграционных тестов, которые не выполняются, когда учетные данные неверны (или предоставленные учетные данные не для администратора), поэтому я хочу иметь возможность это перехватить.

Если учетные данные недействительны, PrincipalContext.ConnectedServer выдает System.DirectoryServices.DirectoryServicesCOMException, однако это не обнаруживается до первого использования PrincipalContext.

try
{
    PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "my_domain.local", "wrong_username", "wrong_password");
}
catch (exception e)
{
    // This block is not hit
}

// `System.DirectoryServices.DirectoryServicesCOMException` raised here
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, samAccountName)) {}

Сведения об исключении:

System.DirectoryServices.DirectoryServicesCOMException
  HResult=0x8007052E
  Message=The user name or password is incorrect.

  Source=System.DirectoryServices
  StackTrace:
   at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.PropertyValueCollection.PopulateList()
   at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
   at System.DirectoryServices.PropertyCollection.get_Item(String propertyName)
   at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer()
   at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit()
   at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
   at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx()
   at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate)
   at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, IdentityType identityType, String identityValue)
   at System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, IdentityType identityType, String identityValue)

Что я пробовал

Первоначально я думал проверить учетные данные при создании, однако, если мы повторно используем PrincipalContext с другими учетными данными, мы получим System.DirectoryServices.Protocols.LdapException.

PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "my_domain.local", "correct_username", "correct_password");
if (ctx.ValidateCredentials("correct_username", "correct_password"))
{
    // `System.DirectoryServices.Protocols.LdapException` raised here
    using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, different_user)) {}
}

Сведения об исключении:

System.DirectoryServices.Protocols.LdapException
  HResult=0x80131500
  Message=The LDAP server is unavailable.

  Source=System.DirectoryServices.Protocols
  StackTrace:
   at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
   at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind()
   at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions)
   at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)
   at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)

Какой правильный подход?

Есть ли приемлемый способ проверить это? Должен ли я попытаться присвоить PrincipalContext.ConnectedServer локальной переменной и перехватить исключение?

1 Ответ

0 голосов
/ 30 апреля 2018

Вы можете просто переместить фактическое использование контекста в блок try:

try
{
    PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "my_domain.local", "wrong_username", "wrong_password");
    using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, samAccountName)) {}
}
catch (exception e)
{

}

Если вы планируете использовать этот контекст для других операций, то это единственный способ проверить, как проверить учетные данные.

Но если ваша цель only заключается в проверке учетных данных, то вы можете использовать DirectoryEntry напрямую (установить System.DirectoryServices из NuGet). Из трассировки стека вы увидите, что PrincipalContext в любом случае использует DirectoryEntry внизу. Я обнаружил, что непосредственное использование DirectoryEntry намного, намного быстрее, хотя иногда с ним может быть сложнее работать.

Вот как вы могли бы проверять учетные данные, используя DirectoryEntry:

var entry = new DirectoryEntry("LDAP://domain.local", "username", "password");
//creating the object doesn't actually make a connection, so we have to do something to test it
try {
    //retrieve only the 'cn' attribute from the object
    entry.RefreshCache(new[] {"cn"});
} catch (Exception e) {

}

Другой способ - использовать LdapConnection напрямую (установите System.DirectoryServices.Protocols из NuGet). Вероятно, это наименьший объем фактического сетевого трафика, который должен произойти для проверки учетных данных. Но вам, возможно, придется выяснить способ аутентификации. По умолчанию используется Negotiate, но если это не сработает, вам придется использовать другой конструктор и вручную выбрать метод аутентификации.

var id = new LdapDirectoryIdentifier("domain.local");
var conn = new LdapConnection(id, new NetworkCredential("username", "password"));
try {
    conn.Bind();
} catch (Exception e) {

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...