Browse Source

fix(ids): 扩展授权验证器实现也需要记录安全日志.

pull/465/head
cKey 4 years ago
parent
commit
11feeb3f83
  1. 90
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsTokenGrantValidator.cs
  2. 2
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsValidatorConsts.cs
  3. 3
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs
  4. 3
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs
  5. 110
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs

90
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsTokenGrantValidator.cs

@ -3,20 +3,22 @@ using IdentityServer4.Events;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Validation;
using LINGYUN.Abp.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.Security.Claims;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource;
using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
using IIdentityUserRepository = LINGYUN.Abp.Identity.IIdentityUserRepository;
namespace LINGYUN.Abp.IdentityServer.SmsValidator
{
public class SmsTokenGrantValidator : IExtensionGrantValidator
@ -25,6 +27,7 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator
protected IEventService EventService { get; }
protected IIdentityUserRepository UserRepository { get; }
protected UserManager<IdentityUser> UserManager { get; }
protected IdentitySecurityLogManager IdentitySecurityLogManager { get; }
protected IStringLocalizer<IdentityResource> IdentityLocalizer { get; }
protected IStringLocalizer<AbpIdentityServerResource> IdentityServerLocalizer { get; }
@ -32,6 +35,7 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator
IEventService eventService,
UserManager<IdentityUser> userManager,
IIdentityUserRepository userRepository,
IdentitySecurityLogManager identitySecurityLogManager,
IStringLocalizer<IdentityResource> identityLocalizer,
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer,
ILogger<SmsTokenGrantValidator> logger)
@ -40,6 +44,7 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator
EventService = eventService;
UserManager = userManager;
UserRepository = userRepository;
IdentitySecurityLogManager = identitySecurityLogManager;
IdentityLocalizer = identityLocalizer;
IdentityServerLocalizer = identityServerLocalizer;
}
@ -76,6 +81,9 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator
{
Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", currentUser.UserName);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityLocalizer["Volo.Abp.Identity:UserLockedOut"]);
await SaveSecurityLogAsync(context, currentUser, IdentityServerSecurityLogActionConsts.LoginLockedout);
return;
}
@ -97,22 +105,80 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, userAccessFailedError);
await EventService.RaiseAsync(new UserLoginFailureEvent(currentUser.UserName, userAccessFailedError, false));
}
return;
}
var sub = await UserManager.GetUserIdAsync(currentUser);
await SaveSecurityLogAsync(context, currentUser, SmsValidatorConsts.SecurityCodeFailed);
var additionalClaims = new List<Claim>();
if (currentUser.TenantId.HasValue)
{
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString()));
return;
}
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, phoneNumber, null));
context.Result = new GrantValidationResult(sub, OidcConstants.AuthenticationMethods.ConfirmationBySms, additionalClaims.ToArray());
// 登录之后需要更新安全令牌
(await UserManager.UpdateSecurityStampAsync(currentUser)).CheckErrors();
await SetSuccessResultAsync(context, currentUser);
}
protected virtual async Task SetSuccessResultAsync(ExtensionGrantValidationContext context, IdentityUser user)
{
var sub = await UserManager.GetUserIdAsync(user);
Logger.LogInformation("Credentials validated for username: {username}", user.UserName);
var additionalClaims = new List<Claim>();
await AddCustomClaimsAsync(additionalClaims, user, context);
context.Result = new GrantValidationResult(
sub,
OidcConstants.AuthenticationMethods.ConfirmationBySms,
additionalClaims.ToArray()
);
await SaveSecurityLogAsync(
context,
user,
IdentityServerSecurityLogActionConsts.LoginSucceeded);
}
protected virtual async Task SaveSecurityLogAsync(
ExtensionGrantValidationContext context,
IdentityUser user,
string action)
{
var logContext = new IdentitySecurityLogContext
{
Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer,
Action = action,
UserName = user.UserName,
ClientId = await FindClientIdAsync(context)
};
logContext.WithProperty("GrantType", GrantType);
await IdentitySecurityLogManager.SaveAsync(logContext);
}
protected virtual Task<string> FindClientIdAsync(ExtensionGrantValidationContext context)
{
return Task.FromResult(context.Request?.Client?.ClientId);
}
protected virtual Task AddCustomClaimsAsync(
List<Claim> customClaims,
IdentityUser user,
ExtensionGrantValidationContext context)
{
if (user.TenantId.HasValue)
{
customClaims.Add(
new Claim(
AbpClaimTypes.TenantId,
user.TenantId?.ToString()
)
);
}
return Task.CompletedTask;
}
}
}

