This commit is contained in:
@@ -233,6 +233,85 @@ namespace AyaNova.Api.Controllers
|
|||||||
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
|
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
|
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
|
}//eoc
|
||||||
}//eons
|
}//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)
|
private async Task SearchIndexAsync(User obj, bool isNew)
|
||||||
{
|
{
|
||||||
//SEARCH INDEXING
|
//SEARCH INDEXING
|
||||||
|
|||||||
Reference in New Issue
Block a user