From a8b4e0dfa9bea041f674d2a92aadd3498913cc42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 2 Feb 2021 11:31:21 +0300 Subject: [PATCH] Seed identity & permission data for a tenant via event handlers. --- .../Entities/Events/Distributed/EtoBase.cs | 0 .../Volo/Abp/MultiTenancy/TenantCreatedEto.cs | 4 +- .../Abp/Identity/AbpIdentityDomainModule.cs | 18 ++++- .../Volo/Abp/Identity/AbpIdentityOptions.cs | 5 ++ .../Volo/Abp/Identity/IdentityDataSeeder.cs | 79 ++++++++++--------- .../Identity/IdentityTenantCreatedHandler.cs | 32 ++++++++ .../Abp/Identity/PasswordOptionsExtensions.cs | 35 ++++++++ .../AbpPermissionManagementDomainModule.cs | 23 +++++- .../PermissionDataSeedContributor.cs | 1 - .../PermissionManagementOptions.cs | 6 +- .../PermissionTenantCreatedHandler.cs | 38 +++++++++ 11 files changed, 197 insertions(+), 44 deletions(-) rename framework/src/{Volo.Abp.Ddd.Domain => Volo.Abp.EventBus.Abstractions}/Volo/Abp/Domain/Entities/Events/Distributed/EtoBase.cs (100%) create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityTenantCreatedHandler.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionTenantCreatedHandler.cs diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoBase.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/Domain/Entities/Events/Distributed/EtoBase.cs similarity index 100% rename from framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoBase.cs rename to framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/Domain/Entities/Events/Distributed/EtoBase.cs diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantCreatedEto.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantCreatedEto.cs index 6cd1544d8c..317995c971 100644 --- a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantCreatedEto.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantCreatedEto.cs @@ -1,10 +1,12 @@ using System; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus; namespace Volo.Abp.MultiTenancy { + [Serializable] [EventName("abp.multi_tenancy.tenant.created")] - public class TenantCreatedEto + public class TenantCreatedEto : EtoBase { public Guid Id { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs index 4269ae2e01..6c2197b38d 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs @@ -1,10 +1,12 @@ -using Microsoft.AspNetCore.Identity; +using System.Collections.Generic; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Volo.Abp.AutoMapper; using Volo.Abp.Domain; using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus.Distributed; using Volo.Abp.Modularity; using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending.Modularity; @@ -57,6 +59,20 @@ namespace Volo.Abp.Identity }); context.Services.AddAbpDynamicOptions(); + + Configure(options => + { + var serviceProvider = context.Services.GetServiceProviderOrNull(); + if (serviceProvider != null) + { + var abpIdentityOptions = serviceProvider.GetRequiredService>().Value; + if (!abpIdentityOptions.IsDistributedEventHandlingEnabled) + { + var identityDomainAssembly = typeof(AbpIdentityDomainModule).Assembly; + options.Handlers.RemoveAll(x => x.Assembly == identityDomainAssembly); + } + } + }); } public override void PostConfigureServices(ServiceConfigurationContext context) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptions.cs index 6cfaf75c0c..36b7ba587a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptions.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptions.cs @@ -4,6 +4,11 @@ { public ExternalLoginProviderDictionary ExternalLoginProviders { get; } + /// + /// Default: true. + /// + public bool IsDistributedEventHandlingEnabled { get; } = true; + public AbpIdentityOptions() { ExternalLoginProviders = new ExternalLoginProviderDictionary(); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs index f6bed1b914..9051dc7d66 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs @@ -49,58 +49,61 @@ namespace Volo.Abp.Identity Check.NotNullOrWhiteSpace(adminEmail, nameof(adminEmail)); Check.NotNullOrWhiteSpace(adminPassword, nameof(adminPassword)); - await IdentityOptions.SetAsync(); - - var result = new IdentityDataSeedResult(); - using (CurrentTenant.Change(tenantId)) { - //"admin" user - const string adminUserName = "admin"; - var adminUser = await UserRepository.FindByNormalizedUserNameAsync( - LookupNormalizer.NormalizeName(adminUserName) - ); + await IdentityOptions.SetAsync(); - if (adminUser != null) + using (IdentityOptions.Value.Password.ClearRequirements()) { - return result; - } + var result = new IdentityDataSeedResult(); + //"admin" user + const string adminUserName = "admin"; + var adminUser = await UserRepository.FindByNormalizedUserNameAsync( + LookupNormalizer.NormalizeName(adminUserName) + ); - adminUser = new IdentityUser( - GuidGenerator.Create(), - adminUserName, - adminEmail, - tenantId - ) - { - Name = adminUserName - }; - - (await UserManager.CreateAsync(adminUser, adminPassword)).CheckErrors(); - result.CreatedAdminUser = true; + if (adminUser != null) + { + return result; + } - //"admin" role - const string adminRoleName = "admin"; - var adminRole = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName)); - if (adminRole == null) - { - adminRole = new IdentityRole( + adminUser = new IdentityUser( GuidGenerator.Create(), - adminRoleName, + adminUserName, + adminEmail, tenantId ) { - IsStatic = true, - IsPublic = true + Name = adminUserName }; - (await RoleManager.CreateAsync(adminRole)).CheckErrors(); - result.CreatedAdminRole = true; - } + (await UserManager.CreateAsync(adminUser, adminPassword)).CheckErrors(); + result.CreatedAdminUser = true; + + //"admin" role + const string adminRoleName = "admin"; + var adminRole = + await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName)); + if (adminRole == null) + { + adminRole = new IdentityRole( + GuidGenerator.Create(), + adminRoleName, + tenantId + ) + { + IsStatic = true, + IsPublic = true + }; - (await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors(); + (await RoleManager.CreateAsync(adminRole)).CheckErrors(); + result.CreatedAdminRole = true; + } - return result; + (await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors(); + + return result; + } } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityTenantCreatedHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityTenantCreatedHandler.cs new file mode 100644 index 0000000000..92a0be629c --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityTenantCreatedHandler.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using AutoMapper.Internal; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity +{ + public class IdentityTenantCreatedHandler : IDistributedEventHandler, ITransientDependency + { + public ILogger Logger { get; set; } + + protected IIdentityDataSeeder IdentityDataSeeder { get; } + + public IdentityTenantCreatedHandler(IIdentityDataSeeder identityDataSeeder) + { + IdentityDataSeeder = identityDataSeeder; + Logger = NullLogger.Instance; + } + + public async Task HandleEventAsync(TenantCreatedEto eventData) + { + await IdentityDataSeeder.SeedAsync( + eventData.Properties.GetOrDefault("AdminEmail") as string ?? "admin@abp.io", + eventData.Properties.GetOrDefault("AdminPassword") as string ?? "1q2w3E*", + eventData.Id + ); + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs new file mode 100644 index 0000000000..793cc6349e --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.AspNetCore.Identity; + +namespace Volo.Abp.Identity +{ + public static class PasswordOptionsExtensions + { + public static IDisposable ClearRequirements(this PasswordOptions options) + { + var oldRequireDigit = options.RequireDigit; + var oldRequiredLength = options.RequiredLength; + var oldRequireLowercase = options.RequireLowercase; + var oldRequireUppercase = options.RequireUppercase; + var oldRequiredUniqueChars = options.RequiredUniqueChars; + var oldRequireNonAlphanumeric = options.RequireNonAlphanumeric; + + options.RequireDigit = false; + options.RequiredLength = 1; + options.RequireLowercase = false; + options.RequireUppercase = false; + options.RequiredUniqueChars = 1; + options.RequireNonAlphanumeric = false; + + return new DisposeAction(() => + { + options.RequireDigit = oldRequireDigit; + options.RequiredLength = oldRequiredLength; + options.RequireLowercase = oldRequireLowercase; + options.RequireUppercase = oldRequireUppercase; + options.RequiredUniqueChars = oldRequiredUniqueChars; + options.RequireNonAlphanumeric = oldRequireNonAlphanumeric; + }); + } + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index c199a2130b..5b3eb9f40f 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -1,6 +1,10 @@ -using Volo.Abp.Authorization; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization; using Volo.Abp.Caching; using Volo.Abp.Domain; +using Volo.Abp.EventBus.Distributed; using Volo.Abp.Json; using Volo.Abp.Modularity; @@ -13,6 +17,21 @@ namespace Volo.Abp.PermissionManagement [DependsOn(typeof(AbpJsonModule))] public class AbpPermissionManagementDomainModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + var serviceProvider = context.Services.GetServiceProviderOrNull(); + if (serviceProvider != null) + { + var abpIdentityOptions = serviceProvider.GetRequiredService>().Value; + if (!abpIdentityOptions.IsDistributedEventHandlingEnabled) + { + var identityDomainAssembly = typeof(AbpPermissionManagementDomainModule).Assembly; + options.Handlers.RemoveAll(x => x.Assembly == identityDomainAssembly); + } + } + }); + } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs index ac8274d445..8260df895f 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs @@ -10,7 +10,6 @@ namespace Volo.Abp.PermissionManagement public class PermissionDataSeedContributor : IDataSeedContributor, ITransientDependency { protected ICurrentTenant CurrentTenant { get; } - protected IPermissionDefinitionManager PermissionDefinitionManager { get; } protected IPermissionDataSeeder PermissionDataSeeder { get; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 674f5daa88..c36cde49ee 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs @@ -5,11 +5,15 @@ namespace Volo.Abp.PermissionManagement { public class PermissionManagementOptions { - //TODO: rename to Providers public ITypeList ManagementProviders { get; } public Dictionary ProviderPolicies { get; } + /// + /// Default: true. + /// + public bool IsDistributedEventHandlingEnabled { get; } = true; + public PermissionManagementOptions() { ManagementProviders = new TypeList(); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionTenantCreatedHandler.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionTenantCreatedHandler.cs new file mode 100644 index 0000000000..8962574434 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionTenantCreatedHandler.cs @@ -0,0 +1,38 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement +{ + public class PermissionTenantCreatedHandler : IDistributedEventHandler, ITransientDependency + { + protected IPermissionDefinitionManager PermissionDefinitionManager { get; } + protected IPermissionDataSeeder PermissionDataSeeder { get; } + + public PermissionTenantCreatedHandler(IPermissionDefinitionManager permissionDefinitionManager, IPermissionDataSeeder permissionDataSeeder) + { + PermissionDefinitionManager = permissionDefinitionManager; + PermissionDataSeeder = permissionDataSeeder; + } + + public async Task HandleEventAsync(TenantCreatedEto eventData) + { + var permissionNames = PermissionDefinitionManager + .GetPermissions() + .Where(p => p.MultiTenancySide.HasFlag(MultiTenancySides.Tenant)) + .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName)) + .Select(p => p.Name) + .ToArray(); + + await PermissionDataSeeder.SeedAsync( + RolePermissionValueProvider.ProviderName, + "admin", + permissionNames, + eventData.Id + ); + } + } +}