Example #1
0
 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);
     }
 }
Example #2
0
        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));
        }