Fixes issue with AffectedUser vs PerformingUser, updates the log formatting and uses the affectedDetails better, fixes the double event calling for auth stuff, fixes the change password event raising, fixes reporting the changed property values for members

This commit is contained in:
Shannon
2018-02-13 00:15:04 +11:00
parent 3cdd8a0c43
commit c4fa3aa649
14 changed files with 179 additions and 89 deletions

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Auditing
{
var identity = Thread.CurrentPrincipal?.GetUmbracoIdentity();
return identity == null
? new User { Id = 0, Name = "(no user)", Email = "" }
? new User { Id = 0, Name = "SYSTEM", Email = "" }
: _userServiceInstance.GetUserById(Convert.ToInt32(identity.Id));
}
}
@@ -68,6 +68,16 @@ namespace Umbraco.Core.Auditing
MemberService.RemovedRoles += OnRemovedRoles;
}
private string FormatEmail(IMember member)
{
return member == null ? string.Empty : member.Email.IsNullOrWhiteSpace() ? "" : $"<{member.Email}>";
}
private string FormatEmail(IUser user)
{
return user == null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? "" : $"<{user.Email}>";
}
private void OnRemovedRoles(IMemberService sender, RolesEventArgs args)
{
var performingUser = PerformingUser;
@@ -76,10 +86,10 @@ namespace Umbraco.Core.Auditing
foreach (var id in args.MemberIds)
{
members.TryGetValue(id, out var member);
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
0, null,
"umbraco/member/roles/removed", $"modified roles for member id:{id} \"{member?.Name ?? "(unknown)"}\" <{member?.Email ?? ""}>, removed {roles}");
-1, $"Member {id} \"{member?.Name ?? "(unknown)"}\" {FormatEmail(member)}",
"umbraco/member/roles/removed", $"roles modified, removed {roles}");
}
}
@@ -91,10 +101,10 @@ namespace Umbraco.Core.Auditing
foreach (var id in args.MemberIds)
{
members.TryGetValue(id, out var member);
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
0, null,
"umbraco/member/roles/assigned", $"modified roles for member id:{id} \"{member?.Name ?? "(unknown)"}\" <{member?.Email ?? ""}>, assigned {roles}");
-1, $"Member {id} \"{member?.Name ?? "(unknown)"}\" {FormatEmail(member)}",
"umbraco/member/roles/assigned", $"roles modified, assigned {roles}");
}
}
@@ -104,15 +114,18 @@ namespace Umbraco.Core.Auditing
var groups = saveEventArgs.SavedEntities;
foreach (var group in groups)
{
//var dp = string.Join(", ", member.Properties.Where(x => x.WasDirty()).Select(x => x.Alias));
var dp = string.Join(", ", ((UserGroup) group).GetWereDirtyProperties());
var sections = string.Join(", ", group.AllowedSections);
var perms = string.Join(", ", group.Permissions);
var dp = string.Join(", ", ((UserGroup) group).GetPreviouslyDirtyProperties());
var sections = ((UserGroup)group).WasPropertyDirty("AllowedSections")
? string.Join(", ", group.AllowedSections)
: null;
var perms = ((UserGroup)group).WasPropertyDirty("Permissions")
? string.Join(", ", group.Permissions)
: null;
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
0, null,
"umbraco/user-group/save", $"save group id:{group.Id}:{group.Alias} \"{group.Name}\", updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}, sections: {sections}, perms: {perms}");
-1, $"User Group {group.Id} \"{group.Name}\" ({group.Alias})",
"umbraco/user-group/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)};{(sections == null ? "" : $", assigned sections: {sections}")}{(perms == null ? "" : $", assigned perms: {perms}")}");
}
}
@@ -126,10 +139,10 @@ namespace Umbraco.Core.Auditing
var assigned = string.Join(", ", perm.AssignedPermissions);
var entity = _entityServiceInstance.Get(perm.EntityId);
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
0, null,
"umbraco/user-group/permissions-change", $"assign group {(perm.IsDefaultPermissions ? "default " : "")}perms id:{group.Id}:{group.Alias} \"{group.Name}\", assigning {(string.IsNullOrWhiteSpace(assigned) ? "(nothing)" : assigned)} on id:{perm.EntityId} \"{entity.Name}\"");
-1, $"User Group {group.Id} \"{group.Name}\" ({group.Alias})",
"umbraco/user-group/permissions-change", $"assigning {(string.IsNullOrWhiteSpace(assigned) ? "(nothing)" : assigned)} on id:{perm.EntityId} \"{entity.Name}\"");
}
}
@@ -139,13 +152,12 @@ namespace Umbraco.Core.Auditing
var members = saveEventArgs.SavedEntities;
foreach (var member in members)
{
//var dp = string.Join(", ", member.Properties.Where(x => x.WasDirty()).Select(x => x.Alias));
var dp = string.Join(", ", ((Member) member).GetWereDirtyProperties());
var dp = string.Join(", ", ((Member) member).GetPreviouslyDirtyProperties());
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
0, null,
"umbraco/member/save", $"save member id:{member.Id} \"{member.Name}\" <{member.Email}>, updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}");
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
"umbraco/member/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}");
}
}
@@ -155,10 +167,10 @@ namespace Umbraco.Core.Auditing
var members = deleteEventArgs.DeletedEntities;
foreach (var member in members)
{
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
0, null,
"umbraco/member/delete", $"delete member id:{member.Id} \"{member.Name}\" <{member.Email}>");
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
"umbraco/member/delete", $"delete member id:{member.Id} \"{member.Name}\" {FormatEmail(member)}");
}
}
@@ -168,17 +180,16 @@ namespace Umbraco.Core.Auditing
var affectedUsers = saveEventArgs.SavedEntities;
foreach (var affectedUser in affectedUsers)
{
var sections = affectedUser.WasPropertyDirty("AllowedSections")
? string.Join(", ", affectedUser.AllowedSections)
: null;
var groups = affectedUser.WasPropertyDirty("Groups")
? string.Join(", ", affectedUser.Groups.Select(x => x.Alias))
: null;
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
var dp = string.Join(", ", ((User)affectedUser).GetPreviouslyDirtyProperties());
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
affectedUser.Id, $"User \"{affectedUser.Name}\" <{affectedUser.Email}>",
"umbraco/user/save", $"save user{(sections == null ? "" : (", sections: " + sections))}{(groups == null ? "" : (", groups: " + groups))}");
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}{(groups == null ? "" : "; groups assigned: " + groups)}");
}
}
@@ -187,9 +198,9 @@ namespace Umbraco.Core.Auditing
var performingUser = PerformingUser;
var affectedUsers = deleteEventArgs.DeletedEntities;
foreach (var affectedUser in affectedUsers)
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", PerformingIp,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.Now,
affectedUser.Id, $"User \"{affectedUser.Name}\" <{affectedUser.Email}>",
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/delete", "delete user");
}
@@ -199,7 +210,7 @@ namespace Umbraco.Core.Auditing
{
var performingUser = _userServiceInstance.GetUserById(identityArgs.PerformingUser);
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
0, null,
"umbraco/user/sign-in/login", "login success");
@@ -212,7 +223,7 @@ namespace Umbraco.Core.Auditing
{
var performingUser = _userServiceInstance.GetUserById(identityArgs.PerformingUser);
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
0, null,
"umbraco/user/sign-in/logout", "logout success");
@@ -228,9 +239,9 @@ namespace Umbraco.Core.Auditing
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
var affectedUser = _userServiceInstance.GetUserById(identityArgs.AffectedUser);
if (affectedUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.AffectedUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
affectedUser.Id, $"User \"{affectedUser.Name}\" <{affectedUser.Email}>",
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/password/reset", "password reset");
}
}
@@ -244,9 +255,9 @@ namespace Umbraco.Core.Auditing
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
var affectedUser = _userServiceInstance.GetUserById(identityArgs.AffectedUser);
if (affectedUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.AffectedUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
affectedUser.Id, $"User \"{affectedUser.Name}\" <{affectedUser.Email}>",
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/password/change", "password change");
}
}
@@ -258,7 +269,7 @@ namespace Umbraco.Core.Auditing
if (identityArgs.PerformingUser < 0) return;
var performingUser = _userServiceInstance.GetUserById(identityArgs.PerformingUser);
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
0, null,
"umbraco/user/sign-in/failed", "login failed");
@@ -273,9 +284,9 @@ namespace Umbraco.Core.Auditing
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
var affectedUser = _userServiceInstance.GetUserById(identityArgs.AffectedUser);
if (affectedUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.AffectedUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
affectedUser.Id, $"User \"{affectedUser.Name}\" <{affectedUser.Email}>",
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/password/forgot/change", "password forgot/change");
}
}
@@ -289,9 +300,9 @@ namespace Umbraco.Core.Auditing
if (performingUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.PerformingUser}");
var affectedUser = _userServiceInstance.GetUserById(identityArgs.AffectedUser);
if (affectedUser == null) throw new InvalidOperationException($"No user found with id {identityArgs.AffectedUser}");
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" <{performingUser.Email}>", identityArgs.IpAddress,
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", identityArgs.IpAddress,
DateTime.Now,
affectedUser.Id, $"User \"{affectedUser.Name}\" <{affectedUser.Email}>",
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/password/forgot/request", "password forgot/request");
}
}

