This commit is contained in:
@@ -233,6 +233,85 @@ namespace AyaNova.Api.Controllers
|
||||
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Change Password
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <param name="changecreds"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("ChangePassword")]
|
||||
public async Task<IActionResult> ChangePassword([FromBody] AuthController.ChangePasswordParam changecreds)
|
||||
{
|
||||
if (!serverState.IsOpen)
|
||||
{
|
||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int nFailedAuthDelay = 3000;//should be just long enough to make brute force a hassle but short enough to not annoy people who just mistyped their creds to login
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(changecreds.OldPassword) || string.IsNullOrWhiteSpace(changecreds.LoginName))
|
||||
{
|
||||
metrics.Measure.Meter.Mark(MetricsRegistry.FailedLoginMeter);
|
||||
//Make a failed pw wait
|
||||
await Task.Delay(nFailedAuthDelay);
|
||||
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(changecreds.NewPassword))
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, "NewPassword"));
|
||||
}
|
||||
|
||||
if (changecreds.NewPassword != changecreds.ConfirmPassword)
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_INVALID_VALUE, "NewPassword", "NewPassword does not match ConfirmPassword"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Multiple users are allowed the same password and login
|
||||
//Salt will differentiate them so get all users that match login, then try to match pw
|
||||
var users = await ct.User.AsNoTracking().Where(m => m.Login == changecreds.LoginName).ToListAsync();
|
||||
|
||||
foreach (User u in users)
|
||||
{
|
||||
string hashed = Hasher.hash(u.Salt, changecreds.OldPassword);
|
||||
if (hashed == u.Password)
|
||||
{
|
||||
|
||||
//If the user is inactive they may not login
|
||||
if (!u.Active)
|
||||
{
|
||||
//respond like bad creds so as not to leak information
|
||||
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
|
||||
}
|
||||
|
||||
|
||||
//fetch and update user
|
||||
//Instantiate the business object handler
|
||||
UserBiz biz = UserBiz.GetBiz(ct, HttpContext);
|
||||
await biz.ChangePasswordAsync(u.Id, changecreds.NewPassword);
|
||||
|
||||
return NoContent();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//No users matched, it's a failed login
|
||||
//Make a failed pw wait
|
||||
await Task.Delay(nFailedAuthDelay);
|
||||
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
public class CredentialsParam
|
||||
@@ -245,5 +324,19 @@ namespace AyaNova.Api.Controllers
|
||||
}
|
||||
|
||||
|
||||
public class ChangePasswordParam
|
||||
{
|
||||
[System.ComponentModel.DataAnnotations.Required]
|
||||
public string LoginName { get; set; }
|
||||
[System.ComponentModel.DataAnnotations.Required]
|
||||
public string OldPassword { get; set; }
|
||||
[System.ComponentModel.DataAnnotations.Required]
|
||||
public string NewPassword { get; set; }
|
||||
[System.ComponentModel.DataAnnotations.Required]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
}//eoc
|
||||
}//eons
|
||||
@@ -196,6 +196,21 @@ namespace AyaNova.Biz
|
||||
}
|
||||
|
||||
|
||||
|
||||
//put
|
||||
internal async Task<bool> ChangePasswordAsync(long userId, string newPassword)
|
||||
{
|
||||
User dbObj = await ct.User.FirstOrDefaultAsync(m => m.Id == userId);
|
||||
dbObj.Password = Hasher.hash(dbObj.Salt, newPassword);
|
||||
await ct.SaveChangesAsync();
|
||||
|
||||
//Log modification and save context
|
||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private async Task SearchIndexAsync(User obj, bool isNew)
|
||||
{
|
||||
//SEARCH INDEXING
|
||||
|
||||
Reference in New Issue
Block a user