2
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsValidatorConsts.cs

@ -9,5 +9,7 @@
public const string SmsValidatorTokenName = "phone_verify_code";
public const string SmsValidatorPurpose = "phone_verify";
public const string SecurityCodeFailed = "SecurityCodeFailed";
}
}

3
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs

@ -37,11 +37,12 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.MiniProgram
IWeChatOpenIdFinder weChatOpenIdFinder,
UserManager<IdentityUser> userManager,
IIdentityUserRepository userRepository,
IdentitySecurityLogManager identitySecurityLogManager,
IStringLocalizer<Volo.Abp.Identity.Localization.IdentityResource> identityLocalizer,
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer,
IStringLocalizer<WeChatResource> wechatLocalizer,
AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory)
: base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer)
: base(eventService, weChatOpenIdFinder, userManager, userRepository, identitySecurityLogManager, identityLocalizer, identityServerLocalizer)
{
WeChatLocalizer = wechatLocalizer;
MiniProgramOptionsFactory = miniProgramOptionsFactory;

3
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs

@ -37,11 +37,12 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official
IWeChatOpenIdFinder weChatOpenIdFinder,
UserManager<IdentityUser> userManager,
IIdentityUserRepository userRepository,
IdentitySecurityLogManager identitySecurityLogManager,
IStringLocalizer<Volo.Abp.Identity.Localization.IdentityResource> identityLocalizer,
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer,
IStringLocalizer<WeChatResource> wechatLocalizer,
AbpWeChatOfficialOptionsFactory weChatOfficialOptionsFactory)
: base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer)
: base(eventService, weChatOpenIdFinder, userManager, userRepository, identitySecurityLogManager, identityLocalizer, identityServerLocalizer)
{
WeChatLocalizer = wechatLocalizer;
WeChatOfficialOptionsFactory = weChatOfficialOptionsFactory;

110
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs

@ -1,5 +1,4 @@

using IdentityModel;
using IdentityModel;
using IdentityServer4.Events;
using IdentityServer4.Models;
using IdentityServer4.Services;
@ -19,11 +18,13 @@ using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
using Volo.Abp.Settings;
using Volo.Abp.Uow;
using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
@ -41,6 +42,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
protected IEventService EventService { get; }
protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; }
protected IIdentityUserRepository UserRepository { get; }
protected IdentitySecurityLogManager IdentitySecurityLogManager { get; }
protected UserManager<IdentityUser> UserManager { get; }
protected IStringLocalizer<IdentityResource> IdentityLocalizer { get; }
protected IStringLocalizer<AbpIdentityServerResource> IdentityServerLocalizer { get; }
@ -50,12 +52,14 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
IWeChatOpenIdFinder weChatOpenIdFinder,
UserManager<IdentityUser> userManager,
IIdentityUserRepository userRepository,
IdentitySecurityLogManager identitySecurityLogManager,
IStringLocalizer<IdentityResource> identityLocalizer,
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer)
{
EventService = eventService;
UserManager = userManager;
UserRepository = userRepository;
IdentitySecurityLogManager = identitySecurityLogManager;
WeChatOpenIdFinder = weChatOpenIdFinder;
IdentityLocalizer = identityLocalizer;
IdentityServerLocalizer = identityServerLocalizer;
@ -81,7 +85,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityServerLocalizer["InvalidGrant:GrantTypeInvalid"]);
return;
}
// TODO: 统一命名规范, 微信认证传递的 code 改为 WeChatOpenIdConsts.WeCahtCodeKey
var wechatCode = raw.Get(AbpWeChatGlobalConsts.TokenName);
if (wechatCode.IsNullOrWhiteSpace() || wechatCode.IsNullOrWhiteSpace())
{
@ -94,6 +98,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
var currentUser = await UserManager.FindByLoginAsync(LoginProvider, wechatOpenId.OpenId);
if (currentUser == null)
{
// 检查是否允许自注册
var settingProvider = ServiceProvider.LazyGetRequiredService<ISettingProvider>();
// TODO 检查启用用户注册是否有必要引用账户模块
if (!await settingProvider.IsTrueAsync("Abp.Account.IsSelfRegistrationEnabled") ||
@ -117,37 +122,108 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
AbpWeChatGlobalConsts.DisplayName))).CheckErrors();
}
// 检查是否已锁定
if (await UserManager.IsLockedOutAsync(currentUser))
{
Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", currentUser.UserName);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityLocalizer["Volo.Abp.Identity:UserLockedOut"]);
return;
}
var sub = await UserManager.GetUserIdAsync(currentUser);
await SaveSecurityLogAsync(context, currentUser, wechatOpenId, IdentityServerSecurityLogActionConsts.LoginLockedout);
var additionalClaims = new List<Claim>();
if (currentUser.TenantId.HasValue)
{
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString()));
}
additionalClaims.Add(new Claim(AbpWeChatClaimTypes.OpenId, wechatOpenId.OpenId));
if (!wechatOpenId.UnionId.IsNullOrWhiteSpace())
{
additionalClaims.Add(new Claim(AbpWeChatClaimTypes.UnionId, wechatOpenId.UnionId));
return;
}
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatOpenId.OpenId, null));
context.Result = new GrantValidationResult(sub, AuthenticationMethod, additionalClaims.ToArray());
// 登录之后需要更新安全令牌
(await UserManager.UpdateSecurityStampAsync(currentUser)).CheckErrors();
await SetSuccessResultAsync(context, currentUser, wechatOpenId);
}
protected virtual Task<bool> CheckFeatureAsync(ExtensionGrantValidationContext context)
{
return Task.FromResult(true);
}
protected virtual async Task SetSuccessResultAsync(ExtensionGrantValidationContext context, IdentityUser user, WeChatOpenId wechatOpenId)
{
var sub = await UserManager.GetUserIdAsync(user);
Logger.LogInformation("Credentials validated for username: {username}", user.UserName);
var additionalClaims = new List<Claim>();
await AddCustomClaimsAsync(additionalClaims, user, wechatOpenId, context);
context.Result = new GrantValidationResult(
sub,
AuthenticationMethod,
additionalClaims.ToArray()
);
await SaveSecurityLogAsync(
context,
user,
wechatOpenId,
IdentityServerSecurityLogActionConsts.LoginSucceeded);
}
protected virtual async Task SaveSecurityLogAsync(
ExtensionGrantValidationContext context,
IdentityUser user,
WeChatOpenId wechatOpenId,
string action)
{
var logContext = new IdentitySecurityLogContext
{
Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer,
Action = action,
UserName = user.UserName,
ClientId = await FindClientIdAsync(context)
};
logContext.WithProperty("GrantType", GrantType);
logContext.WithProperty("Provider", LoginProvider);
logContext.WithProperty("Method", AuthenticationMethod);
await IdentitySecurityLogManager.SaveAsync(logContext);
}
protected virtual Task<string> FindClientIdAsync(ExtensionGrantValidationContext context)
{
return Task.FromResult(context.Request?.Client?.ClientId);
}
protected virtual Task AddCustomClaimsAsync(
List<Claim> customClaims,
IdentityUser user,
WeChatOpenId wechatOpenId,
ExtensionGrantValidationContext context)
{
if (user.TenantId.HasValue)
{
customClaims.Add(
new Claim(
AbpClaimTypes.TenantId,
user.TenantId?.ToString()
)
);
}
customClaims.Add(
new Claim(
AbpWeChatClaimTypes.OpenId,
wechatOpenId.OpenId));
if (!wechatOpenId.UnionId.IsNullOrWhiteSpace())
{
customClaims.Add(
new Claim(
AbpWeChatClaimTypes.UnionId,
wechatOpenId.UnionId));
}
return Task.CompletedTask;
}
}
}

Loading…
Cancel
Save