diff --git a/zero/Configuration/Constants.cs b/zero/Configuration/Constants.cs
index fa96aa14..d9b6832d 100644
--- a/zero/Configuration/Constants.cs
+++ b/zero/Configuration/Constants.cs
@@ -4,11 +4,6 @@ public static partial class Constants
{
public const string ErrorFieldNone = "__zero_no_field";
- public static partial class Tabs
- {
- public const string General = "general";
- }
-
public static partial class Auth
{
public const string SystemUser = "system";
@@ -17,86 +12,11 @@ public static partial class Constants
public const string BackofficeScheme = "zeroBackoffice";
public const string BackofficeCookieName = "zero.be.session";
public const string DefaultCookieName = "zero.session";
-
- public static partial class Claims
- {
- public const string IsZero = "zero.claim.iszero";
- public const string IsSuper = "zero.claim.issuper";
- public const string UserId = "zero.claim.userid";
- public const string UserName = "zero.claim.username";
- public const string Role = "zero.claim.rolealias";
- public const string SecurityStamp = "zero.claim.securitystamp";
- public const string Email = "zero.claim.email";
- public const string Permission = "zero.claim.permission";
- public const string DefaultAppId = "zero.claim.defaultAppId";
- public const string AppId = "zero.claim.appId";
- public const string TicketExpires = "zero.claim.ticketExpires";
- }
}
-
- public static partial class Permissions
- {
- public static partial class Groups
- {
- public const string Sections = "zero.permissions.groups.sections";
- public const string Spaces = "zero.permissions.groups.spaces";
- public const string Settings = "zero.permissions.groups.settings";
- public const string Pages = "zero.permissions.groups.pages";
- public const string Modules = "zero.permissions.groups.modules";
- }
- }
-
-
public static partial class Database
{
public const string ReservationPrefix = "zero.";
public const string Expires = Raven.Client.Constants.Documents.Metadata.Expires;
}
-
- public static partial class Sections
- {
- public const string Dashboard = "dashboard";
- public const string Pages = "pages";
- public const string Spaces = "spaces";
- public const string Media = "media";
- public const string Settings = "settings";
- }
-
- public static partial class Settings
- {
- public const string Updates = "updates";
- public const string Applications = "applications";
- public const string Users = "users";
- public const string Languages = "languages";
- public const string Translations = "translations";
- public const string Countries = "countries";
- public const string Mails = "mailTemplates";
- public const string Integrations = "integrations";
- public const string Logging = "logs";
- public const string Plugins = "plugins";
- public const string CreatePlugin = "createplugin";
- }
-
- public static partial class PermissionCollections
- {
- public const string Sections = "permissionCollectionSections";
- public const string Spaces = "permissionCollectionSpaces";
- public const string Settings = "permisssionCollectionSettings";
- public const string Modules = "permissionCollectionModules";
- }
-
- public static partial class Pages
- {
- public const string FolderAlias = "zero.folder";
- public const string DefaultRootPageTypeAlias = "root";
- public const string PageRouteProviderAlias = "zero.pages";
- }
-
- public static partial class Routing
- {
- public const string InternalRoutePrefix = "/__zero/";
-
- public const string ErrorRoute = InternalRoutePrefix + "error";
- }
}
diff --git a/zero/Identity/IdentityBuilderExtensions.cs b/zero/Identity/IdentityBuilderExtensions.cs
index 864879dd..947ab791 100644
--- a/zero/Identity/IdentityBuilderExtensions.cs
+++ b/zero/Identity/IdentityBuilderExtensions.cs
@@ -9,12 +9,10 @@ public static class IdentityBuilderExtensions
///
/// Adds an implementation of identity information stores.
///
- public static IdentityBuilder AddZeroIdentityStores(this IdentityBuilder builder) where T : class, IZeroIdentityStoreDbProvider
+ public static IdentityBuilder AddZeroIdentityStores(this IdentityBuilder builder)
{
Type userStoreType = typeof(ZeroUserStore<,>).MakeGenericType(builder.UserType, builder.RoleType);
Type roleStoreType = typeof(ZeroRoleStore<>).MakeGenericType(builder.RoleType);
-
- builder.Services.AddScoped();
builder.Services.TryAddScoped(typeof(IUserStore<>).MakeGenericType(builder.UserType), userStoreType);
builder.Services.TryAddScoped(typeof(IRoleStore<>).MakeGenericType(builder.RoleType), roleStoreType);
diff --git a/zero/Identity/ServiceCollectionExtensions.cs b/zero/Identity/ServiceCollectionExtensions.cs
deleted file mode 100644
index 2e087e05..00000000
--- a/zero/Identity/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using Microsoft.AspNetCore.Authentication.Cookies;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Identity;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using zero.Identity;
-
-namespace zero.Identity;
-
-public static class ServiceCollectionExtensions
-{
- ///
- /// Adds the default identity system configuration for the specified User and Role types
- ///
- // public static IdentityBuilder AddZeroIdentity(
- // this IServiceCollection services)
- // where TUser : ZeroIdentityUser, new()
- // where TRole : ZeroIdentityRole, new()
- // where TStore : class, IZeroIdentityStoreDbProvider
- // => services.AddIdentity(setupAction: null!);
-
- ///
- /// Adds and configures the identity system for the specified User and Role types
- ///
- public static IdentityBuilder AddZeroIdentity(
- this IServiceCollection services,
- Action setupAction
- )
- where TUser : ZeroIdentityUser, new()
- where TRole : ZeroIdentityRole, new()
- where TStore : class, IZeroIdentityStoreDbProvider
- {
- // Services used by identity
- services.AddAuthentication(options =>
- {
- options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
- options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
- options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
- })
- .AddCookie(IdentityConstants.ApplicationScheme, o =>
- {
- o.LoginPath = new PathString("/Account/Login");
- o.Events = new CookieAuthenticationEvents
- {
- OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
- };
- })
- .AddCookie(IdentityConstants.ExternalScheme, o =>
- {
- o.Cookie.Name = IdentityConstants.ExternalScheme;
- o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
- })
- .AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o =>
- {
- o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme;
- o.Events = new CookieAuthenticationEvents
- {
- OnValidatePrincipal = SecurityStampValidator.ValidateAsync
- };
- })
- .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
- {
- o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
- o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
- });
-
- // Hosting doesn't add IHttpContextAccessor by default
- services.AddHttpContextAccessor();
-
- // Data stores
- services.AddScoped();
- services.TryAddScoped, ZeroUserStore>();
- services.TryAddScoped, ZeroRoleStore>();
-
- // Identity services
- services.TryAddScoped, UserValidator>();
- services.TryAddScoped, PasswordValidator>();
- services.TryAddScoped, PasswordHasher>();
- services.TryAddScoped();
- services.TryAddScoped, RoleValidator>();
- services.TryAddScoped();
- services.TryAddScoped>();
- services.TryAddScoped>();
- services.TryAddScoped, UserClaimsPrincipalFactory>();
- services.TryAddScoped, DefaultUserConfirmation>();
- services.TryAddScoped>();
- services.TryAddScoped>();
- services.TryAddScoped>();
-
- if (setupAction != null)
- {
- services.Configure(setupAction);
- }
-
- return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
- }
-}
\ No newline at end of file
diff --git a/zero/Identity/ZeroIdentityConstants.cs b/zero/Identity/ZeroIdentityConstants.cs
new file mode 100644
index 00000000..28962812
--- /dev/null
+++ b/zero/Identity/ZeroIdentityConstants.cs
@@ -0,0 +1,31 @@
+namespace zero.Identity;
+
+///
+/// Represents all the options you can use to configure the cookies middleware used by the identity system.
+///
+public class ZeroIdentityConstants
+{
+ public static class CookieNames
+ {
+ private const string CookiePrefix = "zero.id";
+
+ public static readonly string Application = CookiePrefix + ".app";
+ public static readonly string External = CookiePrefix + ".ext";
+ public static readonly string TwoFactorRememberMe = CookiePrefix + ".2fa_rem";
+ public static readonly string TwoFactorUserId = CookiePrefix + ".2fa_id";
+ }
+
+ public static partial class Claims
+ {
+ private const string ClaimPrefix = "zero.claim";
+
+ public static readonly string IsZero = ClaimPrefix + ".iszero";
+ public static readonly string UserId = ClaimPrefix + ".userid";
+ public static readonly string UserName = ClaimPrefix + ".username";
+ public static readonly string Role = ClaimPrefix + ".rolealias";
+ public static readonly string SecurityStamp = ClaimPrefix + ".securitystamp";
+ public static readonly string Email = ClaimPrefix + ".email";
+ public static readonly string Permission = ClaimPrefix + ".permission";
+ public static readonly string TicketExpires = ClaimPrefix + ".ticketExpires";
+ }
+}
diff --git a/zero/Identity/ZeroIdentityExtensions.cs b/zero/Identity/ZeroIdentityExtensions.cs
new file mode 100644
index 00000000..4cdbf5c3
--- /dev/null
+++ b/zero/Identity/ZeroIdentityExtensions.cs
@@ -0,0 +1,161 @@
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace zero.Identity;
+
+public static class ZeroIdentityExtensions
+{
+ //
+ /// Adds the default identity system configuration for the specified User and Role types.
+ ///
+ /// The type representing a User in the system.
+ /// The type representing a Role in the system.
+ /// The services available in the application.
+ /// An for creating and configuring the identity system.
+ public static IdentityBuilder AddZeroIdentity(this IServiceCollection services)
+ where TUser : ZeroIdentityUser, new()
+ where TRole : ZeroIdentityRole, new() =>
+ AddZeroIdentity(services, null);
+
+
+ ///
+ /// Adds and configures the identity system for the specified User and Role types.
+ ///
+ /// The type representing a User in the system.
+ /// The type representing a Role in the system.
+ /// The services available in the application.
+ /// An action to configure the .
+ /// An for creating and configuring the identity system.
+ public static IdentityBuilder AddZeroIdentity(this IServiceCollection services,
+ Action setupAction)
+ where TUser : ZeroIdentityUser, new()
+ where TRole : ZeroIdentityRole, new()
+ {
+ // Services identity depends on
+ services
+ .AddOptions()
+ .AddLogging();
+
+ // Services used by identity
+ services.AddAuthentication(options =>
+ {
+ options.DefaultScheme = IdentityConstants.ApplicationScheme;
+ options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
+ options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
+ options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
+ })
+ .AddCookie(IdentityConstants.ApplicationScheme, o =>
+ {
+ o.LoginPath = new PathString("/Account/Login");
+ o.SlidingExpiration = true;
+ o.ExpireTimeSpan = TimeSpan.FromDays(90);
+
+ o.Cookie.Name = ZeroIdentityConstants.CookieNames.Application;
+ o.Cookie.HttpOnly = true;
+ o.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
+ o.Cookie.SameSite = SameSiteMode.Lax;
+ o.Cookie.Path = "/";
+
+ o.Events = new CookieAuthenticationEvents
+ {
+ OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
+ };
+ })
+ .AddCookie(IdentityConstants.ExternalScheme, o =>
+ {
+ o.Cookie.Name = ZeroIdentityConstants.CookieNames.External;
+ o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
+ })
+ .AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o =>
+ {
+ o.Cookie.Name = ZeroIdentityConstants.CookieNames.TwoFactorRememberMe;
+ o.Events = new CookieAuthenticationEvents
+ {
+ OnValidatePrincipal = SecurityStampValidator.ValidateAsync
+ };
+ })
+ .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
+ {
+ o.Cookie.Name = ZeroIdentityConstants.CookieNames.TwoFactorUserId;
+ o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
+ });
+
+ // Hosting doesn't add IHttpContextAccessor by default
+ services.AddHttpContextAccessor();
+
+ // Identity services
+ services.TryAddScoped, UserValidator>();
+ services.TryAddScoped, PasswordValidator>();
+ services.TryAddScoped, PasswordHasher>();
+ services.TryAddScoped();
+ services.TryAddScoped, RoleValidator>();
+
+ // No interface for the error describer so we can add errors without rev'ing the interface
+ services.TryAddScoped();
+ services.TryAddScoped>();
+ services.TryAddScoped>();
+ services.TryAddScoped, UserClaimsPrincipalFactory>();
+ services.TryAddScoped, DefaultUserConfirmation>();
+ services.TryAddScoped>();
+ services.TryAddScoped>();
+ services.TryAddScoped>();
+
+ services.Configure(opts =>
+ {
+ opts.ClaimsIdentity.UserIdClaimType = ZeroIdentityConstants.Claims.UserId;
+ opts.ClaimsIdentity.UserNameClaimType = ZeroIdentityConstants.Claims.UserName;
+ opts.ClaimsIdentity.RoleClaimType = ZeroIdentityConstants.Claims.Role;
+ opts.ClaimsIdentity.SecurityStampClaimType = ZeroIdentityConstants.Claims.SecurityStamp;
+ opts.ClaimsIdentity.EmailClaimType = ZeroIdentityConstants.Claims.Email;
+
+ opts.Password.RequireDigit = false;
+ opts.Password.RequireLowercase = false;
+ opts.Password.RequireUppercase = false;
+ opts.Password.RequireNonAlphanumeric = false;
+ opts.Password.RequiredLength = 8;
+ opts.Password.RequiredUniqueChars = 1;
+
+ opts.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(60);
+ opts.Lockout.MaxFailedAccessAttempts = 5;
+ opts.Lockout.AllowedForNewUsers = true;
+
+ opts.User.RequireUniqueEmail = true;
+ });
+
+ services.Configure(opts => { opts.ValidationInterval = TimeSpan.FromMinutes(90); });
+
+ if (setupAction != null)
+ {
+ services.Configure(setupAction);
+ }
+
+ IdentityBuilder builder = new(typeof(TUser), typeof(TRole), services);
+
+ builder.AddDefaultTokenProviders();
+ builder.AddZeroIdentityStores();
+
+ return builder;
+ }
+
+
+ ///
+ /// Configures the application cookie.
+ ///
+ /// The services available in the application.
+ /// An action to configure the .
+ /// The services.
+ public static IServiceCollection ConfigureZeroApplicationCookie(this IServiceCollection services, Action configure)
+ => services.Configure(IdentityConstants.ApplicationScheme, configure);
+
+ ///
+ /// Configure the external cookie.
+ ///
+ /// The services available in the application.
+ /// An action to configure the .
+ /// The services.
+ public static IServiceCollection ConfigureZeroExternalCookie(this IServiceCollection services, Action configure)
+ => services.Configure(IdentityConstants.ExternalScheme, configure);
+}
\ No newline at end of file
diff --git a/zero/ZeroBuilder.cs b/zero/ZeroBuilder.cs
index 10e319de..88c432b2 100644
--- a/zero/ZeroBuilder.cs
+++ b/zero/ZeroBuilder.cs
@@ -1,4 +1,5 @@
using FluentValidation;
+using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -33,6 +34,8 @@ public class ZeroBuilder
services.AddControllers();
services.AddRazorPages();
+ services.Configure(opts => opts.Cookie.Name = "zero.antiforgery");
+
// adds and discovers additional and built-in assemblies
new AssemblyDiscovery(Mvc).Execute(_startupOptions.AssemblyDiscoveryRules);