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:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,5 +706,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
return _user.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,4 +152,4 @@ namespace Umbraco.Core.Models.Membership
|
||||
|
||||
public int UserCount { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,4 @@ namespace Umbraco.Web.Models.Mapping
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user