Saya ingin memvalidasi sekumpulan kredensial terhadap pengontrol domain. misalnya:
Username: STACKOVERFLOW\joel
Password: splotchy
Metode 1. Permintaan Direktori Aktif dengan Peniruan Identitas
Banyak orang menyarankan untuk menanyakan sesuatu di Active Directory. Jika pengecualian dilempar, Anda tahu bahwa kredensial tersebut tidak valid - seperti yang disarankan dalam pertanyaan stackoverflow ini .
Namun ada beberapa kelemahan serius dari pendekatan ini :
Anda tidak hanya mengautentikasi akun domain, tetapi Anda juga melakukan pemeriksaan otorisasi implisit. Artinya, Anda membaca properti dari AD menggunakan token peniruan. Bagaimana jika akun yang valid tidak memiliki hak untuk membaca dari AD? Secara default, semua pengguna memiliki akses baca, tetapi kebijakan domain dapat disetel untuk menonaktifkan izin akses untuk akun (dan atau grup) yang dibatasi.
Mengikat terhadap AD memiliki overhead yang serius, cache skema AD harus dimuat di klien (cache ADSI di penyedia ADSI yang digunakan oleh DirectoryServices). Ini adalah jaringan, dan server AD, memakan sumber daya - dan terlalu mahal untuk operasi sederhana seperti mengautentikasi akun pengguna.
Anda mengandalkan kegagalan pengecualian untuk kasus yang tidak luar biasa, dan menganggap itu berarti nama pengguna dan kata sandi tidak valid. Masalah lain (misalnya kegagalan jaringan, kegagalan konektivitas AD, kesalahan alokasi memori, dll) kemudian disalahartikan sebagai kegagalan otentikasi.
Metode 2. LogonUser Win32 API
Orang lain menyarankan menggunakan LogonUser()
fungsi API. Kedengarannya bagus, tapi sayangnya pengguna yang menelepon terkadang membutuhkan izin yang biasanya hanya diberikan ke sistem operasi itu sendiri:
Proses memanggil LogonUser membutuhkan hak istimewa SE_TCB_NAME. Jika proses panggilan tidak memiliki hak istimewa ini, LogonUser gagal dan GetLastError mengembalikan ERROR_PRIVILEGE_NOT_HELD.
Dalam beberapa kasus, proses yang memanggil LogonUser juga harus mengaktifkan hak istimewa SE_CHANGE_NOTIFY_NAME; jika tidak, LogonUser gagal dan GetLastError mengembalikan ERROR_ACCESS_DENIED. Hak istimewa ini tidak diperlukan untuk akun sistem lokal atau akun yang menjadi anggota grup administrator. Secara default, SE_CHANGE_NOTIFY_NAME diaktifkan untuk semua pengguna, tetapi beberapa administrator dapat menonaktifkannya untuk semua orang.
Membagikan hak istimewa " Bertindak sebagai bagian dari sistem operasi " bukanlah sesuatu yang ingin Anda lakukan mau tak mau - seperti yang ditunjukkan Microsoft dalam artikel basis pengetahuan :
... proses yang memanggil LogonUser harus memiliki hak istimewa SE_TCB_NAME (di Pengelola Pengguna, ini adalah hak " Bertindak sebagai bagian dari Sistem Operasi "). Hak istimewa SE_TCB_NAME sangat kuat dan tidak boleh diberikan kepada sembarang pengguna hanya agar mereka dapat menjalankan aplikasi yang perlu memvalidasi kredensial.
Selain itu, panggilan ke LogonUser()
akan gagal jika kata sandi kosong ditentukan.
Apa cara yang tepat untuk mengautentikasi sekumpulan kredensial domain?
Saya kebetulan menelepon dari kode yang dikelola, tetapi ini adalah pertanyaan umum Windows. Dapat diasumsikan bahwa pelanggan telah menginstal .NETFramework 2.0.
sumber
Jawaban:
C # di .NET 3.5 menggunakan System.DirectoryServices.AccountManagement .
bool valid = false; using (PrincipalContext context = new PrincipalContext(ContextType.Domain)) { valid = context.ValidateCredentials( username, password ); }
Ini akan memvalidasi terhadap domain saat ini. Lihat konstruktor PrincipalContext berparameter untuk opsi lain.
sumber
new PrincipalContext(ContextType.Machine)
.using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security; using System.DirectoryServices.AccountManagement; public struct Credentials { public string Username; public string Password; } public class Domain_Authentication { public Credentials Credentials; public string Domain; public Domain_Authentication(string Username, string Password, string SDomain) { Credentials.Username = Username; Credentials.Password = Password; Domain = SDomain; } public bool IsValid() { using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain)) { // validate the credentials return pc.ValidateCredentials(Credentials.Username, Credentials.Password); } } }
sumber
Domain
parameter saat membuatPrincipalContext
, sesuatu yang saya ingin ketahui dan temukan dalam jawaban ini.Saya menggunakan kode berikut untuk memvalidasi kredensial. Metode yang ditunjukkan di bawah ini akan mengkonfirmasi apakah kredensial benar dan jika tidak apakah kata sandi kedaluwarsa atau perlu diubah.
Saya sudah lama mencari sesuatu seperti ini ... Jadi saya harap ini membantu seseorang!
using System; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; using System.Runtime.InteropServices; namespace User { public static class UserValidation { [DllImport("advapi32.dll", SetLastError = true)] static extern bool LogonUser(string principal, string authority, string password, LogonTypes logonType, LogonProviders logonProvider, out IntPtr token); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr handle); enum LogonProviders : uint { Default = 0, // default for platform (use this!) WinNT35, // sends smoke signals to authority WinNT40, // uses NTLM WinNT50 // negotiates Kerb or NTLM } enum LogonTypes : uint { Interactive = 2, Network = 3, Batch = 4, Service = 5, Unlock = 7, NetworkCleartext = 8, NewCredentials = 9 } public const int ERROR_PASSWORD_MUST_CHANGE = 1907; public const int ERROR_LOGON_FAILURE = 1326; public const int ERROR_ACCOUNT_RESTRICTION = 1327; public const int ERROR_ACCOUNT_DISABLED = 1331; public const int ERROR_INVALID_LOGON_HOURS = 1328; public const int ERROR_NO_LOGON_SERVERS = 1311; public const int ERROR_INVALID_WORKSTATION = 1329; public const int ERROR_ACCOUNT_LOCKED_OUT = 1909; //It gives this error if the account is locked, REGARDLESS OF WHETHER VALID CREDENTIALS WERE PROVIDED!!! public const int ERROR_ACCOUNT_EXPIRED = 1793; public const int ERROR_PASSWORD_EXPIRED = 1330; public static int CheckUserLogon(string username, string password, string domain_fqdn) { int errorCode = 0; using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain_fqdn, "ADMIN_USER", "PASSWORD")) { if (!pc.ValidateCredentials(username, password)) { IntPtr token = new IntPtr(); try { if (!LogonUser(username, domain_fqdn, password, LogonTypes.Network, LogonProviders.Default, out token)) { errorCode = Marshal.GetLastWin32Error(); } } catch (Exception) { throw; } finally { CloseHandle(token); } } } return errorCode; } }
sumber
Berikut cara menentukan pengguna lokal:
public bool IsLocalUser() { return windowsIdentity.AuthenticationType == "NTLM"; }
Diedit oleh Ian Boyd
Anda seharusnya tidak menggunakan NTLM lagi. Ini sangat tua, dan sangat buruk, sehingga Pemverifikasi Aplikasi Microsoft (yang digunakan untuk menangkap kesalahan pemrograman umum) akan memberikan peringatan jika mendeteksi Anda menggunakan NTLM.
Berikut adalah bab dari dokumentasi Pemverifikasi Aplikasi tentang mengapa mereka melakukan pengujian jika seseorang salah menggunakan NTLM:
sumber
using System; using System.Collections.Generic; using System.Text; using System.DirectoryServices.AccountManagement; class WindowsCred { private const string SPLIT_1 = "\\"; public static bool ValidateW(string UserName, string Password) { bool valid = false; string Domain = ""; if (UserName.IndexOf("\\") != -1) { string[] arrT = UserName.Split(SPLIT_1[0]); Domain = arrT[0]; UserName = arrT[1]; } if (Domain.Length == 0) { Domain = System.Environment.MachineName; } using (PrincipalContext context = new PrincipalContext(ContextType.Domain, Domain)) { valid = context.ValidateCredentials(UserName, Password); } return valid; } }
Kashif Mushtaq Ottawa, Kanada
sumber