|
|
|
|
@ -101,6 +101,12 @@ public partial class TokenController
|
|
|
|
|
else if (result.IsNotAllowed)
|
|
|
|
|
{
|
|
|
|
|
Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", request.Username);
|
|
|
|
|
|
|
|
|
|
if (user.ShouldChangePasswordOnNextLogin)
|
|
|
|
|
{
|
|
|
|
|
return await HandleShouldChangePasswordOnNextLoginAsync(request, user, request.Password);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errorDescription = "You are not allowed to login! Your account is inactive or needs to confirm your email/phone number.";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
@ -197,8 +203,7 @@ public partial class TokenController
|
|
|
|
|
items: new Dictionary<string, string>
|
|
|
|
|
{
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
|
|
|
|
|
nameof(SignInResult.RequiresTwoFactor),
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = nameof(SignInResult.RequiresTwoFactor)
|
|
|
|
|
},
|
|
|
|
|
parameters: new Dictionary<string, object>
|
|
|
|
|
{
|
|
|
|
|
@ -210,6 +215,82 @@ public partial class TokenController
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<IActionResult> HandleShouldChangePasswordOnNextLoginAsync(OpenIddictRequest request, IdentityUser user, string currentPassword)
|
|
|
|
|
{
|
|
|
|
|
var changePasswordToken = request.GetParameter("ChangePasswordToken")?.ToString();
|
|
|
|
|
var newPassword = request.GetParameter("NewPassword")?.ToString();
|
|
|
|
|
if (!changePasswordToken.IsNullOrWhiteSpace() && !currentPassword.IsNullOrWhiteSpace() && !newPassword.IsNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
if (await UserManager.VerifyUserTokenAsync(user, TokenOptions.DefaultProvider, nameof(IdentityUser.ShouldChangePasswordOnNextLogin), changePasswordToken))
|
|
|
|
|
{
|
|
|
|
|
var changePasswordResult = await UserManager.ChangePasswordAsync(user, currentPassword, newPassword);
|
|
|
|
|
if (changePasswordResult.Succeeded)
|
|
|
|
|
{
|
|
|
|
|
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
|
|
|
|
|
{
|
|
|
|
|
Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict,
|
|
|
|
|
Action = IdentitySecurityLogActionConsts.ChangePassword,
|
|
|
|
|
UserName = request.Username,
|
|
|
|
|
ClientId = request.ClientId
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
user.SetShouldChangePasswordOnNextLogin(false);
|
|
|
|
|
await UserManager.UpdateAsync(user);
|
|
|
|
|
return await SetSuccessResultAsync(request, user);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger.LogInformation("ChangePassword failed for username: {username}, reason: {changePasswordResult}", request.Username, changePasswordResult.Errors.Select(x => x.Description).JoinAsString(", "));
|
|
|
|
|
|
|
|
|
|
var properties = new AuthenticationProperties(new Dictionary<string, string>
|
|
|
|
|
{
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = changePasswordResult.Errors.Select(x => x.Description).JoinAsString(", ")
|
|
|
|
|
});
|
|
|
|
|
return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger.LogInformation("Authentication failed for username: {username}, reason: InvalidAuthenticatorCode", request.Username);
|
|
|
|
|
|
|
|
|
|
var properties = new AuthenticationProperties(new Dictionary<string, string>
|
|
|
|
|
{
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Invalid authenticator code!"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger.LogInformation("Authentication failed for username: {username}, reason: {ShouldChangePasswordOnNextLogin}", request.Username, nameof(user.ShouldChangePasswordOnNextLogin));
|
|
|
|
|
|
|
|
|
|
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
|
|
|
|
|
{
|
|
|
|
|
Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict,
|
|
|
|
|
Action = OpenIddictSecurityLogActionConsts.LoginNotAllowed,
|
|
|
|
|
UserName = request.Username,
|
|
|
|
|
ClientId = request.ClientId
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var properties = new AuthenticationProperties(
|
|
|
|
|
items: new Dictionary<string, string>
|
|
|
|
|
{
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
|
|
|
|
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = nameof(IdentityUser.ShouldChangePasswordOnNextLogin)
|
|
|
|
|
},
|
|
|
|
|
parameters: new Dictionary<string, object>
|
|
|
|
|
{
|
|
|
|
|
["userId"] = user.Id.ToString("N"),
|
|
|
|
|
["changePasswordToken"] = await UserManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, nameof(IdentityUser.ShouldChangePasswordOnNextLogin))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<IActionResult> SetSuccessResultAsync(OpenIddictRequest request, IdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
// Create a new ClaimsPrincipal containing the claims that
|
|
|
|
|
|