diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor
index f10c0203..f0a057d0 100644
--- a/Oqtane.Client/Modules/Admin/Login/Index.razor
+++ b/Oqtane.Client/Modules/Admin/Login/Index.razor
@@ -144,7 +144,7 @@ else
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
if (user != null)
{
- await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
+ await logger.LogInformation(LogFunction.Security, "Email Verified For Username {Username}", _username);
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
}
else
diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor
index 549059e4..c6401a47 100644
--- a/Oqtane.Client/Modules/Admin/Users/Edit.razor
+++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor
@@ -18,13 +18,13 @@
-
+
-
+
-
+
+
+
+
+
+
+
@@ -68,7 +77,7 @@
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
-
+
}
-
+
@@ -167,6 +176,7 @@
private string _togglepassword = string.Empty;
private string _confirm = string.Empty;
private string _email = string.Empty;
+ private string _confirmed = string.Empty;
private string _displayname = string.Empty;
private string _timezoneid = string.Empty;
private string _isdeleted;
@@ -204,6 +214,7 @@
{
_username = user.Username;
_email = user.Email;
+ _confirmed = user.EmailConfirmed.ToString();
_displayname = user.DisplayName;
_timezoneid = PageState.User.TimeZoneId;
_isdeleted = user.IsDeleted.ToString();
@@ -255,6 +266,7 @@
user.Username = _username;
user.Password = _password;
user.Email = _email;
+ user.EmailConfirmed = bool.Parse(_confirmed);
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
user.TimeZoneId = _timezoneid;
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
diff --git a/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx
index 0b1a8780..f1fb0c8a 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx
@@ -121,10 +121,10 @@
Forgot Password
- User Account Verified Successfully. You Can Now Login With Your Username And Password Below.
+ User Account Email Address Verified Successfully. You Can Now Login With Your Username And Password.
- User Account Could Not Be Verified. Please Contact Your Administrator For Further Instructions.
+ User Account Email Address Could Not Be Verified. Please Contact Your Administrator For Further Instructions.
User Account Linked Successfully. You Can Now Login With Your External Login Below.
diff --git a/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx
index df4ccc95..ff38ec85 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Users/Edit.resx
@@ -216,4 +216,10 @@
The user's time zone
+
+ Confirmed?
+
+
+ Indicates if the user's email is verified
+
\ No newline at end of file
diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs
index 37648c4f..7789a2d3 100644
--- a/Oqtane.Server/Controllers/UserController.cs
+++ b/Oqtane.Server/Controllers/UserController.cs
@@ -140,6 +140,7 @@ namespace Oqtane.Controllers
filtered.LastLoginOn = user.LastLoginOn;
filtered.LastIPAddress = user.LastIPAddress;
filtered.TwoFactorRequired = user.TwoFactorRequired;
+ filtered.EmailConfirmed = user.EmailConfirmed;
filtered.Roles = user.Roles;
filtered.CreatedBy = user.CreatedBy;
filtered.CreatedOn = user.CreatedOn;
@@ -200,10 +201,15 @@ namespace Oqtane.Controllers
[Authorize]
public async Task Put(int id, [FromBody] User user)
{
- if (ModelState.IsValid && user.SiteId == _tenantManager.GetAlias().SiteId && user.UserId == id && _users.GetUser(user.UserId, false) != null
+ var existing = _userManager.GetUser(user.UserId, user.SiteId);
+ if (ModelState.IsValid && user.SiteId == _tenantManager.GetAlias().SiteId && user.UserId == id && existing != null
&& (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin) || User.Identity.Name == user.Username))
{
- user.EmailConfirmed = User.IsInRole(RoleNames.Admin);
+ // only administrators can update the email confirmation
+ if (!User.IsInRole(RoleNames.Admin))
+ {
+ user.EmailConfirmed = existing.EmailConfirmed;
+ }
user = await _userManager.UpdateUser(user);
}
else
diff --git a/Oqtane.Server/Managers/UserManager.cs b/Oqtane.Server/Managers/UserManager.cs
index 84679d23..5e1e6e64 100644
--- a/Oqtane.Server/Managers/UserManager.cs
+++ b/Oqtane.Server/Managers/UserManager.cs
@@ -65,7 +65,12 @@ namespace Oqtane.Managers
{
user.SiteId = siteid;
user.Roles = GetUserRoles(user.UserId, user.SiteId);
- user.SecurityStamp = _identityUserManager.FindByNameAsync(user.Username).GetAwaiter().GetResult()?.SecurityStamp;
+ var identityuser = _identityUserManager.FindByNameAsync(user.Username).GetAwaiter().GetResult();
+ if (identityuser != null)
+ {
+ user.SecurityStamp = identityuser.SecurityStamp;
+ user.EmailConfirmed = identityuser.EmailConfirmed;
+ }
user.Settings = _settings.GetSettings(EntityNames.User, user.UserId)
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
}
@@ -245,22 +250,30 @@ namespace Oqtane.Managers
{
identityuser.Email = user.Email;
await _identityUserManager.UpdateAsync(identityuser); // security stamp not updated
-
- // if email address changed and it is not confirmed, verification is required for new email address
- if (!user.EmailConfirmed)
- {
- string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
- string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
- string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
- var notification = new Notification(user.SiteId, user, "User Account Verification", body);
- _notifications.AddNotification(notification);
- }
}
if (user.EmailConfirmed)
{
- var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
- await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
+ if (!identityuser.EmailConfirmed)
+ {
+ var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
+ await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
+
+ string body = "Dear " + user.DisplayName + ",\n\nThe Email Address For Your User Account Has Been Verified. You Can Now Login With Your Username And Password.";
+ var notification = new Notification(user.SiteId, user, "User Account Verification", body);
+ _notifications.AddNotification(notification);
+ }
+ }
+ else
+ {
+ identityuser.EmailConfirmed = false;
+ await _identityUserManager.UpdateAsync(identityuser); // security stamp not updated
+
+ string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
+ string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
+ string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
+ var notification = new Notification(user.SiteId, user, "User Account Verification", body);
+ _notifications.AddNotification(notification);
}
user = _users.UpdateUser(user);