/// <summary> /// Change user password /// </summary> public bool ChangePassword(string userName, string currentPassword, string newPassword, out string errorReason) { var identity = LdapIdentity.ParseUser(userName); errorReason = null; try { LdapProfile userProfile; using (var connection = new LdapConnection(_configuration.Domain)) { connection.Credential = new NetworkCredential(identity.Name, currentPassword); connection.Bind(); var domain = LdapIdentity.FqdnToDn(_configuration.Domain); var isProfileLoaded = LoadProfile(connection, domain, identity, out var profile); if (!isProfileLoaded) { errorReason = Resources.AD.UnableToChangePassword; return(false); } userProfile = profile; } _logger.Debug($"Changing password for user '{identity.Name}' in {userProfile.BaseDn.DnToFqdn()}"); using (var ctx = new PrincipalContext(ContextType.Domain, userProfile.BaseDn.DnToFqdn(), null, ContextOptions.Negotiate, identity.Name, currentPassword)) { using (var user = UserPrincipal.FindByIdentity(ctx, IdentityType.DistinguishedName, userProfile.DistinguishedName)) { user.ChangePassword(currentPassword, newPassword); user.Save(); } } _logger.Debug($"Password changed for user '{identity.Name}'"); return(true); } catch (PasswordException pex) { _logger.Warning($"Changing password for user '{identity.Name}' failed: {pex.Message}, {pex.HResult}"); errorReason = Resources.AD.PasswordDoesNotMeetRequirements; } catch (Exception ex) { _logger.Warning($"Changing password for user {identity.Name} failed: {ex.Message}"); errorReason = Resources.AD.UnableToChangePassword; } return(false); }
/// <summary> /// Verify User Name, Password, User Status and Policy against Active Directory /// </summary> public ActiveDirectoryCredentialValidationResult VerifyCredential(string userName, string password) { if (string.IsNullOrEmpty(userName)) { throw new ArgumentNullException(nameof(userName)); } if (string.IsNullOrEmpty(password)) { _logger.Error($"Empty password provided for user '{userName}'"); return(ActiveDirectoryCredentialValidationResult.UnknowError("Invalid credentials")); } var user = LdapIdentity.ParseUser(userName); try { _logger.Debug($"Verifying user '{user.Name}' credential and status at {_configuration.Domain}"); using (var connection = new LdapConnection(_configuration.Domain)) { connection.Credential = new NetworkCredential(user.Name, password); connection.Bind(); _logger.Information($"User '{user.Name}' credential and status verified successfully at {_configuration.Domain}"); var domain = LdapIdentity.FqdnToDn(_configuration.Domain); var isProfileLoaded = LoadProfile(connection, domain, user, out var profile); if (!isProfileLoaded) { return(ActiveDirectoryCredentialValidationResult.UnknowError("Unable to load profile")); } var checkGroupMembership = !string.IsNullOrEmpty(_configuration.ActiveDirectory2FaGroup); if (checkGroupMembership) { var isMemberOf = IsMemberOf(connection, profile.BaseDn, user, _configuration.ActiveDirectory2FaGroup); if (!isMemberOf) { _logger.Information($"User '{user.Name}' is NOT member of {_configuration.ActiveDirectory2FaGroup} group"); _logger.Information($"Bypass second factor for user '{user.Name}'"); return(ActiveDirectoryCredentialValidationResult.ByPass()); } _logger.Information($"User '{user.Name}' is member of {_configuration.ActiveDirectory2FaGroup} group"); } var result = ActiveDirectoryCredentialValidationResult.Ok(); result.DisplayName = profile.DisplayName; result.Email = profile.Email; if (_configuration.UseActiveDirectoryUserPhone) { result.Phone = profile.Phone; } if (_configuration.UseActiveDirectoryMobileUserPhone) { result.Phone = profile.Mobile; } return(result); } } catch (LdapException lex) { var result = ActiveDirectoryCredentialValidationResult.KnownError(lex.ServerErrorMessage); _logger.Warning($"Verification user '{user.Name}' at {_configuration.Domain} failed: {result.Reason}"); return(result); } catch (Exception ex) { _logger.Error(ex, $"Verification user '{user.Name}' at {_configuration.Domain} failed."); return(ActiveDirectoryCredentialValidationResult.UnknowError()); } }
private IDictionary <string, LdapIdentity> LoadForestSchema(LdapConnection connection, LdapIdentity root) { _logger.Debug($"Loading forest schema from {root.Name}"); try { var domainNameSuffixes = new Dictionary <string, LdapIdentity>(); var trustedDomainsResult = Query(connection, "CN=System," + root.Name, "objectClass=trustedDomain", SearchScope.OneLevel, "cn"); var schema = new List <LdapIdentity> { root }; for (var i = 0; i < trustedDomainsResult.Entries.Count; i++) { var entry = trustedDomainsResult.Entries[i]; var attribute = entry.Attributes["cn"]; if (attribute != null) { var trustPartner = LdapIdentity.FqdnToDn(attribute[0].ToString()); _logger.Debug($"Found trusted domain {trustPartner.Name}"); if (!trustPartner.IsChildOf(root)) { schema.Add(trustPartner); } } } foreach (var domain in schema) { var domainSuffix = domain.DnToFqdn(); if (!domainNameSuffixes.ContainsKey(domainSuffix)) { domainNameSuffixes.Add(domainSuffix, domain); } try { var uPNSuffixesResult = Query(connection, "CN=Partitions,CN=Configuration," + domain.Name, "objectClass=*", SearchScope.Base, "uPNSuffixes"); for (var i = 0; i < uPNSuffixesResult.Entries.Count; i++) { var entry = uPNSuffixesResult.Entries[i]; var attribute = entry.Attributes["uPNSuffixes"]; if (attribute != null) { for (var j = 0; j < attribute.Count; j++) { var suffix = attribute[j].ToString(); if (!domainNameSuffixes.ContainsKey(suffix)) { domainNameSuffixes.Add(suffix, domain); _logger.Debug($"Found alternative UPN suffix {suffix} for domain {domain.Name}"); } } } } } catch (Exception ex) { _logger.Warning($"Unable to query {domain.Name}: {ex.Message}"); } } return(domainNameSuffixes); } catch (Exception ex) { _logger.Error(ex, "Unable to load forest schema"); return(null); } }