Как я могу проверить имя пользователя и пароль для Active Directory? Я просто хочу проверить правильность имени пользователя и пароля.
Подтвердить имя пользователя и пароль в Active Directory?
Ответ 1
Если вы работаете с .NET 3.5 или новее, вы можете использовать пространство имен System.DirectoryServices.AccountManagement
и легко проверить свои учетные данные:
// create a "principal context" - e.g. your domain (could be machine, too)
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "mypassword");
}
Это простой, надежный, он на 100% управляемый код на вашем конце - что еще вы можете попросить?: -)
Подробнее читайте здесь:
- Управление принципами безопасности каталога в .NET Framework 3.5
- Документы MSDN в System.DirectoryServices.AccountManagement
Update:
Как указано в этом другом вопросе SO (и его ответах), существует проблема с этим вызовом, возможно, возвращая True
для старых паролей пользователя. Просто помните об этом поведении и не удивляйтесь, если это произойдет:-) (спасибо @MikeGledhill за то, что указали это!)
Ответ 2
Мы делаем это в нашей Интранет
Вы должны использовать System.DirectoryServices;
Вот кишки кода
using (DirectoryEntry adsEntry = new DirectoryEntry(path, strAccountId, strPassword))
{
using (DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry))
{
//adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person))";
adsSearcher.Filter = "(sAMAccountName=" + strAccountId + ")";
try
{
SearchResult adsSearchResult = adsSearcher.FindOne();
bSucceeded = true;
strAuthenticatedBy = "Active Directory";
strError = "User has been authenticated by Active Directory.";
}
catch (Exception ex)
{
// Failed to authenticate. Most likely it is caused by unknown user
// id or bad strPassword.
strError = ex.Message;
}
finally
{
adsEntry.Close();
}
}
}
Ответ 3
В нескольких представленных здесь решениях нет возможности различать неправильный пользователь/пароль и пароль, который необходимо изменить. Это можно сделать следующим образом:
using System;
using System.DirectoryServices.Protocols;
using System.Net;
namespace ProtocolTest
{
class Program
{
static void Main(string[] args)
{
try
{
LdapConnection connection = new LdapConnection("ldap.fabrikam.com");
NetworkCredential credential = new NetworkCredential("user", "password");
connection.Credential = credential;
connection.Bind();
Console.WriteLine("logged in");
}
catch (LdapException lexc)
{
String error = lexc.ServerErrorMessage;
Console.WriteLine(lexc);
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
}
}
}
Если пароль пользователя неверен или пользователь не существует, ошибка будет содержать
"8009030C: LdapErr: DSID-0C0904DC, комментарий: Ошибка AcceptSecurityContext, данные 52e, v1db1",
если пароль пользователя нужно изменить, он будет содержать
"8009030C: LdapErr: DSID-0C0904DC, комментарий: Ошибка AcceptSecurityContext, данные 773, v1db1"
Значение данных lexc.ServerErrorMessage
представляет собой шестнадцатеричное представление кода ошибки Win32. Это те же коды ошибок, которые были бы возвращены путем вызова вызова Win32 LogonUser API. В приведенном ниже списке представлены общие значения с шестнадцатеричным и десятичным значениями:
525 user not found (1317)
52e invalid credentials (1326)
530 not permitted to logon at this time (1328)
531 not permitted to logon at this workstation (1329)
532 password expired (1330)
533 account disabled (1331)
701 account expired (1793)
773 user must reset password (1907)
775 user account locked (1909)
Ответ 4
очень простое решение с использованием DirectoryServices:
using System.DirectoryServices;
//srvr = ldap server, e.g. LDAP://domain.com
//usr = user name
//pwd = user password
public bool IsAuthenticated(string srvr, string usr, string pwd)
{
bool authenticated = false;
try
{
DirectoryEntry entry = new DirectoryEntry(srvr, usr, pwd);
object nativeObject = entry.NativeObject;
authenticated = true;
}
catch (DirectoryServicesCOMException cex)
{
//not authenticated; reason why is in cex
}
catch (Exception ex)
{
//not authenticated due to some other exception [this is optional]
}
return authenticated;
}
для обнаружения плохих пользователей/паролей требуется доступ к NativeObject
Ответ 5
К сожалению, нет простого способа проверить учетные данные пользователей в AD.
С каждым представленным до сих пор способом вы можете получить ложно-отрицательный: пользовательские creds будут действительны, однако AD при возврате false будет возвращать false:
- Пользователь должен сменить пароль при следующем входе в систему.
- Срок действия пароля пользователя истек.
ActiveDirectory не позволит вам использовать LDAP, чтобы определить, недействителен ли пароль из-за того, что пользователь должен сменить пароль или срок их пароля истек.
Чтобы определить изменение пароля или срок действия пароля истек, вы можете вызвать Win32: LogonUser() и проверить код ошибки Windows для следующих 2 констант:
- ERROR_PASSWORD_MUST_CHANGE = 1907
- ERROR_PASSWORD_EXPIRED = 1330
Ответ 6
Вероятно, самым простым способом является PInvoke LogonUser Win32 API.e.g.
Ссылка MSDN здесь...
Определенно хотите использовать тип входа
LOGON32_LOGON_NETWORK (3)
Это создает только легкий токен - идеально подходит для проверок AuthN. (другие типы могут использоваться для создания интерактивных сеансов и т.д.)
Ответ 7
Полное решение .Net - использовать классы из пространства имен System.DirectoryServices. Они позволяют напрямую запрашивать сервер AD. Вот небольшой пример, который бы сделал это:
using (DirectoryEntry entry = new DirectoryEntry())
{
entry.Username = "here goes the username you want to validate";
entry.Password = "here goes the password";
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(objectclass=user)";
try
{
searcher.FindOne();
}
catch (COMException ex)
{
if (ex.ErrorCode == -2147023570)
{
// Login or password is incorrect
}
}
}
// FindOne() didn't throw, the credentials are correct
Этот код напрямую подключается к серверу AD, используя предоставленные учетные данные. Если учетные данные недействительны, искатель .FindOne() выдаст исключение. ErrorCode соответствует ошибке COM недопустимого имени пользователя/пароля.
Вам не нужно запускать код как пользователь AD. Фактически, я успешно использую его для запроса информации на сервере AD, от клиента за пределами домена!
Ответ 8
Еще один вызов .NET для быстрой аутентификации учетных данных LDAP:
using System.DirectoryServices;
using(var DE = new DirectoryEntry(path, username, password)
{
try
{
DE.RefreshCache(); // This will force credentials validation
}
catch (COMException ex)
{
// Validation failed - handle how you want
}
}
Ответ 9
Попробуйте этот код (ПРИМЕЧАНИЕ: Сообщается, что он не работает на сервере Windows 2000)
#region NTLogonUser
#region Direct OS LogonUser Code
[DllImport( "advapi32.dll")]
private static extern bool LogonUser(String lpszUsername,
String lpszDomain, String lpszPassword, int dwLogonType,
int dwLogonProvider, out int phToken);
[DllImport("Kernel32.dll")]
private static extern int GetLastError();
public static bool LogOnXP(String sDomain, String sUser, String sPassword)
{
int token1, ret;
int attmpts = 0;
bool LoggedOn = false;
while (!LoggedOn && attmpts < 2)
{
LoggedOn= LogonUser(sUser, sDomain, sPassword, 3, 0, out token1);
if (LoggedOn) return (true);
else
{
switch (ret = GetLastError())
{
case (126): ;
if (attmpts++ > 2)
throw new LogonException(
"Specified module could not be found. error code: " +
ret.ToString());
break;
case (1314):
throw new LogonException(
"Specified module could not be found. error code: " +
ret.ToString());
case (1326):
// edited out based on comment
// throw new LogonException(
// "Unknown user name or bad password.");
return false;
default:
throw new LogonException(
"Unexpected Logon Failure. Contact Administrator");
}
}
}
return(false);
}
#endregion Direct Logon Code
#endregion NTLogonUser
за исключением того, что вам нужно создать собственное собственное исключение для "LogonException"
Ответ 10
Если вы застряли с .NET 2.0 и управляемым кодом, вот еще один способ, который работает с локальными и доменными учетными записями:
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Diagnostics;
static public bool Validate(string domain, string username, string password)
{
try
{
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo()
{
FileName = "no_matter.xyz",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
LoadUserProfile = true,
Domain = String.IsNullOrEmpty(domain) ? "" : domain,
UserName = username,
Password = Credentials.ToSecureString(password)
};
proc.Start();
proc.WaitForExit();
}
catch (System.ComponentModel.Win32Exception ex)
{
switch (ex.NativeErrorCode)
{
case 1326: return false;
case 2: return true;
default: throw ex;
}
}
catch (Exception ex)
{
throw ex;
}
return false;
}
Ответ 11
Моя простая функция
private bool IsValidActiveDirectoryUser(string activeDirectoryServerDomain, string username, string password)
{
try
{
DirectoryEntry de = new DirectoryEntry("LDAP://" + activeDirectoryServerDomain, username + "@" + activeDirectoryServerDomain, password, AuthenticationTypes.Secure);
DirectorySearcher ds = new DirectorySearcher(de);
ds.FindOne();
return true;
}
catch //(Exception ex)
{
return false;
}
}
Ответ 12
Проверка подлинности Windows может быть выполнена по различным причинам: неправильное имя пользователя или пароль, заблокированная учетная запись, истекший пароль и т.д. Чтобы различать эти ошибки, вызовите функцию API LogonUser через P/Invoke и проверьте код ошибки, если функция возвращает false
:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public static class Win32Authentication
{
private class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle() // called by P/Invoke
: base(true)
{
}
protected override bool ReleaseHandle()
{
return CloseHandle(this.handle);
}
}
private enum LogonType : uint
{
Network = 3, // LOGON32_LOGON_NETWORK
}
private enum LogonProvider : uint
{
WinNT50 = 3, // LOGON32_PROVIDER_WINNT50
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string userName, string domain, string password,
LogonType logonType, LogonProvider logonProvider,
out SafeTokenHandle token);
public static void AuthenticateUser(string userName, string password)
{
string domain = null;
string[] parts = userName.Split('\\');
if (parts.Length == 2)
{
domain = parts[0];
userName = parts[1];
}
SafeTokenHandle token;
if (LogonUser(userName, domain, password, LogonType.Network, LogonProvider.WinNT50, out token))
token.Dispose();
else
throw new Win32Exception(); // calls Marshal.GetLastWin32Error()
}
}
Использование образца:
try
{
Win32Authentication.AuthenticateUser("EXAMPLE\\user", "[email protected]");
// Or: Win32Authentication.AuthenticateUser("[email protected]", "[email protected]");
}
catch (Win32Exception ex)
{
switch (ex.NativeErrorCode)
{
case 1326: // ERROR_LOGON_FAILURE (incorrect user name or password)
// ...
case 1327: // ERROR_ACCOUNT_RESTRICTION
// ...
case 1330: // ERROR_PASSWORD_EXPIRED
// ...
case 1331: // ERROR_ACCOUNT_DISABLED
// ...
case 1907: // ERROR_PASSWORD_MUST_CHANGE
// ...
case 1909: // ERROR_ACCOUNT_LOCKED_OUT
// ...
default: // Other
break;
}
}
Примечание. LogonUser требует отношения доверия с доменом, который вы проверяете.