Fix #4752: validate the username and email.
This commit is contained in:
parent
7f978c7845
commit
4f74962ce2
|
@ -156,129 +156,130 @@
|
||||||
private List<SiteTemplate> _templates;
|
private List<SiteTemplate> _templates;
|
||||||
private string _template = Constants.DefaultSiteTemplate;
|
private string _template = Constants.DefaultSiteTemplate;
|
||||||
private bool _register = true;
|
private bool _register = true;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private string _loadingDisplay = "display: none;";
|
private string _loadingDisplay = "display: none;";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
// include CSS
|
// include CSS
|
||||||
var content = $"<link rel=\"stylesheet\" href=\"{Constants.BootstrapStylesheetUrl}\" integrity=\"{Constants.BootstrapStylesheetIntegrity}\" crossorigin=\"anonymous\" type=\"text/css\"/>";
|
var content = $"<link rel=\"stylesheet\" href=\"{Constants.BootstrapStylesheetUrl}\" integrity=\"{Constants.BootstrapStylesheetIntegrity}\" crossorigin=\"anonymous\" type=\"text/css\"/>";
|
||||||
SiteState.AppendHeadContent(content);
|
SiteState.AppendHeadContent(content);
|
||||||
|
|
||||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||||
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
_databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
if (_databases.Exists(item => item.IsDefault))
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
{
|
{
|
||||||
_databaseName = _databases.Find(item => item.IsDefault).Name;
|
_databaseName = _databases.Find(item => item.IsDefault).Name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_databaseName = "LocalDB";
|
_databaseName = "LocalDB";
|
||||||
}
|
}
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
|
|
||||||
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
|
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DatabaseChanged(ChangeEventArgs eventArgs)
|
private void DatabaseChanged(ChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_databaseName = (string)eventArgs.Value;
|
_databaseName = (string)eventArgs.Value;
|
||||||
_showConnectionString = false;
|
_showConnectionString = false;
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_message = Localizer["Error.DbConfig.Load"];
|
_message = Localizer["Error.DbConfig.Load"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadDatabaseConfigComponent()
|
private void LoadDatabaseConfigComponent()
|
||||||
{
|
{
|
||||||
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
||||||
if (database != null)
|
if (database != null)
|
||||||
{
|
{
|
||||||
_databaseConfigType = Type.GetType(database.ControlType);
|
_databaseConfigType = Type.GetType(database.ControlType);
|
||||||
DatabaseConfigComponent = builder =>
|
DatabaseConfigComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _databaseConfigType);
|
builder.OpenComponent(0, _databaseConfigType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
// include JavaScript
|
// include JavaScript
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
await interop.IncludeScript("", Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous", "", "head");
|
await interop.IncludeScript("", Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous", "", "head");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Install()
|
private async Task Install()
|
||||||
{
|
{
|
||||||
var connectionString = String.Empty;
|
var connectionString = String.Empty;
|
||||||
if (_showConnectionString)
|
if (_showConnectionString)
|
||||||
{
|
{
|
||||||
connectionString = _connectionString;
|
connectionString = _connectionString;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
{
|
{
|
||||||
connectionString = databaseConfigControl.GetConnectionString();
|
connectionString = databaseConfigControl.GetConnectionString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
|
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
|
||||||
{
|
{
|
||||||
if (await UserService.ValidatePasswordAsync(_hostPassword))
|
var result = await UserService.ValidateUserAsync(_hostUsername, _hostEmail, _hostPassword);
|
||||||
{
|
if (result.Succeeded)
|
||||||
_loadingDisplay = "";
|
{
|
||||||
StateHasChanged();
|
_loadingDisplay = "";
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
Uri uri = new Uri(NavigationManager.Uri);
|
Uri uri = new Uri(NavigationManager.Uri);
|
||||||
|
|
||||||
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
||||||
|
|
||||||
var config = new InstallConfig
|
var config = new InstallConfig
|
||||||
{
|
{
|
||||||
DatabaseType = database.DBType,
|
DatabaseType = database.DBType,
|
||||||
ConnectionString = connectionString,
|
ConnectionString = connectionString,
|
||||||
Aliases = uri.Authority,
|
Aliases = uri.Authority,
|
||||||
HostUsername = _hostUsername,
|
HostUsername = _hostUsername,
|
||||||
HostPassword = _hostPassword,
|
HostPassword = _hostPassword,
|
||||||
HostEmail = _hostEmail,
|
HostEmail = _hostEmail,
|
||||||
HostName = _hostUsername,
|
HostName = _hostUsername,
|
||||||
TenantName = TenantNames.Master,
|
TenantName = TenantNames.Master,
|
||||||
IsNewTenant = true,
|
IsNewTenant = true,
|
||||||
SiteName = Constants.DefaultSite,
|
SiteName = Constants.DefaultSite,
|
||||||
Register = _register,
|
Register = _register,
|
||||||
SiteTemplate = _template,
|
SiteTemplate = _template,
|
||||||
RenderMode = RenderModes.Static,
|
RenderMode = RenderModes.Static,
|
||||||
Runtime = Runtimes.Server
|
Runtime = Runtimes.Server
|
||||||
};
|
};
|
||||||
|
|
||||||
var installation = await InstallationService.Install(config);
|
var installation = await InstallationService.Install(config);
|
||||||
if (installation.Success)
|
if (installation.Success)
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
|
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_message = installation.Message;
|
_message = installation.Message;
|
||||||
_loadingDisplay = "display: none;";
|
_loadingDisplay = "display: none;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_message = Localizer["Message.Password.Invalid"];
|
_message = string.Join("<br />", result.Errors.Select(i => i.Value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -113,6 +113,15 @@ namespace Oqtane.Services
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<User> VerifyTwoFactorAsync(User user, string token);
|
Task<User> VerifyTwoFactorAsync(User user, string token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validate identity user info.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username"></param>
|
||||||
|
/// <param name="email"></param>
|
||||||
|
/// <param name="password"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<UserValidateResult> ValidateUserAsync(string username, string email, string password);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validate a users password against the password policy
|
/// Validate a users password against the password policy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -89,6 +89,11 @@ namespace Oqtane.Services
|
||||||
return await PostJsonAsync<User>($"{Apiurl}/twofactor?token={token}", user);
|
return await PostJsonAsync<User>($"{Apiurl}/twofactor?token={token}", user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserValidateResult> ValidateUserAsync(string username, string email, string password)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<UserValidateResult>($"{Apiurl}/validateuser?username={WebUtility.UrlEncode(username)}&email={WebUtility.UrlEncode(email)}&password={WebUtility.UrlEncode(password)}");
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> ValidatePasswordAsync(string password)
|
public async Task<bool> ValidatePasswordAsync(string password)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<bool>($"{Apiurl}/validate/{WebUtility.UrlEncode(password)}");
|
return await GetJsonAsync<bool>($"{Apiurl}/validate/{WebUtility.UrlEncode(password)}");
|
||||||
|
|
|
@ -347,6 +347,13 @@ namespace Oqtane.Controllers
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/validate/x
|
||||||
|
[HttpGet("validateuser")]
|
||||||
|
public async Task<UserValidateResult> ValidateUser(string username, string email, string password)
|
||||||
|
{
|
||||||
|
return await _userManager.ValidateUser(username, email, password);
|
||||||
|
}
|
||||||
|
|
||||||
// GET api/<controller>/validate/x
|
// GET api/<controller>/validate/x
|
||||||
[HttpGet("validate/{password}")]
|
[HttpGet("validate/{password}")]
|
||||||
public async Task<bool> Validate(string password)
|
public async Task<bool> Validate(string password)
|
||||||
|
|
41
Oqtane.Server/Managers/InstallUserManager.cs
Normal file
41
Oqtane.Server/Managers/InstallUserManager.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Oqtane.Managers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class is only used for user validation during installation process.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUser"></typeparam>
|
||||||
|
internal class InstallUserManager<TUser> : UserManager<IdentityUser>
|
||||||
|
{
|
||||||
|
public InstallUserManager(IUserStore<IdentityUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<IdentityUser> passwordHasher, IEnumerable<IUserValidator<IdentityUser>> userValidators, IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<IdentityUser>> logger) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<IdentityUser> FindByNameAsync(string userName)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<IdentityUser> FindByEmailAsync(string email)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<string> GetUserIdAsync(IdentityUser user)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ namespace Oqtane.Managers
|
||||||
Task<User> ResetPassword(User user, string token);
|
Task<User> ResetPassword(User user, string token);
|
||||||
User VerifyTwoFactor(User user, string token);
|
User VerifyTwoFactor(User user, string token);
|
||||||
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
||||||
|
Task<UserValidateResult> ValidateUser(string username, string email, string password);
|
||||||
Task<bool> ValidatePassword(string password);
|
Task<bool> ValidatePassword(string password);
|
||||||
Task<Dictionary<string, string>> ImportUsers(int siteId, string filePath, bool notify);
|
Task<Dictionary<string, string>> ImportUsers(int siteId, string filePath, bool notify);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,41 @@ namespace Oqtane.Managers
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly IStringLocalizer<UserManager> _localizer;
|
private readonly IStringLocalizer<UserManager> _localizer;
|
||||||
|
private readonly IUserStore<IdentityUser> _identityStore;
|
||||||
|
private readonly Microsoft.Extensions.Options.IOptions<IdentityOptions> _identityOptionsAccessor;
|
||||||
|
private readonly IPasswordHasher<IdentityUser> _passwordHasher;
|
||||||
|
private readonly IEnumerable<IUserValidator<IdentityUser>> _userValidators;
|
||||||
|
private readonly IEnumerable<IPasswordValidator<IdentityUser>> _passwordValidators;
|
||||||
|
private readonly ILookupNormalizer _identityKeyNormalizer;
|
||||||
|
private readonly IdentityErrorDescriber _identityErrors;
|
||||||
|
private readonly IServiceProvider _identityServices;
|
||||||
|
private readonly Microsoft.Extensions.Logging.ILogger<UserManager<IdentityUser>> _identityLogger;
|
||||||
|
|
||||||
public UserManager(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, IProfileRepository profiles, ISettingRepository settings, ISiteRepository sites, ISyncManager syncManager, ILogManager logger, IMemoryCache cache, IStringLocalizer<UserManager> localizer)
|
public UserManager(
|
||||||
|
IUserRepository users,
|
||||||
|
IRoleRepository roles,
|
||||||
|
IUserRoleRepository userRoles,
|
||||||
|
UserManager<IdentityUser> identityUserManager,
|
||||||
|
SignInManager<IdentityUser> identitySignInManager,
|
||||||
|
ITenantManager tenantManager,
|
||||||
|
INotificationRepository notifications,
|
||||||
|
IFolderRepository folders,
|
||||||
|
IProfileRepository profiles,
|
||||||
|
ISettingRepository settings,
|
||||||
|
ISiteRepository sites,
|
||||||
|
ISyncManager syncManager,
|
||||||
|
ILogManager logger,
|
||||||
|
IMemoryCache cache,
|
||||||
|
IStringLocalizer<UserManager> localizer,
|
||||||
|
IUserStore<IdentityUser> store,
|
||||||
|
Microsoft.Extensions.Options.IOptions<IdentityOptions> optionsAccessor,
|
||||||
|
IPasswordHasher<IdentityUser> passwordHasher,
|
||||||
|
IEnumerable<IUserValidator<IdentityUser>> userValidators,
|
||||||
|
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators,
|
||||||
|
ILookupNormalizer keyNormalizer,
|
||||||
|
IdentityErrorDescriber errors,
|
||||||
|
IServiceProvider services,
|
||||||
|
Microsoft.Extensions.Logging.ILogger<UserManager<IdentityUser>> identityLogger)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
_roles = roles;
|
_roles = roles;
|
||||||
|
@ -51,6 +84,15 @@ namespace Oqtane.Managers
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_localizer = localizer;
|
_localizer = localizer;
|
||||||
|
_identityStore = store;
|
||||||
|
_identityOptionsAccessor = optionsAccessor;
|
||||||
|
_passwordHasher = passwordHasher;
|
||||||
|
_userValidators = userValidators;
|
||||||
|
_passwordValidators = passwordValidators;
|
||||||
|
_identityKeyNormalizer = keyNormalizer;
|
||||||
|
_identityErrors = errors;
|
||||||
|
_identityServices = services;
|
||||||
|
_identityLogger = identityLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public User GetUser(int userid, int siteid)
|
public User GetUser(int userid, int siteid)
|
||||||
|
@ -540,6 +582,40 @@ namespace Oqtane.Managers
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserValidateResult> ValidateUser(string username, string email, string password)
|
||||||
|
{
|
||||||
|
var validateResult = new UserValidateResult { Succeeded = true };
|
||||||
|
var installUserManager = new InstallUserManager<IdentityUser>(_identityStore, _identityOptionsAccessor, _passwordHasher, _userValidators, _passwordValidators, _identityKeyNormalizer, _identityErrors, _identityServices, _identityLogger);
|
||||||
|
|
||||||
|
var user = new IdentityUser { UserName = username, Email = email, EmailConfirmed = true };
|
||||||
|
var userValidator = new UserValidator<IdentityUser>();
|
||||||
|
var userResult = await userValidator.ValidateAsync(installUserManager, user);
|
||||||
|
if (!userResult.Succeeded)
|
||||||
|
{
|
||||||
|
validateResult.Succeeded = false;
|
||||||
|
if(userResult.Errors != null)
|
||||||
|
{
|
||||||
|
validateResult.Errors = userResult.Errors?.ToDictionary(i => i.Code, i => i.Description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var passwordValidator = new PasswordValidator<IdentityUser>();
|
||||||
|
var passwordResult = await passwordValidator.ValidateAsync(installUserManager, null, password);
|
||||||
|
if (!passwordResult.Succeeded && !validateResult.Errors.ContainsKey("InvalidPassword"))
|
||||||
|
{
|
||||||
|
validateResult.Succeeded = false;
|
||||||
|
if (passwordResult.Errors != null)
|
||||||
|
{
|
||||||
|
foreach (var error in passwordResult.Errors)
|
||||||
|
{
|
||||||
|
validateResult.Errors.Add(error.Code, error.Description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validateResult;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> ValidatePassword(string password)
|
public async Task<bool> ValidatePassword(string password)
|
||||||
{
|
{
|
||||||
var validator = new PasswordValidator<IdentityUser>();
|
var validator = new PasswordValidator<IdentityUser>();
|
||||||
|
|
15
Oqtane.Shared/Models/UserValidateResult.cs
Normal file
15
Oqtane.Shared/Models/UserValidateResult.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Oqtane.Models
|
||||||
|
{
|
||||||
|
public class UserValidateResult
|
||||||
|
{
|
||||||
|
public bool Succeeded { get; set; }
|
||||||
|
|
||||||
|
public IDictionary<string, string> Errors { get; set; } = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user