private async Task <UserDetail> AuthenticateUser(string username, string password, string domain, string container, ContextOptions?options, UserDetail authenticatedUser, ActiveDirectoryAuthenticator auth) { try { // validate the credentials return(await auth.Authenticate(username, password, domain, container, cbWithProperties.Checked, options)); } catch (UnableToAuthenticateException ex) { textBoxOutput.AppendText($"{ex.Message} (username: {textBoxUsername.Text}, domain: {domain}){Environment.NewLine}"); return(null); } }
private async void ButtonAuthenticate_Click(object sender, EventArgs e) { textBoxOutput.Clear(); string username = textBoxUsername.Text.Trim(); string password = textBoxPassword.Text.Trim(); string domain = textBoxAdDomain.Text.Trim(); string container = textBoxAdContainer.Text.Trim(); if (domain.Length == 0) { domain = null; } if (container.Length == 0) { container = null; } ContextOptions?options = null; if (cbSsl.Checked) { options = ContextOptions.SecureSocketLayer; } if (cbSimpleBind.Checked) { options = options == null ? ContextOptions.SimpleBind : options | ContextOptions.SimpleBind; } if (cbNegotiate.Checked) { options = options == null ? ContextOptions.Negotiate : options | ContextOptions.Negotiate; } buttonAuthenticate.Enabled = false; labelStatus.Text = "Authenticating..."; UserDetail authenticatedUser = null; var auth = new ActiveDirectoryAuthenticator(); authenticatedUser = await AuthenticateUser(username, password, domain, container, options, authenticatedUser, auth); bool valid = authenticatedUser != null; if (valid == false && string.IsNullOrEmpty(domain) == false) { // Get DC based on domain if specified textBoxOutput.AppendText($"Failed to validate.{Environment.NewLine}Retrying by resolving Domain Controller for domain: {domain}...{Environment.NewLine}"); string server = await auth.GetDomainController(username, password, domain); if (string.IsNullOrEmpty(server) == false) { textBoxOutput.AppendText($"Domain Controller server: {server}{Environment.NewLine}"); // Retry, specifying server as domain authenticatedUser = await AuthenticateUser(username, password, server, container, options, authenticatedUser, auth); valid = authenticatedUser != null; } else { textBoxOutput.AppendText($"Unable to resolve Domain Controller{Environment.NewLine}"); } } string validText = valid ? "User credentials are valid" : "User credentials are not valid or failed to validate"; pictureBoxStatus.Image = valid ? imageList.Images[1] : imageList.Images[2]; textBoxOutput.AppendText($"{Environment.NewLine}{validText}"); if (valid) { textBoxOutput.AppendText($"{Environment.NewLine}{Environment.NewLine}"); if (string.IsNullOrEmpty(authenticatedUser.DomainController) == false) { textBoxOutput.AppendText($"Domain Controller from validated context: {authenticatedUser.DomainController}{Environment.NewLine}"); } textBoxOutput.AppendText($"{Environment.NewLine}"); textBoxOutput.AppendText($"Id: {authenticatedUser.Id}{Environment.NewLine}"); textBoxOutput.AppendText($"Username: {authenticatedUser.Username}{Environment.NewLine}"); textBoxOutput.AppendText($"Name: {authenticatedUser.Name}{Environment.NewLine}"); textBoxOutput.AppendText($"GivenName: {authenticatedUser.GivenName}{Environment.NewLine}"); textBoxOutput.AppendText($"MiddleName: {authenticatedUser.MiddleName}{Environment.NewLine}"); textBoxOutput.AppendText($"Surname: {authenticatedUser.Surname}{Environment.NewLine}"); textBoxOutput.AppendText($"FullName: {authenticatedUser.FullName}{Environment.NewLine}"); textBoxOutput.AppendText($"DistinguishedName: {authenticatedUser.DistinguishedName}{Environment.NewLine}"); textBoxOutput.AppendText($"EmailAddress: {authenticatedUser.Email}{Environment.NewLine}"); textBoxOutput.AppendText($"AccountName: {authenticatedUser.AccountName}{Environment.NewLine}"); textBoxOutput.AppendText($"BadLogonCount: {authenticatedUser.BadLogonCount}{Environment.NewLine}"); if (authenticatedUser.Properties != null) { textBoxOutput.AppendText($"{Environment.NewLine}Properties...{Environment.NewLine}{Environment.NewLine}"); foreach (KeyValuePair <string, string> kv in authenticatedUser.Properties) { textBoxOutput.AppendText($"{kv.Key}: {kv.Value}{Environment.NewLine}"); } } } labelStatus.Text = ""; buttonAuthenticate.Enabled = true; }
/// <summary> /// Authenticate user by username and password /// </summary> /// <param name="username">username or user principle name (domain\username or email format)</param> /// <param name="password">password</param> /// <param name="domain">optional domain</param> /// <param name="container">optional container string</param> /// <param name="withProperties">if true, adds additional properties</param> /// <returns>Authenticated user details or null if not authenticated</returns> /// <exception cref="UnableToAuthenticateException">Thrown if there is an error authenticating</exception> public async Task <UserDetail> Authenticate(string username, string password, string domain = null, string container = null, bool withProperties = false, ContextOptions?options = null) { return(await Task.Run(() => { try { using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain, container)) { // validate the credentials. Uses either method to allow specifying options and default without. bool isValid; if (options.HasValue) { isValid = context.ValidateCredentials(username, password, options.Value); } else { isValid = context.ValidateCredentials(username, password); } if (isValid == false) { return null; } // get user and dump details UserPrincipal foundUser = FindUser(context, username); if (foundUser != null) { string userPrincipalName = foundUser.UserPrincipalName.Trim(); if (string.IsNullOrEmpty(userPrincipalName)) { throw new UnableToAuthenticateException("User has no User Principal Name"); } var authenticatedUser = new UserDetail { // Use Guid for Id if available, otherwise email address Id = foundUser.Guid.HasValue ? foundUser.Guid.ToString() : userPrincipalName.ToLower(), Username = userPrincipalName, Email = string.IsNullOrEmpty(foundUser.EmailAddress) == false ? foundUser.EmailAddress : userPrincipalName, FullName = foundUser.DisplayName, Name = foundUser.Name, GivenName = foundUser.GivenName, MiddleName = foundUser.MiddleName, Surname = foundUser.Surname, Description = foundUser.Description, AccountName = foundUser.SamAccountName, DistinguishedName = foundUser.DistinguishedName, BadLogonCount = foundUser.BadLogonCount, DomainController = context.ConnectedServer }; // Populate underlying properties if (withProperties && foundUser.GetUnderlyingObject() is DirectoryEntry de && de.Properties.Count > 0) { authenticatedUser.Properties = new Dictionary <string, string>(); IDictionaryEnumerator ide = de.Properties.GetEnumerator(); ide.Reset(); while (ide.MoveNext()) { PropertyValueCollection property = ide.Entry.Value as PropertyValueCollection; authenticatedUser.Properties.Add(property.PropertyName.ToString(), property.Value.ToString()); } } return authenticatedUser; } } } catch (COMException ex) { // Sometimes ValidateCredentials doesn't just return false for invalid credentials, it throws a COMException! if ((uint)ex.ErrorCode == E_USERNAME_OR_PASSWORD_INVALID) { return null; } // Something else throw new UnableToAuthenticateException(ex.Message, ex); } catch (PrincipalServerDownException ex) { throw new UnableToAuthenticateException(ex.Message, ex); } catch (UnableToAuthenticateException) { throw; } catch (Exception ex) { throw new UnableToAuthenticateException(ex.Message, ex); } return null; }).ConfigureAwait(false)); }