Properly validate create user input

This commit is contained in:
nicolas.dorier
2020-03-18 20:51:50 +09:00
parent 132c36df7b
commit 540a31207e
2 changed files with 157 additions and 34 deletions

View File

@@ -1,3 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
@@ -24,16 +25,19 @@ namespace BTCPayServer.Controllers.RestApi.Users
private readonly RoleManager<IdentityRole> _roleManager;
private readonly SettingsRepository _settingsRepository;
private readonly EventAggregator _eventAggregator;
private readonly IPasswordValidator<ApplicationUser> _passwordValidator;
public UsersController(UserManager<ApplicationUser> userManager, BTCPayServerOptions btcPayServerOptions,
RoleManager<IdentityRole> roleManager, SettingsRepository settingsRepository,
EventAggregator eventAggregator)
EventAggregator eventAggregator,
IPasswordValidator<ApplicationUser> passwordValidator)
{
_userManager = userManager;
_btcPayServerOptions = btcPayServerOptions;
_roleManager = roleManager;
_settingsRepository = settingsRepository;
_eventAggregator = eventAggregator;
_passwordValidator = passwordValidator;
}
[Authorize(Policy = Policies.CanModifyProfile.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
@@ -48,6 +52,14 @@ namespace BTCPayServer.Controllers.RestApi.Users
[HttpPost("~/api/v1/users")]
public async Task<ActionResult<ApplicationUserData>> CreateUser(CreateApplicationUserRequest request)
{
if (request?.Email is null)
return BadRequest(CreateValidationProblem(nameof(request.Email), "Email is missing"));
if (!Validation.EmailValidator.IsEmail(request.Email))
{
return BadRequest(CreateValidationProblem(nameof(request.Email), "Invalid email"));
}
if (request?.Password is null)
return BadRequest(CreateValidationProblem(nameof(request.Password), "Password is missing"));
var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>() ?? new PoliciesSettings();
var anyAdmin = (await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any();
var admin = request.IsAdministrator.GetValueOrDefault(!anyAdmin);
@@ -58,10 +70,22 @@ namespace BTCPayServer.Controllers.RestApi.Users
RequiresEmailConfirmation = policies.RequiresConfirmedEmail,
EmailConfirmed = request.EmailConfirmed.GetValueOrDefault(false)
};
var identityResult = await _userManager.CreateAsync(user);
var passwordValidation = await this._passwordValidator.ValidateAsync(_userManager, user, request.Password);
if (!passwordValidation.Succeeded)
{
foreach (var error in passwordValidation.Errors)
{
ModelState.AddModelError(nameof(request.Password), error.Description);
}
return BadRequest(new ValidationProblemDetails(ModelState));
}
var identityResult = await _userManager.CreateAsync(user, request.Password);
if (!identityResult.Succeeded)
{
AddErrors(identityResult);
foreach (var error in identityResult.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return BadRequest(new ValidationProblemDetails(ModelState));
}
else if (admin)
@@ -69,12 +93,17 @@ namespace BTCPayServer.Controllers.RestApi.Users
await _roleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);
}
_eventAggregator.Publish(new UserRegisteredEvent() {Request = Request, User = user, Admin = admin});
return CreatedAtAction("", user);
}
private ValidationProblemDetails CreateValidationProblem(string propertyName, string errorMessage)
{
var modelState = new ModelStateDictionary();
modelState.AddModelError(propertyName, errorMessage);
return new ValidationProblemDetails(modelState);
}
private static ApplicationUserData FromModel(ApplicationUser data)
{
return new ApplicationUserData()
@@ -85,33 +114,5 @@ namespace BTCPayServer.Controllers.RestApi.Users
RequiresEmailConfirmation = data.RequiresEmailConfirmation
};
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
}
[ModelMetadataType(typeof(CreateApplicationUserRequestMetadata))]
public class CreateApplicationUserRequest : BTCPayServer.Client.Models.CreateApplicationUserRequest
{
}
public class CreateApplicationUserRequestMetadata
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
}
}