Active Directory'ye karşı bir kullanıcı adını ve şifreyi nasıl doğrulayabilirim? Sadece bir kullanıcı adı ve şifrenin doğru olup olmadığını kontrol etmek istiyorum.
Active Directory'ye karşı bir kullanıcı adını ve şifreyi nasıl doğrulayabilirim? Sadece bir kullanıcı adı ve şifrenin doğru olup olmadığını kontrol etmek istiyorum.
Yanıtlar:
.NET 3.5 veya daha yeni bir sürümde çalışıyorsanız, System.DirectoryServices.AccountManagement
ad alanını kullanabilir ve kimlik bilgilerinizi kolayca doğrulayabilirsiniz:
// 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");
}
Basit, güvenilir, sonunda% 100 C # yönetilen kod - daha ne isteyebilirsiniz? :-)
Bununla ilgili her şeyi buradan okuyun:
Güncelleme:
Özetlendiği gibi bu diğer SO soru (ve cevapları) bu çağrı muhtemelen dönen bir sorun yoktur True
bir kullanıcının eski şifreler için. Sadece bu davranışın farkında olun ve bu olursa çok şaşırmayın :-) (bunu işaret ettiği için @MikeGledhill'e teşekkürler!)
UserPrinciple.FindByIdentity
önce iletilen kullanıcı kimliğinin var olup olmadığını görmek için aramak isteyebilirsiniz .
ContextOptions.Negotiate
.
Bunu intranetimizde yapıyoruz
System.DirectoryServices kullanmanız gerekir;
İşte kodun cesaretleri
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();
}
}
}
strPassword
LDAP içinde düz metin olarak saklandığı anlamına mı geliyor ?
Close()
bir using
değişkeni açıkça çağırmaya gerek yoktur .
Burada sunulan birkaç çözüm, yanlış bir kullanıcı / şifre ile değiştirilmesi gereken bir şifre arasında ayrım yapma yeteneğinden yoksundur. Bu şu şekilde yapılabilir:
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);
}
}
}
}
Kullanıcı şifresi yanlışsa veya kullanıcı mevcut değilse, hata
"8009030C: LdapErr: DSID-0C0904DC, yorum: AcceptSecurityContext hatası, veri 52e, v1db1",
kullanıcı şifresinin değiştirilmesi gerekiyorsa,
"8009030C: LdapErr: DSID-0C0904DC, yorum: AcceptSecurityContext hatası, veri 773, v1db1"
lexc.ServerErrorMessage
Veri değeri Win32 hata kodu bir altıgen temsilidir. Bunlar, aksi takdirde Win32 LogonUser API çağrısı çağrılarak döndürülecek aynı hata kodlarıdır. Aşağıdaki liste, onaltılık ve ondalık değerler içeren bir dizi ortak değeri özetler:
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)
System.DirectoryServices
veSystem.DirectoryServices.Protocols
DirectoryServices kullanarak çok basit bir çözüm:
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;
}
hatalı bir kullanıcı / parola algılamak için NativeObject erişimi gerekir
PrincipleContext
. Ancak .NET 3.5 veya daha PrincipleContext
Maalesef kullanıcıların AD kimlik bilgilerini kontrol etmenin "basit" bir yolu yoktur.
Şimdiye kadar sunulan her yöntemle yanlış negatif alabilirsiniz: Bir kullanıcının kredileri geçerli olur, ancak AD belirli koşullar altında false döndürür:
ActiveDirectory, bir kullanıcının parolayı değiştirmesi gerektiğinden veya parolanın süresinin dolup dolmadığından dolayı bir parolanın geçersiz olup olmadığını belirlemek için LDAP kullanmanıza izin vermez.
Parola değişikliğini veya parolanın zaman aşımını belirlemek için Win32: LogonUser () öğesini çağırabilir ve aşağıdaki 2 sabit için windows hata kodunu kontrol edebilirsiniz:
Muhtemelen en kolay yol PInvoke LogonUser Win32 API.eg
MSDN Başvurusu burada ...
Kesinlikle oturum açma türünü kullanmak istiyorum
LOGON32_LOGON_NETWORK (3)
Bu yalnızca hafif bir simge oluşturur - AuthN kontrolleri için mükemmeldir. (etkileşimli oturumlar oluşturmak için diğer türler kullanılabilir)
LogonUser
API olmasını gerektirir işletim sistemi bir parçası olarak çalışma privelage; bu kullanıcıların aldığı bir şey değildir ve kuruluştaki her kullanıcıya vermek istediğiniz bir şey değildir. ( msdn.microsoft.com/en-us/library/aa378184(v=vs.85).aspx )
Tam bir .Net çözümü System.DirectoryServices ad alanından sınıfları kullanmaktır. Bir AD sunucusunu doğrudan sorgulamaya izin verirler. İşte bunu yapacak küçük bir örnek:
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
Bu kod, sağlanan kimlik bilgilerini kullanarak doğrudan AD sunucusuna bağlanır. Kimlik bilgileri geçersizse, searcher.FindOne () bir istisna atar. ErrorCode, "geçersiz kullanıcı adı / şifre" COM hatasına karşılık gelen koddur.
Kodu AD kullanıcısı olarak çalıştırmanız gerekmez. Aslında, başarılı bir şekilde bir AD sunucusu, etki alanı dışındaki bir istemciden bilgi sorgulamak için kullanın!
LDAP kimlik bilgilerini hızlı bir şekilde doğrulamak için başka bir .NET çağrısı:
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
}
}
Bu kodu deneyin (Not: Windows Server 2000 üzerinde çalıştığı bildirildi)
#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
ancak "LogonException" için kendi özel istisnanızı oluşturmanız gerekir
.NET 2.0 ve yönetilen kod ile sıkışıp kalırsanız, yerel ve etki alanı hesaplarıyla çalışan başka bir yol daha vardır:
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;
}
Windows kimlik doğrulaması çeşitli nedenlerle başarısız olabilir: yanlış kullanıcı adı veya parola, kilitli hesap, süresi dolmuş parola ve daha fazlası. Bu hataları birbirinden ayırt etmek için P / Invoke aracılığıyla LogonUser API işlevini çağırın ve işlev döndürürse hata kodunu kontrol edin 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()
}
}
Örnek kullanım:
try
{
Win32Authentication.AuthenticateUser("EXAMPLE\\user", "P@ssw0rd");
// Or: Win32Authentication.AuthenticateUser("user@example.com", "P@ssw0rd");
}
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;
}
}
Not: LogonUser, doğruladığınız alan adıyla bir güven ilişkisi gerektirir.
Basit İşlevim
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;
}
}
Burada referansınız için eksiksiz kimlik doğrulama çözümüm.
İlk olarak, aşağıdaki dört referansı ekleyin
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
using System.DirectoryServices.AccountManagement;
using System.Net;
private void AuthUser() {
try{
string Uid = "USER_NAME";
string Pass = "PASSWORD";
if (Uid == "")
{
MessageBox.Show("Username cannot be null");
}
else if (Pass == "")
{
MessageBox.Show("Password cannot be null");
}
else
{
LdapConnection connection = new LdapConnection("YOUR DOMAIN");
NetworkCredential credential = new NetworkCredential(Uid, Pass);
connection.Credential = credential;
connection.Bind();
// after authenticate Loading user details to data table
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, Uid);
DirectoryEntry up_User = (DirectoryEntry)user.GetUnderlyingObject();
DirectorySearcher deSearch = new DirectorySearcher(up_User);
SearchResultCollection results = deSearch.FindAll();
ResultPropertyCollection rpc = results[0].Properties;
DataTable dt = new DataTable();
DataRow toInsert = dt.NewRow();
dt.Rows.InsertAt(toInsert, 0);
foreach (string rp in rpc.PropertyNames)
{
if (rpc[rp][0].ToString() != "System.Byte[]")
{
dt.Columns.Add(rp.ToString(), typeof(System.String));
foreach (DataRow row in dt.Rows)
{
row[rp.ToString()] = rpc[rp][0].ToString();
}
}
}
//You can load data to grid view and see for reference only
dataGridView1.DataSource = dt;
}
} //Error Handling part
catch (LdapException lexc)
{
String error = lexc.ServerErrorMessage;
string pp = error.Substring(76, 4);
string ppp = pp.Trim();
if ("52e" == ppp)
{
MessageBox.Show("Invalid Username or password, contact ADA Team");
}
if ("775" == ppp)
{
MessageBox.Show("User account locked, contact ADA Team");
}
if ("525" == ppp)
{
MessageBox.Show("User not found, contact ADA Team");
}
if ("530" == ppp)
{
MessageBox.Show("Not permitted to logon at this time, contact ADA Team");
}
if ("531" == ppp)
{
MessageBox.Show("Not permitted to logon at this workstation, contact ADA Team");
}
if ("532" == ppp)
{
MessageBox.Show("Password expired, contact ADA Team");
}
if ("533" == ppp)
{
MessageBox.Show("Account disabled, contact ADA Team");
}
if ("533" == ppp)
{
MessageBox.Show("Account disabled, contact ADA Team");
}
} //common error handling
catch (Exception exc)
{
MessageBox.Show("Invalid Username or password, contact ADA Team");
}
finally {
tbUID.Text = "";
tbPass.Text = "";
}
}