193 lines
6.7 KiB
C#
193 lines
6.7 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using IdentityServer4.Events;
|
|
using IdentityServer4.Models;
|
|
using IdentityServer4.Services;
|
|
using IdentityServer4.Validation;
|
|
using Microsoft.Extensions.Logging;
|
|
using xCommons.Extensions;
|
|
using xExceptions.Constants;
|
|
using xIdentityModels.Navigations;
|
|
using xIds.Interfaces;
|
|
using static IdentityModel.OidcConstants;
|
|
|
|
namespace xIds.Validators
|
|
{
|
|
public class XResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
|
|
{
|
|
private readonly IXIdentityManager identityManager;
|
|
private readonly IEventService events;
|
|
private readonly ILogger<XResourceOwnerPasswordValidator> logger;
|
|
|
|
public XResourceOwnerPasswordValidator(
|
|
IXIdentityManager identityProvider,
|
|
IEventService events,
|
|
ILogger<XResourceOwnerPasswordValidator> logger
|
|
)
|
|
{
|
|
this.identityManager = identityProvider;
|
|
this.events = events;
|
|
this.logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates the resource owner password credential
|
|
/// by providing UserName/Email or PhoneNumber
|
|
/// </summary>
|
|
/// <param name="context">The context.</param>
|
|
/// <returns></returns>
|
|
public virtual async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
|
|
{
|
|
//
|
|
var clientId = context.Request?.Client?.ClientId;
|
|
var xUser = await identityManager.GetUserAsync(context.UserName, true);
|
|
|
|
//
|
|
// Check Force Data ...
|
|
var isForced = true;
|
|
var isForcedStr = context.Request?.Raw["force"];
|
|
if (!isForcedStr.IsNullOrEmpty())
|
|
{
|
|
isForced = isForcedStr.FromJSON<bool>();
|
|
}
|
|
|
|
//
|
|
XDevice device = null;
|
|
var language = context.Request?.Raw["language"];
|
|
var deviceStr = context.Request?.Raw["device"];
|
|
if (deviceStr.IsNullOrEmpty() && isForced)
|
|
{
|
|
//
|
|
logger.LogError($"Device not Found ...");
|
|
|
|
//
|
|
await events
|
|
.RaiseAsync(
|
|
new UserLoginFailureEvent(
|
|
xUser.UserName,
|
|
XException.InvalidDevice.ToXError().Message,
|
|
false,
|
|
clientId
|
|
));
|
|
return;
|
|
}
|
|
device = isForced ? deviceStr.FromJSON<XDevice>() : null;
|
|
|
|
//
|
|
XException exception;
|
|
if (!xUser.IsNull())
|
|
{
|
|
//
|
|
var result = await identityManager
|
|
.CheckPasswordSignInAsync(
|
|
xUser,
|
|
context.Password,
|
|
device,
|
|
language,
|
|
true,
|
|
isForced
|
|
);
|
|
if (result.Succeeded)
|
|
{
|
|
//
|
|
logger.LogInformation("Credentials validated for username: {username}", xUser.UserName);
|
|
|
|
//
|
|
// Update User Last Login ...
|
|
xUser.LastLogin = DateTime.UtcNow;
|
|
await identityManager.UpdateUserAsync(xUser);
|
|
|
|
//
|
|
await events.RaiseAsync(
|
|
new UserLoginSuccessEvent(
|
|
xUser.UserName, xUser.Id, xUser.UserName, false, clientId
|
|
));
|
|
|
|
//
|
|
context.Result = new GrantValidationResult(xUser.Id, AuthenticationMethods.Password);
|
|
return;
|
|
}
|
|
else if (result.IsLockedOut)
|
|
{
|
|
//
|
|
logger.LogInformation("Authentication failed for username: {username}, reason: locked out", xUser.UserName);
|
|
|
|
//
|
|
exception = XException.AccountLockedOut;
|
|
await events
|
|
.RaiseAsync(
|
|
new UserLoginFailureEvent(
|
|
xUser.UserName,
|
|
exception.ToXError().Message,
|
|
false,
|
|
clientId
|
|
));
|
|
}
|
|
else if (result.IsNotAllowed)
|
|
{
|
|
//
|
|
logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", xUser.UserName);
|
|
|
|
//
|
|
exception = XException.NotAllowed;
|
|
await events
|
|
.RaiseAsync(
|
|
new UserLoginFailureEvent(
|
|
xUser.UserName,
|
|
exception.ToXError().Message,
|
|
false,
|
|
clientId
|
|
));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", xUser.UserName);
|
|
|
|
//
|
|
exception = XException.LoginFailed;
|
|
await events
|
|
.RaiseAsync(
|
|
new UserLoginFailureEvent(
|
|
xUser.UserName,
|
|
exception.ToXError().Message,
|
|
false,
|
|
clientId
|
|
));
|
|
|
|
//
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
logger.LogInformation("No user found matching username: {username}", xUser.UserName);
|
|
|
|
//
|
|
exception = XException.InvalidUserName;
|
|
await events
|
|
.RaiseAsync(
|
|
new UserLoginFailureEvent(
|
|
xUser.UserName,
|
|
exception.ToXError().Message,
|
|
false,
|
|
clientId
|
|
));
|
|
}
|
|
|
|
//
|
|
Exception ecs = exception.ToException();
|
|
if (exception == XException.AccountLockedOut && xUser.LockoutEnd.HasValue)
|
|
{
|
|
//
|
|
var passedTime = xUser.LockoutEnd.Value.UtcDateTime;
|
|
ecs = XException.AccountLockedOut
|
|
.AddContentToException(passedTime.ToString());
|
|
}
|
|
|
|
//
|
|
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, ecs.Message);
|
|
}
|
|
}
|
|
} |