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 f4e4bba1a0..cf2169883c 100644 --- a/framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs +++ b/framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs @@ -122,5 +122,44 @@ namespace System.Security.Principal return Guid.Parse(editionIdOrNull.Value); } + + public static ClaimsIdentity AddIfNotContains(this ClaimsIdentity claimsIdentity, Claim claim) + { + Check.NotNull(claimsIdentity, nameof(claimsIdentity)); + + if (!claimsIdentity.Claims.Any(x => string.Equals(x.Type, claim.Type, StringComparison.OrdinalIgnoreCase))) + { + claimsIdentity.AddClaim(claim); + } + + return claimsIdentity; + } + + public static ClaimsIdentity AddOrReplace(this ClaimsIdentity claimsIdentity, Claim claim) + { + Check.NotNull(claimsIdentity, nameof(claimsIdentity)); + + foreach (var x in claimsIdentity.FindAll(claim.Type).ToList()) + { + claimsIdentity.RemoveClaim(x); + } + + claimsIdentity.AddClaim(claim); + + return claimsIdentity; + } + + public static ClaimsPrincipal AddIdentityIfNotContains([NotNull] this ClaimsPrincipal principal, ClaimsIdentity identity) + { + Check.NotNull(principal, nameof(principal)); + + if (!principal.Identities.Any(x => string.Equals(x.AuthenticationType, identity.AuthenticationType, StringComparison.OrdinalIgnoreCase))) + { + principal.AddIdentity(identity); + } + + return principal; + } + } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory.cs index b00b38ea8c..899d71de04 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory.cs @@ -8,6 +8,8 @@ namespace Volo.Abp.Security.Claims { public class AbpClaimsPrincipalFactory : IAbpClaimsPrincipalFactory, ITransientDependency { + public static string AuthenticationType => "Abp.Application"; + protected IServiceScopeFactory ServiceScopeFactory { get; } protected AbpClaimsPrincipalFactoryOptions Options { get; } @@ -19,11 +21,14 @@ namespace Volo.Abp.Security.Claims Options = abpClaimOptions.Value; } - public virtual async Task CreateAsync() + public virtual async Task CreateAsync(ClaimsPrincipal existsClaimsPrincipal = null) { using (var scope = ServiceScopeFactory.CreateScope()) { - var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity()); + var claimsPrincipal = existsClaimsPrincipal ?? new ClaimsPrincipal(new ClaimsIdentity( + AuthenticationType, + AbpClaimTypes.UserName, + AbpClaimTypes.Role)); var context = new AbpClaimsPrincipalContributorContext(claimsPrincipal, scope.ServiceProvider); diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ClaimsIdentityExtensions.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ClaimsIdentityExtensions.cs deleted file mode 100644 index bf8bb26784..0000000000 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ClaimsIdentityExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Linq; -using System.Security.Claims; - -namespace Volo.Abp.Security.Claims -{ - public static class ClaimsIdentityExtensions - { - public static ClaimsIdentity AddIfNotContains(this ClaimsIdentity claimsIdentity, Claim claim) - { - if (!claimsIdentity.Claims.Any(existClaim => - existClaim != null && - string.Equals(existClaim.Type, claim.Type, StringComparison.OrdinalIgnoreCase))) - { - claimsIdentity.AddClaim(claim); - } - - return claimsIdentity; - } - } -} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpClaimsPrincipalFactory.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpClaimsPrincipalFactory.cs index 1de0afbcab..d1eb22afc0 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpClaimsPrincipalFactory.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpClaimsPrincipalFactory.cs @@ -5,6 +5,6 @@ namespace Volo.Abp.Security.Claims { public interface IAbpClaimsPrincipalFactory { - Task CreateAsync(); + Task CreateAsync(ClaimsPrincipal existsClaimsPrincipal = null); } } diff --git a/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj b/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj index 925c0e5b88..e367a6dc56 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj +++ b/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj @@ -8,6 +8,7 @@ + diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs index a1ce5c56aa..506aeba018 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs @@ -1,11 +1,13 @@ -using Volo.Abp.Modularity; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; using Volo.Abp.SecurityLog; namespace Volo.Abp.Security { [DependsOn( typeof(AbpSecurityModule), - typeof(AbpTestBaseModule) + typeof(AbpTestBaseModule), + typeof(AbpAutofacModule) )] public class AbpSecurityTestModule : AbpModule { diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Test.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Test.cs new file mode 100644 index 0000000000..4cdcbe620b --- /dev/null +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Test.cs @@ -0,0 +1,104 @@ +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Security.Claims +{ + public class AbpClaimsPrincipalFactory_Test : AbpIntegratedTest + { + private readonly IAbpClaimsPrincipalFactory _abpClaimsPrincipalFactory; + private static string TestAuthenticationType => "Identity.Application"; + + public AbpClaimsPrincipalFactory_Test() + { + _abpClaimsPrincipalFactory = GetRequiredService(); + + } + + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + } + + [Fact] + public async Task CreateAsync() + { + var claimsPrincipal = await _abpClaimsPrincipalFactory.CreateAsync(); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io"); + claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io"); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0"); + } + + [Fact] + public async Task Create_With_Exists_ClaimsPrincipal() + { + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(TestAuthenticationType, ClaimTypes.Name, ClaimTypes.Role)); + claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Name, "123")); + claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Role, "admin")); + + await _abpClaimsPrincipalFactory.CreateAsync(claimsPrincipal); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == "123"); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "admin"); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io"); + claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io"); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0"); + } + + class TestAbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor + { + public Task ContributeAsync(AbpClaimsPrincipalContributorContext context) + { + var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType) + ?? new ClaimsIdentity(TestAuthenticationType); + + claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin@abp.io")); + + context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity); + + return Task.CompletedTask; + } + } + + class Test2AbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor + { + public Task ContributeAsync(AbpClaimsPrincipalContributorContext context) + { + var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType) + ?? new ClaimsIdentity(TestAuthenticationType); + + claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin2@abp.io")); + + context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity); + + return Task.CompletedTask; + } + } + + class Test3AbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor + { + public Task ContributeAsync(AbpClaimsPrincipalContributorContext context) + { + var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType) + ?? new ClaimsIdentity(TestAuthenticationType); + + claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Version, "2.0")); + + context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity); + + return Task.CompletedTask; + } + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs index 2543e846e6..16369e8285 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs @@ -4,6 +4,7 @@ using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; +using System.Security.Principal; using Volo.Abp.DependencyInjection; using Volo.Abp.Security.Claims; using Volo.Abp.Uow; @@ -69,11 +70,7 @@ namespace Volo.Abp.Identity using (CurrentPrincipalAccessor.Change(identity)) { - var abpClaimsPrincipal = await AbpClaimsPrincipalFactory.CreateAsync(); - foreach (var claim in abpClaimsPrincipal.Claims) - { - identity.AddIfNotContains(claim); - } + await AbpClaimsPrincipalFactory.CreateAsync(principal); } return principal; diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory_Tests.cs new file mode 100644 index 0000000000..01704e108a --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory_Tests.cs @@ -0,0 +1,64 @@ +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.Identity +{ + public class AbpUserClaimsPrincipalFactory_Tests : AbpIdentityDomainTestBase + { + private readonly IdentityUserManager _identityUserManager; + private readonly AbpUserClaimsPrincipalFactory _abpUserClaimsPrincipalFactory; + private readonly IdentityTestData _testData; + + public AbpUserClaimsPrincipalFactory_Tests() + { + _identityUserManager = GetRequiredService(); + _abpUserClaimsPrincipalFactory = GetRequiredService(); + _testData = GetRequiredService(); + } + + [Fact] + public async Task Add_And_Replace_Claims_Test() + { + await UsingUowAsync(async () => + { + var user = await _identityUserManager.GetByIdAsync(_testData.UserJohnId); + user.ShouldNotBeNull(); + + var claimsPrincipal = await _abpUserClaimsPrincipalFactory.CreateAsync(user); + + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.NameIdentifier && x.Value == user.Id.ToString()); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == user.UserName); + + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Uri && x.Value =="www.abp.io"); + + claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == user.Email); + claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "replaced@abp.io"); + }); + } + + class TestAbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency + { + //https://github.com/dotnet/aspnetcore/blob/v5.0.0/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs#L79 + private static string IdentityAuthenticationType => "Identity.Application"; + + public Task ContributeAsync(AbpClaimsPrincipalContributorContext context) + { + var claimsIdentity = context.ClaimsPrincipal.Identities.First(x => x.AuthenticationType == IdentityAuthenticationType); + + claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Uri, "www.abp.io")); + claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "replaced@abp.io")); + + context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity); + + return Task.CompletedTask; + } + } + + } +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs index 982e52cfab..219cb943d8 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs @@ -1,11 +1,11 @@ using System; using System.Linq; using System.Security.Claims; +using System.Security.Principal; using System.Threading.Tasks; using IdentityModel; using Microsoft.AspNetCore.Identity; using Volo.Abp.DependencyInjection; -using Volo.Abp.Security.Claims; using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.IdentityServer.AspNetIdentity diff --git a/npm/packs/tui-editor/package.json b/npm/packs/tui-editor/package.json index f46853da85..0d02f2457d 100644 --- a/npm/packs/tui-editor/package.json +++ b/npm/packs/tui-editor/package.json @@ -10,7 +10,7 @@ "@abp/jquery": "~4.2.2", "@abp/markdown-it": "~4.2.2", "tui-editor": "^1.4.10", - "tui-code-snippet": "^2.3.2" + "tui-code-snippet": "1.5.2" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" }