View File

@@ -46,12 +46,8 @@ namespace Umbraco.Core.Auditing
/// </summary>
public string Username { get; private set; }
/// <summary>
/// Sets the properties on the event being raised, all parameters are optional except for the action being performed
/// </summary>
/// <param name="action">An action based on the AuditEvent enum</param>
/// <param name="ipAddress">The client's IP address. This is usually automatically set but could be overridden if necessary</param>
/// <param name="performingUser">The Id of the user performing the action (if different from the user affected by the action)</param>
[Obsolete("Use the method that has the affectedUser parameter instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public IdentityAuditEventArgs(AuditEvent action, string ipAddress, int performingUser = -1)
{
DateTimeUtc = DateTime.UtcNow;
@@ -65,7 +61,29 @@ namespace Umbraco.Core.Auditing
}
/// <summary>
/// Creates an instance without a performing user (the id will be set to -1)
/// Default constructor
/// </summary>
/// <param name="action"></param>
/// <param name="ipAddress"></param>
/// <param name="comment"></param>
/// <param name="performingUser"></param>
/// <param name="affectedUser"></param>
public IdentityAuditEventArgs(AuditEvent action, string ipAddress, string comment = null, int performingUser = -1, int affectedUser = -1)
{
DateTimeUtc = DateTime.UtcNow;
Action = action;
IpAddress = ipAddress;
Comment = comment;
AffectedUser = affectedUser;
PerformingUser = performingUser == -1
? GetCurrentRequestBackofficeUserId()
: performingUser;
}
/// <summary>
/// Creates an instance without a performing or affected user (the id will be set to -1)
/// </summary>
/// <param name="action"></param>
/// <param name="ipAddress"></param>

View File

@@ -544,6 +544,28 @@ namespace Umbraco.Core.Models
return false;
}
/// <summary>
/// Returns both instance dirty properties and property type properties
/// </summary>
/// <returns></returns>
public override IEnumerable<string> GetDirtyProperties()
{
var instanceProperties = base.GetDirtyProperties();
var propertyTypes = Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
return instanceProperties.Concat(propertyTypes);
}
/// <summary>
/// Returns both instance dirty properties and property type properties
/// </summary>
/// <returns></returns>
internal override IEnumerable<string> GetPreviouslyDirtyProperties()
{
var instanceProperties = base.GetPreviouslyDirtyProperties();
var propertyTypes = Properties.Where(x => x.WasDirty()).Select(x => x.Alias);
return instanceProperties.Concat(propertyTypes);
}
#endregion
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Umbraco.Core.Models.EntityBase
: _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
}
internal virtual IEnumerable<string> GetWereDirtyProperties()
internal virtual IEnumerable<string> GetPreviouslyDirtyProperties()
{
return _lastPropertyChangedInfo == null
? Enumerable.Empty<string>()

View File

@@ -170,7 +170,19 @@ namespace Umbraco.Core.Models
public string RawPasswordValue
{
get { return _rawPasswordValue; }
set { SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, Ps.Value.PasswordSelector); }
set
{
if (value == null)
{
//special case, this is used to ensure that the password is not updated when persisting, in this case
//we don't want to track changes either
_rawPasswordValue = null;
}
else
{
SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, Ps.Value.PasswordSelector);
}
}
}
/// <summary>
@@ -628,4 +640,4 @@ namespace Umbraco.Core.Models
}
}
}
}

