diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs index 5d1f6d8414..b1b97c4b91 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs @@ -11,6 +11,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations public Guid? TenantId { get; set; } + public Guid? ImpersonatorUserId { get; set; } + + public Guid? ImpersonatorTenantId { get; set; } + public string UserName { get; set; } public string Name { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index eab7d968a9..c60fdeac93 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -127,6 +127,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations IsAuthenticated = _currentUser.IsAuthenticated, Id = _currentUser.Id, TenantId = _currentUser.TenantId, + ImpersonatorUserId = _currentUser.FindImpersonatorUserId(), + ImpersonatorTenantId = _currentUser.FindImpersonatorTenantId(), UserName = _currentUser.UserName, SurName = _currentUser.SurName, Name = _currentUser.Name, diff --git a/framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs b/framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs index cf2169883c..83a587cc25 100644 --- a/framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs +++ b/framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs @@ -17,10 +17,12 @@ namespace System.Security.Principal { return null; } - if (Guid.TryParse(userIdOrNull.Value, out Guid result)) + + if (Guid.TryParse(userIdOrNull.Value, out Guid guid)) { - return result; + return guid; } + return null; } @@ -36,7 +38,12 @@ namespace System.Security.Principal return null; } - return Guid.Parse(userIdOrNull.Value); + if (Guid.TryParse(userIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; } public static Guid? FindTenantId([NotNull] this ClaimsPrincipal principal) @@ -49,7 +56,12 @@ namespace System.Security.Principal return null; } - return Guid.Parse(tenantIdOrNull.Value); + if (Guid.TryParse(tenantIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; } public static Guid? FindTenantId([NotNull] this IIdentity identity) @@ -64,7 +76,12 @@ namespace System.Security.Principal return null; } - return Guid.Parse(tenantIdOrNull.Value); + if (Guid.TryParse(tenantIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; } public static string FindClientId([NotNull] this ClaimsPrincipal principal) @@ -105,7 +122,12 @@ namespace System.Security.Principal return null; } - return Guid.Parse(editionIdOrNull.Value); + if (Guid.TryParse(editionIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; } public static Guid? FindEditionId([NotNull] this IIdentity identity) @@ -120,7 +142,88 @@ namespace System.Security.Principal return null; } - return Guid.Parse(editionIdOrNull.Value); + if (Guid.TryParse(editionIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; + } + + public static Guid? FindImpersonatorTenantId([NotNull] this ClaimsPrincipal principal) + { + Check.NotNull(principal, nameof(principal)); + + var impersonatorTenantIdOrNull = principal.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.ImpersonatorTenantId); + if (impersonatorTenantIdOrNull == null || impersonatorTenantIdOrNull.Value.IsNullOrWhiteSpace()) + { + return null; + } + + if (Guid.TryParse(impersonatorTenantIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; + } + + public static Guid? FindImpersonatorTenantId([NotNull] this IIdentity identity) + { + Check.NotNull(identity, nameof(identity)); + + var claimsIdentity = identity as ClaimsIdentity; + + var impersonatorTenantIdOrNull = claimsIdentity?.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.ImpersonatorTenantId); + if (impersonatorTenantIdOrNull == null || impersonatorTenantIdOrNull.Value.IsNullOrWhiteSpace()) + { + return null; + } + + if (Guid.TryParse(impersonatorTenantIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; + } + + public static Guid? FindImpersonatorUserId([NotNull] this ClaimsPrincipal principal) + { + Check.NotNull(principal, nameof(principal)); + + var impersonatorUserIdOrNull = principal.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.ImpersonatorUserId); + if (impersonatorUserIdOrNull == null || impersonatorUserIdOrNull.Value.IsNullOrWhiteSpace()) + { + return null; + } + + if (Guid.TryParse(impersonatorUserIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; + } + + public static Guid? FindImpersonatorUserId([NotNull] this IIdentity identity) + { + Check.NotNull(identity, nameof(identity)); + + var claimsIdentity = identity as ClaimsIdentity; + + var impersonatorUserIdOrNull = claimsIdentity?.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.ImpersonatorUserId); + if (impersonatorUserIdOrNull == null || impersonatorUserIdOrNull.Value.IsNullOrWhiteSpace()) + { + return null; + } + + if (Guid.TryParse(impersonatorUserIdOrNull.Value, out var guid)) + { + return guid; + } + + return null; } public static ClaimsIdentity AddIfNotContains(this ClaimsIdentity claimsIdentity, Claim claim) diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs index 271d5d3d94..da87e89946 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs @@ -67,5 +67,15 @@ namespace Volo.Abp.Security.Claims /// Default: "client_id". /// public static string ClientId { get; set; } = "client_id"; + + /// + /// Default: "impersonator_tenantid". + /// + public static string ImpersonatorTenantId { get; set; } = "impersonator_tenantid"; + + /// + /// Default: "impersonator_userid". + /// + public static string ImpersonatorUserId { get; set; } = "impersonator_userid"; } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/CurrentUserExtensions.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/CurrentUserExtensions.cs index 43032fe214..d1d75bf16d 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Users/CurrentUserExtensions.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Users/CurrentUserExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using JetBrains.Annotations; +using Volo.Abp.Security.Claims; namespace Volo.Abp.Users { @@ -30,5 +31,35 @@ namespace Volo.Abp.Users return currentUser.Id.Value; } + + public static Guid? FindImpersonatorTenantId([NotNull] this ICurrentUser currentUser) + { + var impersonatorTenantId = currentUser.FindClaimValue(AbpClaimTypes.ImpersonatorTenantId); + if (impersonatorTenantId == null || impersonatorTenantId.IsNullOrWhiteSpace()) + { + return null; + } + if (Guid.TryParse(impersonatorTenantId, out var guid)) + { + return guid; + } + + return null; + } + + public static Guid? FindImpersonatorUserId([NotNull] this ICurrentUser currentUser) + { + var impersonatorUserId = currentUser.FindClaimValue(AbpClaimTypes.ImpersonatorUserId); + if (impersonatorUserId == null || impersonatorUserId.IsNullOrWhiteSpace()) + { + return null; + } + if (Guid.TryParse(impersonatorUserId, out var guid)) + { + return guid; + } + + return null; + } } -} \ No newline at end of file +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpClaimsService.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpClaimsService.cs index 80c275252c..a977afd2e9 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpClaimsService.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpClaimsService.cs @@ -16,6 +16,8 @@ namespace Volo.Abp.IdentityServer private static readonly string[] AdditionalOptionalClaimNames = { AbpClaimTypes.TenantId, + AbpClaimTypes.ImpersonatorTenantId, + AbpClaimTypes.ImpersonatorUserId, AbpClaimTypes.Name, AbpClaimTypes.SurName, JwtClaimTypes.PreferredUserName, diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs index 55121aec99..f75f10d687 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs @@ -107,8 +107,6 @@ namespace Volo.Abp.IdentityServer identityServerBuilder.AddInMemoryApiResources(configuration.GetSection("IdentityServer:ApiResources")); identityServerBuilder.AddInMemoryIdentityResources(configuration.GetSection("IdentityServer:IdentityResources")); } - - identityServerBuilder.AddExtensionGrantValidator(); } public override void PostConfigureServices(ServiceConfigurationContext context) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/LinkLoginExtensionGrantValidator.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/LinkLoginExtensionGrantValidator.cs deleted file mode 100644 index f7422c6a77..0000000000 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/LinkLoginExtensionGrantValidator.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using System.Threading.Tasks; -using IdentityServer4.Validation; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging; -using Volo.Abp.Identity; -using Volo.Abp.IdentityServer.Localization; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Security.Claims; -using Volo.Abp.Users; -using IdentityUser = Volo.Abp.Identity.IdentityUser; - -namespace Volo.Abp.IdentityServer.AspNetIdentity -{ - public class LinkLoginExtensionGrantValidator : IExtensionGrantValidator - { - public const string ExtensionGrantType = "LinkLogin"; - - public string GrantType => ExtensionGrantType; - - protected ITokenValidator TokenValidator { get; } - protected IdentityLinkUserManager IdentityLinkUserManager { get; } - protected ICurrentTenant CurrentTenant { get; } - protected ICurrentUser CurrentUser { get; } - protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; } - protected IdentityUserManager UserManager { get; } - protected IdentitySecurityLogManager IdentitySecurityLogManager { get; } - protected ILogger Logger { get; } - protected IStringLocalizer Localizer { get; } - - public LinkLoginExtensionGrantValidator( - ITokenValidator tokenValidator, - IdentityLinkUserManager identityLinkUserManager, - ICurrentTenant currentTenant, - ICurrentUser currentUser, - IdentityUserManager userManager, - ICurrentPrincipalAccessor currentPrincipalAccessor, - IdentitySecurityLogManager identitySecurityLogManager, - ILogger logger, - IStringLocalizer localizer) - { - TokenValidator = tokenValidator; - IdentityLinkUserManager = identityLinkUserManager; - CurrentTenant = currentTenant; - CurrentUser = currentUser; - UserManager = userManager; - CurrentPrincipalAccessor = currentPrincipalAccessor; - IdentitySecurityLogManager = identitySecurityLogManager; - Logger = logger; - Localizer = localizer; - } - - public virtual async Task ValidateAsync(ExtensionGrantValidationContext context) - { - var accessToken = context.Request.Raw["access_token"]; - if (accessToken.IsNullOrWhiteSpace()) - { - context.Result = new GrantValidationResult - { - IsError = true, - Error = "invalid_access_token" - }; - return; - } - - var result = await TokenValidator.ValidateAccessTokenAsync(accessToken); - if (result.IsError) - { - context.Result = new GrantValidationResult - { - IsError = true, - Error = result.Error, - ErrorDescription = result.ErrorDescription - }; - return; - } - - using (CurrentPrincipalAccessor.Change(result.Claims)) - { - if (!Guid.TryParse(context.Request.Raw["LinkUserId"], out var linkUserId)) - { - context.Result = new GrantValidationResult - { - IsError = true, - Error = "invalid_link_user_id" - }; - return; - } - - Guid? linkTenantId = null; - if (!context.Request.Raw["LinkTenantId"].IsNullOrWhiteSpace()) - { - if (!Guid.TryParse(context.Request.Raw["LinkTenantId"], out var parsedGuid)) - { - context.Result = new GrantValidationResult - { - IsError = true, - Error = "invalid_link_tenant_id" - }; - return; - } - - linkTenantId = parsedGuid; - } - - var isLinked = await IdentityLinkUserManager.IsLinkedAsync( - new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), - new IdentityLinkUserInfo(linkUserId, linkTenantId), - true); - - if (isLinked) - { - using (CurrentTenant.Change(linkTenantId)) - { - var user = await UserManager.GetByIdAsync(linkUserId); - var sub = await UserManager.GetUserIdAsync(user); - - var additionalClaims = new List(); - await AddCustomClaimsAsync(additionalClaims, user, context); - - context.Result = new GrantValidationResult( - sub, - GrantType, - additionalClaims.ToArray() - ); - } - } - else - { - context.Result = new GrantValidationResult - { - IsError = true, - Error = Localizer["TheTargetUserIsNotLinkedToYou"] - }; - } - } - } - - protected virtual Task AddCustomClaimsAsync(List customClaims, IdentityUser user, ExtensionGrantValidationContext context) - { - if (user.TenantId.HasValue) - { - customClaims.Add(new Claim(AbpClaimTypes.TenantId, user.TenantId?.ToString())); - } - - return Task.CompletedTask; - } - } -}