diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor
index 28166ecb..54b53348 100644
--- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor
+++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor
@@ -224,126 +224,133 @@ else
@code {
- private string username = string.Empty;
- private string _password = string.Empty;
- private string _passwordtype = "password";
- private string _togglepassword = string.Empty;
- private string confirm = string.Empty;
- private bool allowtwofactor = false;
- private string twofactor = "False";
- private string email = string.Empty;
- private string displayname = string.Empty;
- private FileManager filemanager;
- private int folderid = -1;
- private int photofileid = -1;
- private File photo = null;
- private List profiles;
- private Dictionary settings;
- private string category = string.Empty;
- private string filter = "to";
- private List notifications;
+ private string username = string.Empty;
+ private string _password = string.Empty;
+ private string _passwordtype = "password";
+ private string _togglepassword = string.Empty;
+ private string confirm = string.Empty;
+ private bool allowtwofactor = false;
+ private string twofactor = "False";
+ private string email = string.Empty;
+ private string displayname = string.Empty;
+ private FileManager filemanager;
+ private int folderid = -1;
+ private int photofileid = -1;
+ private File photo = null;
+ private List profiles;
+ private Dictionary settings;
+ private string category = string.Empty;
+ private string filter = "to";
+ private List notifications;
- public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
+ public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
- protected override async Task OnParametersSetAsync()
- {
- try
- {
- _togglepassword = SharedLocalizer["ShowPassword"];
+ protected override async Task OnParametersSetAsync()
+ {
+ try
+ {
+ _togglepassword = SharedLocalizer["ShowPassword"];
- if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
- {
- allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
- }
+ if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
+ {
+ allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
+ }
- if (PageState.User != null)
- {
- username = PageState.User.Username;
- twofactor = PageState.User.TwoFactorRequired.ToString();
- email = PageState.User.Email;
- displayname = PageState.User.DisplayName;
+ if (PageState.User != null)
+ {
+ username = PageState.User.Username;
+ twofactor = PageState.User.TwoFactorRequired.ToString();
+ email = PageState.User.Email;
+ displayname = PageState.User.DisplayName;
- // get user folder
- var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
- if (folder != null)
- {
- folderid = folder.FolderId;
- }
+ // get user folder
+ var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
+ if (folder != null)
+ {
+ folderid = folder.FolderId;
+ }
- if (PageState.User.PhotoFileId != null)
- {
- photofileid = PageState.User.PhotoFileId.Value;
- photo = await FileService.GetFileAsync(photofileid);
- }
- else
- {
- photofileid = -1;
- photo = null;
- }
+ if (PageState.User.PhotoFileId != null)
+ {
+ photofileid = PageState.User.PhotoFileId.Value;
+ photo = await FileService.GetFileAsync(photofileid);
+ }
+ else
+ {
+ photofileid = -1;
+ photo = null;
+ }
- profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
- settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
+ profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
+ settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
- await LoadNotificationsAsync();
- }
- else
- {
- AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
- }
- }
- catch (Exception ex)
- {
- await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
- AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
- }
- }
+ await LoadNotificationsAsync();
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
+ }
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
+ }
+ }
- private async Task LoadNotificationsAsync()
- {
- notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
- notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
- }
+ private async Task LoadNotificationsAsync()
+ {
+ notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
+ notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
+ }
- private string GetProfileValue(string SettingName, string DefaultValue)
- => SettingService.GetSetting(settings, SettingName, DefaultValue);
+ private string GetProfileValue(string SettingName, string DefaultValue)
+ => SettingService.GetSetting(settings, SettingName, DefaultValue);
- private async Task Save()
- {
- try
- {
- if (username != string.Empty && email != string.Empty && ValidateProfiles())
- {
- if (_password == confirm)
- {
- var user = PageState.User;
- user.Username = username;
- user.Password = _password;
- user.TwoFactorRequired = bool.Parse(twofactor);
- user.Email = email;
- user.DisplayName = (displayname == string.Empty ? username : displayname);
- user.PhotoFileId = filemanager.GetFileId();
- if (user.PhotoFileId == -1)
- {
- user.PhotoFileId = null;
- }
- if (user.PhotoFileId != null)
- {
- photofileid = user.PhotoFileId.Value;
- photo = await FileService.GetFileAsync(photofileid);
- }
- else
- {
- photofileid = -1;
- photo = null;
- }
+ private async Task Save()
+ {
+ try
+ {
+ if (username != string.Empty && email != string.Empty && ValidateProfiles())
+ {
+ if (_password == confirm)
+ {
+ var user = PageState.User;
+ user.Username = username;
+ user.Password = _password;
+ user.TwoFactorRequired = bool.Parse(twofactor);
+ user.Email = email;
+ user.DisplayName = (displayname == string.Empty ? username : displayname);
+ user.PhotoFileId = filemanager.GetFileId();
+ if (user.PhotoFileId == -1)
+ {
+ user.PhotoFileId = null;
+ }
+ if (user.PhotoFileId != null)
+ {
+ photofileid = user.PhotoFileId.Value;
+ photo = await FileService.GetFileAsync(photofileid);
+ }
+ else
+ {
+ photofileid = -1;
+ photo = null;
+ }
- await UserService.UpdateUserAsync(user);
- await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
- await logger.LogInformation("User Profile Saved");
+ user = await UserService.UpdateUserAsync(user);
+ if (user != null)
+ {
+ await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
+ await logger.LogInformation("User Profile Saved");
- AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
- StateHasChanged();
- }
+ AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
+ StateHasChanged();
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
+ }
+ }
else
{
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor
index cb8339c0..6fffed9c 100644
--- a/Oqtane.Client/Modules/Admin/Users/Edit.razor
+++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor
@@ -201,58 +201,64 @@ else
photofileid = -1;
photo = null;
}
- isdeleted = user.IsDeleted.ToString();
+ isdeleted = user.IsDeleted.ToString();
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
lastipaddress = user.LastIPAddress;
settings = await SettingService.GetUserSettingsAsync(user.UserId);
- createdby = user.CreatedBy;
- createdon = user.CreatedOn;
- modifiedby = user.ModifiedBy;
- modifiedon = user.ModifiedOn;
- deletedby = user.DeletedBy;
- deletedon = user.DeletedOn;
- }
- }
- }
- catch (Exception ex)
- {
- await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
- AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
- }
- }
+ createdby = user.CreatedBy;
+ createdon = user.CreatedOn;
+ modifiedby = user.ModifiedBy;
+ modifiedon = user.ModifiedOn;
+ deletedby = user.DeletedBy;
+ deletedon = user.DeletedOn;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
+ AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
+ }
+ }
- private string GetProfileValue(string SettingName, string DefaultValue)
- => SettingService.GetSetting(settings, SettingName, DefaultValue);
+ private string GetProfileValue(string SettingName, string DefaultValue)
+ => SettingService.GetSetting(settings, SettingName, DefaultValue);
- private async Task SaveUser()
- {
- try
- {
- if (username != string.Empty && email != string.Empty && ValidateProfiles())
- {
- if (_password == confirm)
- {
- var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
- user.SiteId = PageState.Site.SiteId;
- user.Username = username;
- user.Password = _password;
- user.Email = email;
- user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
- user.PhotoFileId = null;
- user.PhotoFileId = filemanager.GetFileId();
- if (user.PhotoFileId == -1)
- {
- user.PhotoFileId = null;
- }
+ private async Task SaveUser()
+ {
+ try
+ {
+ if (username != string.Empty && email != string.Empty && ValidateProfiles())
+ {
+ if (_password == confirm)
+ {
+ var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
+ user.SiteId = PageState.Site.SiteId;
+ user.Username = username;
+ user.Password = _password;
+ user.Email = email;
+ user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
+ user.PhotoFileId = null;
+ user.PhotoFileId = filemanager.GetFileId();
+ if (user.PhotoFileId == -1)
+ {
+ user.PhotoFileId = null;
+ }
- user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
+ user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
- user = await UserService.UpdateUserAsync(user);
- await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
- await logger.LogInformation("User Saved {User}", user);
-
- NavigationManager.NavigateTo(NavigateUrl());
+ user = await UserService.UpdateUserAsync(user);
+ if (user != null)
+ {
+ await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
+ await logger.LogInformation("User Saved {User}", user);
+ NavigationManager.NavigateTo(NavigateUrl());
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
+ }
}
else
{
diff --git a/Oqtane.Client/Resources/Installer/Installer.resx b/Oqtane.Client/Resources/Installer/Installer.resx
index fd937839..4d9afff5 100644
--- a/Oqtane.Client/Resources/Installer/Installer.resx
+++ b/Oqtane.Client/Resources/Installer/Installer.resx
@@ -136,7 +136,7 @@
Please Enter All Required Fields. Ensure Passwords Match And Email Address Provided Is Valid.
- The Password Provided Does Not Meet The Password Policy. Please Verify The Minimum Password Length And Complexity Requirements.
+ The Password Provided Does Not Meet The Complexity Policy. Passwords Must Be At Least 6 Characters In Length And Contain Uppercase, Lowercase, Numeric, And Punctuation Characters.
Please Register Me For Major Product Updates And Security Bulletins
diff --git a/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx b/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx
index 2d09bacc..3a9a097b 100644
--- a/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx
@@ -120,6 +120,9 @@
Passwords Entered Do Not Match
+
+ Password Provided Does Not Meet The Complexity Policy
+
From
diff --git a/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx
index 41446826..b0263e50 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx
@@ -120,6 +120,9 @@
Passwords Entered Do Not Match
+
+ Password Provided Does Not Meet The Complexity Policy
+
Identity
diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs
index 0cfdc502..b872a6a2 100644
--- a/Oqtane.Server/Controllers/UserController.cs
+++ b/Oqtane.Server/Controllers/UserController.cs
@@ -247,17 +247,33 @@ namespace Oqtane.Controllers
if (identityuser != null)
{
identityuser.Email = user.Email;
+ var valid = true;
if (user.Password != "")
{
- identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password);
+ var validator = new PasswordValidator();
+ var result = await validator.ValidateAsync(_identityUserManager, null, user.Password);
+ valid = result.Succeeded;
+ if (valid)
+ {
+ identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password);
+ }
+ }
+ if (valid)
+ {
+ await _identityUserManager.UpdateAsync(identityuser);
+
+ user = _users.UpdateUser(user);
+ _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Update);
+ _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Refresh);
+ user.Password = ""; // remove sensitive information
+ _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
+ }
+ else
+ {
+ _logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. Password Does Not Meet Complexity Requirements.", user.Username);
+ user = null;
}
- await _identityUserManager.UpdateAsync(identityuser);
}
- user = _users.UpdateUser(user);
- _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Update);
- _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Refresh);
- user.Password = ""; // remove sensitive information
- _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
}
else
{