View File

@@ -706,5 +706,6 @@ namespace Umbraco.Core.Models.Membership
return _user.GetHashCode();
}
}
}
}
}

View File

@@ -152,4 +152,4 @@ namespace Umbraco.Core.Models.Membership
public int UserCount { get; private set; }
}
}
}

View File

@@ -420,6 +420,33 @@ namespace Umbraco.Core.Security
return await base.CheckPasswordAsync(user, password);
}
public override Task<IdentityResult> ResetPasswordAsync(int userId, string token, string newPassword)
{
var result = base.ResetPasswordAsync(userId, token, newPassword);
if (result.Result.Succeeded)
RaisePasswordResetEvent(userId);
return result;
}
/// <summary>
/// This is a special method that will reset the password but will raise the Password Changed event instead of the reset event
/// </summary>
/// <param name="userId"></param>
/// <param name="token"></param>
/// <param name="newPassword"></param>
/// <returns></returns>
/// <remarks>
/// We use this because in the back office the only way an admin can change another user's password without first knowing their password
/// is to generate a token and reset it, however, when we do this we want to track a password change, not a password reset
/// </remarks>
public Task<IdentityResult> ChangePasswordWithResetAsync(int userId, string token, string newPassword)
{
var result = base.ResetPasswordAsync(userId, token, newPassword);
if (result.Result.Succeeded)
RaisePasswordChangedEvent(userId);
return result;
}
public override Task<IdentityResult> ChangePasswordAsync(int userId, string currentPassword, string newPassword)
{
var result = base.ChangePasswordAsync(userId, currentPassword, newPassword);
@@ -554,27 +581,27 @@ namespace Umbraco.Core.Security
internal void RaiseAccountLockedEvent(int userId)
{
OnAccountLocked(new IdentityAuditEventArgs(AuditEvent.AccountLocked, GetCurrentRequestIpAddress(), userId));
OnAccountLocked(new IdentityAuditEventArgs(AuditEvent.AccountLocked, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseAccountUnlockedEvent(int userId)
{
OnAccountUnlocked(new IdentityAuditEventArgs(AuditEvent.AccountUnlocked, GetCurrentRequestIpAddress(), userId));
OnAccountUnlocked(new IdentityAuditEventArgs(AuditEvent.AccountUnlocked, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseForgotPasswordRequestedEvent(int userId)
{
OnForgotPasswordRequested(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordRequested, GetCurrentRequestIpAddress(), userId));
OnForgotPasswordRequested(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordRequested, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseForgotPasswordChangedSuccessEvent(int userId)
{
OnForgotPasswordChangedSuccess(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordChangedSuccess, GetCurrentRequestIpAddress(), userId));
OnForgotPasswordChangedSuccess(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordChangedSuccess, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseLoginFailedEvent(int userId)
{
OnLoginFailed(new IdentityAuditEventArgs(AuditEvent.LoginFailed, GetCurrentRequestIpAddress(), userId));
OnLoginFailed(new IdentityAuditEventArgs(AuditEvent.LoginFailed, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseInvalidLoginAttemptEvent(string username)
@@ -584,31 +611,33 @@ namespace Umbraco.Core.Security
internal void RaiseLoginRequiresVerificationEvent(int userId)
{
OnLoginRequiresVerification(new IdentityAuditEventArgs(AuditEvent.LoginRequiresVerification, GetCurrentRequestIpAddress(), userId));
OnLoginRequiresVerification(new IdentityAuditEventArgs(AuditEvent.LoginRequiresVerification, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseLoginSuccessEvent(int userId)
{
OnLoginSuccess(new IdentityAuditEventArgs(AuditEvent.LoginSucces, GetCurrentRequestIpAddress(), userId));
OnLoginSuccess(new IdentityAuditEventArgs(AuditEvent.LoginSucces, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseLogoutSuccessEvent(int userId)
{
OnLogoutSuccess(new IdentityAuditEventArgs(AuditEvent.LogoutSuccess, GetCurrentRequestIpAddress(), userId));
OnLogoutSuccess(new IdentityAuditEventArgs(AuditEvent.LogoutSuccess, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaisePasswordChangedEvent(int userId)
{
OnPasswordChanged(new IdentityAuditEventArgs(AuditEvent.PasswordChanged, GetCurrentRequestIpAddress(), userId));
OnPasswordChanged(new IdentityAuditEventArgs(AuditEvent.PasswordChanged, GetCurrentRequestIpAddress(), affectedUser: userId));
}
//TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense.
internal void RaisePasswordResetEvent(int userId)
{
OnPasswordReset(new IdentityAuditEventArgs(AuditEvent.PasswordReset, GetCurrentRequestIpAddress(), userId));
OnPasswordReset(new IdentityAuditEventArgs(AuditEvent.PasswordReset, GetCurrentRequestIpAddress(), affectedUser: userId));
}
internal void RaiseResetAccessFailedCountEvent(int userId)
{
OnResetAccessFailedCount(new IdentityAuditEventArgs(AuditEvent.ResetAccessFailedCount, GetCurrentRequestIpAddress(), userId));
OnResetAccessFailedCount(new IdentityAuditEventArgs(AuditEvent.ResetAccessFailedCount, GetCurrentRequestIpAddress(), affectedUser: userId));
}
public static event EventHandler AccountLocked;

View File

@@ -120,6 +120,10 @@ namespace Umbraco.Core.Services
if (string.IsNullOrWhiteSpace(eventType)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(eventType));
if (string.IsNullOrWhiteSpace(eventDetails)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(eventDetails));
//we need to truncate the data else we'll get SQL errors
affectedDetails = affectedDetails?.Substring(0, Math.Min(affectedDetails.Length, 1024));
eventDetails = eventDetails.Substring(0, Math.Min(eventDetails.Length, 1024));
//validate the eventType - must contain a forward slash, no spaces, no special chars
var eventTypeParts = eventType.ToCharArray();
if (eventTypeParts.Contains('/') == false || eventTypeParts.All(c => char.IsLetterOrDigit(c) || c == '/' || c == '-') == false)

View File

@@ -144,15 +144,12 @@ namespace Umbraco.Web.Editors
{
var userMgr = this.TryGetOwinContext().Result.GetBackOfficeUserManager();
//raise the appropriate event
//raise the reset event
//TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense.
if (data.Reset.HasValue && data.Reset.Value)
{
userMgr.RaisePasswordResetEvent(Security.CurrentUser.Id);
}
else
{
userMgr.RaisePasswordChangedEvent(Security.CurrentUser.Id);
}
//even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword
var result = new ModelWithNotifications<string>(passwordChangeResult.Result.ResetPassword);

View File

@@ -93,7 +93,7 @@ namespace Umbraco.Web.Editors
? userMgr.GeneratePassword()
: passwordModel.NewPassword;
var resetResult = await userMgr.ResetPasswordAsync(savingUser.Id, resetToken, newPass);
var resetResult = await userMgr.ChangePasswordWithResetAsync(savingUser.Id, resetToken, newPass);
if (resetResult.Succeeded == false)
{
@@ -166,6 +166,7 @@ namespace Umbraco.Web.Editors
}
//Are we resetting the password??
//TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense.
if (passwordModel.Reset.HasValue && passwordModel.Reset.Value)
{
var canReset = membershipProvider.CanResetPassword(_userService);
@@ -291,4 +292,4 @@ namespace Umbraco.Web.Editors
}
}
}
}
}

View File

@@ -561,18 +561,10 @@ namespace Umbraco.Web.Editors
{
var passwordChanger = new PasswordChanger(Logger, Services.UserService, UmbracoContext.HttpContext);
//this will change the password and raise appropriate events
var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(Security.CurrentUser, found, userSave.ChangePassword, UserManager);
if (passwordChangeResult.Success)
{
var userMgr = this.TryGetOwinContext().Result.GetBackOfficeUserManager();
//raise the event - NOTE that the ChangePassword.Reset value here doesn't mean it's been 'reset', it means
//it's been changed by a back office user
if (userSave.ChangePassword.Reset.HasValue && userSave.ChangePassword.Reset.Value)
{
userMgr.RaisePasswordChangedEvent(intId.Result);
}
//need to re-get the user
found = Services.UserService.GetUserById(intId.Result);
}
@@ -722,4 +714,4 @@ namespace Umbraco.Web.Editors
}
}
}
}

View File

@@ -39,4 +39,4 @@ namespace Umbraco.Web.Models.Mapping
}
}
}
}

View File

@@ -28,10 +28,13 @@ namespace Umbraco.Web.Models.Mapping
.ConstructUsing((UserGroupSave save) => new UserGroup() { CreateDate = DateTime.Now })
.IgnoreDeletableEntityCommonProperties()
.ForMember(dest => dest.Id, map => map.Condition(source => GetIntId(source.Id) > 0))
.ForMember(dest => dest.Id, map => map.MapFrom(source => GetIntId(source.Id)))
.ForMember(dest => dest.Permissions, map => map.MapFrom(source => source.DefaultPermissions))
.ForMember(dest => dest.Id, map => map.MapFrom(source => GetIntId(source.Id)))
//.ForMember(dest => dest.Permissions, map => map.MapFrom(source => source.DefaultPermissions))
.ForMember(dest => dest.Permissions, map => map.Ignore())
.AfterMap((save, userGroup) =>
{
userGroup.Permissions = save.DefaultPermissions;
userGroup.ClearAllowedSections();
foreach (var section in save.Sections)
{
@@ -466,4 +469,4 @@ namespace Umbraco.Web.Models.Mapping
}
}
}
}