diff --git a/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs b/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs index 491d0c59e..4e32d317a 100644 --- a/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs +++ b/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs @@ -69,7 +69,7 @@ namespace Squidex.Domain.Users } else { - return await userManager.FindByEmailWithClaimsAsyncAsync(idOrEmail); + return await userManager.FindByEmailWithClaimsAsync(idOrEmail); } } } diff --git a/backend/src/Squidex.Domain.Users/UserManagerExtensions.cs b/backend/src/Squidex.Domain.Users/UserManagerExtensions.cs index 251aa1420..30cb86f19 100644 --- a/backend/src/Squidex.Domain.Users/UserManagerExtensions.cs +++ b/backend/src/Squidex.Domain.Users/UserManagerExtensions.cs @@ -55,7 +55,7 @@ namespace Squidex.Domain.Users return await userManager.ResolveUserAsync(user); } - public static async Task FindByEmailWithClaimsAsyncAsync(this UserManager userManager, string email) + public static async Task FindByEmailWithClaimsAsync(this UserManager userManager, string email) { if (email == null) { diff --git a/backend/src/Squidex.Infrastructure/Security/PermissionSet.cs b/backend/src/Squidex.Infrastructure/Security/PermissionSet.cs index ee3c06055..ab015d611 100644 --- a/backend/src/Squidex.Infrastructure/Security/PermissionSet.cs +++ b/backend/src/Squidex.Infrastructure/Security/PermissionSet.cs @@ -48,6 +48,20 @@ namespace Squidex.Infrastructure.Security display = new Lazy(() => string.Join(";", this.permissions)); } + public PermissionSet Add(string permission) + { + Guard.NotNullOrEmpty(permission); + + return Add(new Permission(permission)); + } + + public PermissionSet Add(Permission permission) + { + Guard.NotNull(permission); + + return new PermissionSet(permissions.Union(Enumerable.Repeat(permission, 1)).Distinct()); + } + public bool Allows(Permission? other) { if (other == null) diff --git a/backend/src/Squidex/Areas/IdentityServer/Config/CreateAdminHost.cs b/backend/src/Squidex/Areas/IdentityServer/Config/CreateAdminHost.cs index 164849ba8..31346dcd3 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Config/CreateAdminHost.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Config/CreateAdminHost.cs @@ -19,6 +19,7 @@ using Squidex.Domain.Users; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Security; using Squidex.Shared; +using Squidex.Shared.Users; namespace Squidex.Areas.IdentityServer.Config { @@ -49,19 +50,41 @@ namespace Squidex.Areas.IdentityServer.Config var adminEmail = identityOptions.AdminEmail; var adminPass = identityOptions.AdminPassword; - if (userManager.SupportsQueryableUsers && !userManager.Users.Any()) + var isEmpty = IsEmpty(userManager); + + if (isEmpty || identityOptions.AdminRecreate) { try { - var values = new UserValues + var user = await userManager.FindByEmailWithClaimsAsync(adminEmail); + + if (user != null) + { + if (identityOptions.AdminRecreate) + { + var permissions = user.Permissions().Add(Permissions.Admin); + + var values = new UserValues + { + Password = adminPass, + Permissions = permissions + }; + + await userManager.UpdateAsync(user.Identity, values); + } + } + else { - Email = adminEmail, - Password = adminPass, - Permissions = new PermissionSet(Permissions.Admin), - DisplayName = adminEmail - }; + var values = new UserValues + { + Email = adminEmail, + Password = adminPass, + Permissions = new PermissionSet(Permissions.Admin), + DisplayName = adminEmail + }; - await userManager.CreateAsync(userFactory, values); + await userManager.CreateAsync(userFactory, values); + } } catch (Exception ex) { @@ -73,5 +96,10 @@ namespace Squidex.Areas.IdentityServer.Config } } } + + private static bool IsEmpty(UserManager userManager) + { + return userManager.SupportsQueryableUsers && !userManager.Users.Any(); + } } } diff --git a/backend/src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs b/backend/src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs index 983e56954..676a27b95 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs @@ -268,7 +268,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account { var email = externalLogin.Principal.FindFirst(ClaimTypes.Email).Value; - user = await userManager.FindByEmailWithClaimsAsyncAsync(email); + user = await userManager.FindByEmailWithClaimsAsync(email); if (user != null) { diff --git a/backend/src/Squidex/Config/MyIdentityOptions.cs b/backend/src/Squidex/Config/MyIdentityOptions.cs index 4d6d7a33b..01fb1eb8c 100644 --- a/backend/src/Squidex/Config/MyIdentityOptions.cs +++ b/backend/src/Squidex/Config/MyIdentityOptions.cs @@ -11,6 +11,10 @@ namespace Squidex.Config { public sealed class MyIdentityOptions { + public string PrivacyUrl { get; set; } + + public string AuthorityUrl { get; set; } + public string AdminEmail { get; set; } public string AdminPassword { get; set; } @@ -45,11 +49,7 @@ namespace Squidex.Config public Dictionary OidcRoleMapping { get; set; } - public string AuthorityUrl { get; set; } - - public string PrivacyUrl { get; set; } - - public bool RequiresHttps { get; set; } + public bool AdminRecreate { get; set; } public bool AllowPasswordAuth { get; set; } @@ -57,6 +57,8 @@ namespace Squidex.Config public bool NoConsent { get; set; } + public bool RequiresHttps { get; set; } + public bool ShowPII { get; set; } public bool IsAdminConfigured() diff --git a/backend/src/Squidex/appsettings.json b/backend/src/Squidex/appsettings.json index ec81f1348..f6156d974 100644 --- a/backend/src/Squidex/appsettings.json +++ b/backend/src/Squidex/appsettings.json @@ -428,6 +428,10 @@ */ "adminEmail": "", "adminPassword": "", + /* + * Recreate the admin if it does not exist or the password does not match. + */ + "adminRecreate": false, /* * Client with all admin permissions. */ diff --git a/backend/tests/Squidex.Infrastructure.Tests/Security/PermissionSetTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Security/PermissionSetTests.cs index f76ae19ba..05c0fb461 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Security/PermissionSetTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Security/PermissionSetTests.cs @@ -113,5 +113,25 @@ namespace Squidex.Infrastructure.Security Assert.False(sut.Includes(null)); } + + [Fact] + public void Should_add_permission_by_string() + { + var sut = + new PermissionSet("app.contents") + .Add("admin.*"); + + Assert.True(sut.Includes(new Permission("admin"))); + } + + [Fact] + public void Should_add_permission() + { + var sut = + new PermissionSet("app.contents") + .Add(new Permission("admin.*")); + + Assert.True(sut.Includes(new Permission("admin"))); + } } }