Skip to content

Ntuthuko/consolidate authentication settings#4330

Open
ntuthukomsane-boxfusion wants to merge 86 commits intoshesha-io:mainfrom
ntuthukomsane-boxfusion:ntuthuko/consolidate-authentication-settings
Open

Ntuthuko/consolidate authentication settings#4330
ntuthukomsane-boxfusion wants to merge 86 commits intoshesha-io:mainfrom
ntuthukomsane-boxfusion:ntuthuko/consolidate-authentication-settings

Conversation

@ntuthukomsane-boxfusion
Copy link
Copy Markdown

@ntuthukomsane-boxfusion ntuthukomsane-boxfusion commented Dec 9, 2025

This pr addresses the following:
[#4366]

Consolidation of authentication settings by taking all the authentication settings which were previously used as individual settings into a newly created "DefaultAuthenticationSettings" object

Summary by CodeRabbit

  • New Features

    • Unified user-management/authentication settings UI, frontend redirect controls and auto‑logoff options.
  • Updates

    • Centralized OTP, password complexity, lockout and reset options; added email‑link reset and configurable lifetimes.
    • Enhanced self‑registration with configurable creation/link modes, allowed‑domain checks, dynamic person linking and default role assignment.
    • New user link/update flow for existing accounts.
  • Style

    • Clarified labels for registration/OTP methods (Email OTP, Mobile OTP, Email Link).
  • Chores

    • One‑way migration to consolidate authentication settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 9, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Consolidates frontend user/auth configuration into a new IUserManagementSettings surface, removes legacy settings types, rewires OTP/authorization/user services to use DefaultAuthentication/GeneralFrontendSecurity, refactors user-registration for dynamic Person resolution, adds frontend redirect settings, and includes a migration to transform stored settings.

Changes

Cohort / File(s) Summary
Unified settings & models
shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/IUserManagementSettings.cs, shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/DefaultAuthenticationSettings.cs, shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/GeneralFrontendSecuritySettings.cs, shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettings.cs, shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettingNames.cs
Added IUserManagementSettings and new POCOs/constants consolidating authentication, OTP, password complexity, lockout, frontend-security, and user-management configuration.
Removed legacy setting types
shesha-core/src/Shesha.Framework/Configuration/IPasswordComplexitySettings.cs, shesha-core/src/Shesha.Application/Otp/Configuration/IOtpSettings.cs, shesha-core/src/Shesha.Application/Otp/Configuration/OtpSettings.cs, shesha-core/src/Shesha.Application/UserManagements/Configurations/IUserManagementSettings.cs, shesha-core/src/Shesha.Application/UserManagements/Configurations/UserManagementSettings.cs, shesha-core/src/Shesha.Application/UserManagements/Configurations/UserManagementSettingNames.cs
Deleted older interfaces and POCOs for password complexity, OTP, and legacy user-management settings (public API removals).
Frontend redirect aggregation
shesha-core/src/Shesha.Framework/Configuration/FrontendApplicationRedirectsSettings.cs, shesha-core/src/Shesha.Framework/Configuration/IFrontendSettings.cs, shesha-core/src/Shesha.Framework/SheshaFrameworkModule.cs, shesha-core/src/Shesha.Application/Notifications/NotificationTemplateProcessor.cs
Replaced separate DefaultUrl/PublicUrl with aggregated FrontendApplicationRedirectsSettings and updated initialization and template processing to use the new structure.
OTP subsystem wiring
shesha-core/src/Shesha.Application/Otp/OtpAppService.cs, shesha-core/src/Shesha.Application/Otp/OtpManager.cs, shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs
Switched OTP config access from IOtpSettings to IUserManagementSettings.DefaultAuthentication; constructors and Get/Set flows updated to the consolidated settings.
Authorization & user services
shesha-core/src/Shesha.Application/Authorization/Settings/AuthorizationSettingsAppService.cs, shesha-core/src/Shesha.Application/SecurityQuestions/QuestionAnswersAppService.cs, shesha-core/src/Shesha.Application/Users/UserAppService.cs, shesha-core/src/Shesha.Framework/Authorization/Users/UserManager.cs
Replaced IPasswordComplexitySettings/ISecuritySettings usage with IUserManagementSettings (DefaultAuthentication/GeneralFrontendSecuritySettings). Converted some sync flows to async and added UserManager.LinkUserAsync.
User-management app service refactor
shesha-core/src/Shesha.Application/UserManagements/UserManagementAppService.cs
Large refactor: dynamic Person entity resolution via EntityConfig, configurable creation/link modes (RefListCreationMode), allowed-domain validation, registration auditing, default-role assignment, and many helper methods; expanded dependencies.
Settings consolidation & renames
shesha-core/src/Shesha.Framework/Configuration/Security/ISecuritySettings.cs, shesha-core/src/Shesha.Framework/Configuration/Security/SecuritySettings.cs, shesha-core/src/Shesha.Framework/Configuration/SheshaSettingNames.cs
Removed lockout/reset/logoff props from old SecuritySettings/ISecuritySettings; renamed and added setting-name constants (BaseUrl/DefaultPath, DefaultAuthenticationSettings, ApplicationRedirects).
DTOs, enums & mapping tweaks
shesha-core/src/Shesha.Framework/Domain/Enums/SupportedRegistrationMethods.cs, shesha-core/src/Shesha.Application/Authorization/Settings/Dto/AuthorizationSettingsDto.cs, shesha-core/src/Shesha.Application/Persons/PersonAccountDto.cs, shesha-core/src/Shesha.Application/ShaRoleAppointedPersons/Dto/ShaRoleAppointedPersonMapProfile.cs
Added EmailLink enum and adjusted display labels; AuthorizationSettingsDto gains AutoLogoffAfterInactivity and Display attributes; removed isContractor from PersonAccountDto; mapper now uses EntityReferenceDto<Guid?> for Person.
Project file & migration
shesha-core/src/Shesha.Application/Shesha.Application.csproj, shesha-core/src/Shesha.Framework/Migrations/M20251215130900.cs, shesha-core/src/Shesha.Application/SheshaApplicationModule.cs
Moved .shaconfig to EmbeddedResource; added one-way migration to transform stored settings (UserManagement/Security/OTP → DefaultAuthentication/GeneralFrontendSecuritySettings); module updated to register IUserManagementSettings and defaults.
Other small additions
shesha-core/src/Shesha.Framework/Configuration/FrontendApplicationRedirectsSettings.cs, shesha-core/src/Shesha.Application/Notifications/NotificationTemplateProcessor.cs
Added FrontendApplicationRedirectsSettings class and changed FrontEndAppTag.PublicUrl type/source to the new redirects settings.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant UserManagementAppService
  participant EntityConfigStore
  participant DynamicRepository
  participant UserManager
  participant RoleService

  rect rgba(200,230,255,0.5)
  Client->>UserManagementAppService: CreateAsync(registrationDto)
  UserManagementAppService->>EntityConfigStore: Resolve Person entity type/config
  EntityConfigStore-->>UserManagementAppService: Type metadata
  UserManagementAppService->>DynamicRepository: FindOrCreatePerson(per CreationMode)
  DynamicRepository-->>UserManagementAppService: Person entity
  UserManagementAppService->>UserManager: CreateOrLinkUser(userDto, DefaultAuthentication)
  UserManager-->>UserManagementAppService: User entity
  UserManagementAppService->>RoleService: AssignDefaultRoles(user, config.DefaultRoles)
  RoleService-->>UserManagementAppService: Roles assigned
  UserManagementAppService-->>Client: Return mapped PersonAccountDto
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • IvanIlyichev
  • AlexStepantsov
  • James-Baloyi

Poem

🐇 I hopped through configs, neat and spry,
Bundled auth, OTP, and redirects by and by.
I migrated values, linked users anew,
Mapped persons and roles — a carrot-coded view.
Hop, nibble, commit — a rabbit’s joyous queue.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main objective of consolidating authentication settings into a unified configuration object.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 26

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
shesha-core/src/Shesha.Application/Otp/OtpAppService.cs (1)

49-61: Same data loss risk: OTP update overwrites all other authentication settings.

Similar to AuthorizationSettingsAppService, this method creates a new DefaultAuthenticationSettings with only OTP-related fields, overwriting any existing lockout, password complexity, and password reset settings configured elsewhere.

This is especially problematic since both OtpAppService.UpdateSettingsAsync and AuthorizationSettingsAppService.UpdateSettingsAsync write to the same DefaultAuthentication settings object—whichever runs last will overwrite the other's fields.

Apply the same fix: fetch existing settings first and preserve unrelated fields:

+            var existingSettings = await _userManagementSettings.DefaultAuthentication.GetValueAsync();
+
             await _userManagementSettings.DefaultAuthentication.SetValueAsync(new DefaultAuthenticationSettings
             {
+                // Preserve existing lockout, password complexity, and password reset settings
+                UserLockOutEnabled = existingSettings.UserLockOutEnabled,
+                MaxFailedAccessAttemptsBeforeLockout = existingSettings.MaxFailedAccessAttemptsBeforeLockout,
+                DefaultAccountLockoutSeconds = existingSettings.DefaultAccountLockoutSeconds,
+                RequireDigit = existingSettings.RequireDigit,
+                RequireLowercase = existingSettings.RequireLowercase,
+                RequireNonAlphanumeric = existingSettings.RequireNonAlphanumeric,
+                RequireUppercase = existingSettings.RequireUppercase,
+                RequiredLength = existingSettings.RequiredLength,
+                UseResetPasswordViaEmailLink = existingSettings.UseResetPasswordViaEmailLink,
+                ResetPasswordEmailLinkLifetime = existingSettings.ResetPasswordEmailLinkLifetime,
+                UseResetPasswordViaSmsOtp = existingSettings.UseResetPasswordViaSmsOtp,
+                ResetPasswordSmsOtpLifetime = existingSettings.ResetPasswordSmsOtpLifetime,
+                UseResetPasswordViaSecurityQuestions = existingSettings.UseResetPasswordViaSecurityQuestions,
+                ResetPasswordViaSecurityQuestionsNumQuestionsAllowed = existingSettings.ResetPasswordViaSecurityQuestionsNumQuestionsAllowed,
+                // ... other fields to preserve
+
                 PasswordLength = input.PasswordLength,
                 Alphabet = input.Alphabet,
                 ...
             });
shesha-core/src/Shesha.Application/UserManagements/UserManagementAppService.cs (2)

77-205: Email is now effectively mandatory and domain validation throws non‑user‑friendly exceptions

Within CreateAsync, HandleAllowedDomainsAsync is called unconditionally with input.EmailAddress (line 153), and that helper throws ArgumentException if the email is missing or malformed, and InvalidOperationException if the domain is not allowed. This has a few implications:

  • Behaviour change: even when defaultAuthenticationSettings.UserEmailAsUsername is false, email becomes mandatory because HandleAllowedDomainsAsync will throw for null/empty emails before validationResults.ThrowValidationExceptionIfAny(L) runs.
  • Inconsistent UX: other validation errors are aggregated into validationResults and surfaced as proper validation exceptions, but domain issues surface as ArgumentException / InvalidOperationException, which will typically present as 500s rather than user‑friendly messages.

If email is meant to be optional when username is used, the domain handler should short‑circuit when string.IsNullOrWhiteSpace(input.EmailAddress) and AllowedEmailDomains is empty/whitespace. If email is meant to be required in all cases, consider:

  • Expressing that via the validationResults list rather than ArgumentException.
  • Using UserFriendlyException (or the same validation mechanism) for invalid format and disallowed domain to keep responses consistent.

A possible direction (adjust to your conventions):

-            await HandleAllowedDomainsAsync(
-                input.EmailAddress ?? throw new UserFriendlyException(nameof(input.EmailAddress), "Email address cannot be null."),
-                allowedEmailDomains ?? string.Empty
-            );
+            if (!string.IsNullOrWhiteSpace(input.EmailAddress) || !string.IsNullOrWhiteSpace(allowedEmailDomains))
+            {
+                await HandleAllowedDomainsAsync(
+                    input.EmailAddress ?? throw new UserFriendlyException(nameof(input.EmailAddress), "Email address cannot be null."),
+                    allowedEmailDomains ?? string.Empty
+                );
+            }

and inside HandleAllowedDomainsAsync (see separate comment) change the thrown exception types to your user‑facing ones.


162-318: CreationMode handling is inconsistent (null CreationMode and MustAlreadyExist with user‑less Person will currently blow up)

The combination of HandleCreationModeAsync (lines 243–270) and CreateOrLinkUserAsync (lines 272–318) has a couple of problematic edge cases:

  1. creationMode == null

    • HandleCreationModeAsync hits the default branch and throws NotImplementedException even though the comment says “Default behavior (no creation mode specified) – create new person.”
    • CreateOrLinkUserAsync also throws ArgumentNullException when creationMode is null (line 280), while CreateOrLinkPersonEntityAsync’s default case happily creates a new person (lines 357–360).
      This will break existing tenants where CreationMode hasn’t been configured yet and also contradicts the documented “default” behaviour.
  2. RefListCreationMode.MustAlreadyExist with an existing Person but no Person.User

    • HandleCreationModeAsync only requires existingPerson != null (lines 257–260), so validation passes.
    • In CreateOrLinkUserAsync, foundUser becomes ((Person)existingPerson).User. If that property is null, there is no matching switch arm for MustAlreadyExist, so the default arm runs and throws InvalidOperationException("Unsupported creation mode: ...") (line 316).
    • Business‑wise, MustAlreadyExist usually means “person record must already exist”; it does not require a pre‑existing User. You almost certainly want to allow creating a new user and then linking it.

To make behaviour consistent and keep backwards compatibility, I suggest:

  • Treat null CreationMode as the legacy “create new person + user” behaviour.
  • For MustAlreadyExist, allow the case where the person exists but has no user: create a new user and then link.

One possible refactor:

-        private static async Task HandleCreationModeAsync(RefListCreationMode? creationMode, object? existingPerson)
-        {
-            await Task.CompletedTask; // Make it async compatible since we no longer need to call database
-
-            switch (creationMode)
-            {
-                case RefListCreationMode.Always:
-                    if (existingPerson != null)
-                        throw new UserFriendlyException($"A person with the same identifier already exists. Creation mode is set to 'Always' which requires no existing person.");
-                    break;
-
-                case RefListCreationMode.MustAlreadyExist:
-                    if (existingPerson == null)
-                        throw new UserFriendlyException($"No existing person found with the specified identifier. Creation mode is set to 'Must already exist' which requires a pre-existing person.");
-                    break;
-
-                case RefListCreationMode.CreateNewButLinkIfExist:
-                    // No validation needed - handled in CreateOrLinkPersonAsync
-                    break;
-
-                default:
-                    // Default behavior (no creation mode specified) - create new person
-                    throw new NotImplementedException();
-            }
-        }
+        private static Task HandleCreationModeAsync(RefListCreationMode? creationMode, object? existingPerson)
+        {
+            // Default behaviour when not configured: no extra validation (equivalent to "create new")
+            if (creationMode == null)
+                return Task.CompletedTask;
+
+            switch (creationMode)
+            {
+                case RefListCreationMode.Always:
+                    if (existingPerson != null)
+                        throw new UserFriendlyException("A person with the same identifier already exists. Creation mode is set to 'Always' which requires no existing person.");
+                    break;
+
+                case RefListCreationMode.MustAlreadyExist:
+                    if (existingPerson == null)
+                        throw new UserFriendlyException("No existing person found with the specified identifier. Creation mode is set to 'Must already exist' which requires a pre-existing person.");
+                    break;
+
+                case RefListCreationMode.CreateNewButLinkIfExist:
+                    // No additional validation – linking logic handles this mode.
+                    break;
+
+                default:
+                    throw new InvalidOperationException($"Unsupported creation mode: {creationMode}");
+            }
+
+            return Task.CompletedTask;
+        }

and in CreateOrLinkUserAsync:

-        private async Task<User> CreateOrLinkUserAsync(
+        private async Task<User> CreateOrLinkUserAsync(
             RefListCreationMode? creationMode,
             object? existingPerson,
             CreatePersonAccountDto input,
             string? userName,
             long? supportedPasswordResetMethods
         )
         {
-            if (creationMode is null)
-                throw new ArgumentNullException(nameof(creationMode));
-
             var isInternalAccount = input.TypeOfAccount?.ItemValue == (long)RefListTypeOfAccount.Internal;
             var username = userName.NotNull();
             var foundUser = existingPerson != null ? ((Person)existingPerson).User : null;
@@
-            return creationMode switch
-            {
-                RefListCreationMode.Always when foundUser is null => await CreateUserAsync(),
-                RefListCreationMode.MustAlreadyExist when foundUser is not null => await LinkUserAsync(),
-                RefListCreationMode.CreateNewButLinkIfExist when foundUser is not null => await LinkUserAsync(),
-                RefListCreationMode.CreateNewButLinkIfExist => await CreateUserAsync(),
-                _ => throw new InvalidOperationException($"Unsupported creation mode: {creationMode}")
-            };
+            if (creationMode is null)
+            {
+                // Legacy/default behaviour: always create a new user
+                return await CreateUserAsync();
+            }
+
+            return creationMode switch
+            {
+                RefListCreationMode.Always => await CreateUserAsync(),
+
+                // Person must exist by now; if they already have a user, link, otherwise create a new one.
+                RefListCreationMode.MustAlreadyExist when foundUser is not null => await LinkUserAsync(),
+                RefListCreationMode.MustAlreadyExist => await CreateUserAsync(),
+
+                RefListCreationMode.CreateNewButLinkIfExist when foundUser is not null => await LinkUserAsync(),
+                RefListCreationMode.CreateNewButLinkIfExist => await CreateUserAsync(),
+
+                _ => throw new InvalidOperationException($"Unsupported creation mode: {creationMode}")
+            };
         }

This keeps CreateOrLinkPersonEntityAsync’s default behaviour (“create new person”) aligned with the user creation logic and prevents NotImplementedException / InvalidOperationException from leaking to callers in normal configuration scenarios.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between daf1ddf and 8f55ab7.

⛔ Files ignored due to path filters (2)
  • shesha-core/test/Shesha.Tests/Otp/OtpManager_Tests.cs is excluded by none and included by none
  • shesha-core/test/Shesha.Tests/Otp/PasswordGenerator_Tests.cs is excluded by none and included by none
📒 Files selected for processing (33)
  • shesha-core/src/Shesha.Application/Authorization/Settings/AuthorizationSettingsAppService.cs (1 hunks)
  • shesha-core/src/Shesha.Application/Authorization/Settings/Dto/AuthorizationSettingsDto.cs (3 hunks)
  • shesha-core/src/Shesha.Application/Notifications/NotificationTemplateProcessor.cs (1 hunks)
  • shesha-core/src/Shesha.Application/Otp/Configuration/IOtpSettings.cs (0 hunks)
  • shesha-core/src/Shesha.Application/Otp/Configuration/OtpSettings.cs (0 hunks)
  • shesha-core/src/Shesha.Application/Otp/OtpAppService.cs (3 hunks)
  • shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs (1 hunks)
  • shesha-core/src/Shesha.Application/Otp/OtpManager.cs (6 hunks)
  • shesha-core/src/Shesha.Application/Persons/PersonAccountDto.cs (0 hunks)
  • shesha-core/src/Shesha.Application/SecurityQuestions/QuestionAnswersAppService.cs (3 hunks)
  • shesha-core/src/Shesha.Application/ShaRoleAppointedPersons/Dto/ShaRoleAppointedPersonMapProfile.cs (1 hunks)
  • shesha-core/src/Shesha.Application/Shesha.Application.csproj (2 hunks)
  • shesha-core/src/Shesha.Application/SheshaApplicationModule.cs (4 hunks)
  • shesha-core/src/Shesha.Application/UserManagements/Configurations/IUserManagementSettings.cs (0 hunks)
  • shesha-core/src/Shesha.Application/UserManagements/Configurations/UserManagementSettingNames.cs (0 hunks)
  • shesha-core/src/Shesha.Application/UserManagements/Configurations/UserManagementSettings.cs (0 hunks)
  • shesha-core/src/Shesha.Application/UserManagements/UserManagementAppService.cs (3 hunks)
  • shesha-core/src/Shesha.Application/Users/UserAppService.cs (11 hunks)
  • shesha-core/src/Shesha.Framework/Authorization/Users/UserManager.cs (6 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/FrontendApplicationRedirectsSettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/IFrontendSettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/IPasswordComplexitySettings.cs (0 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/DefaultAuthenticationSettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/GeneralFrontendSecuritySettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/IUserManagementSettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/RefListCreationMode.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettingNames.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/ISecuritySettings.cs (0 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/SecuritySettings.cs (0 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/SheshaSettingNames.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Domain/Enums/SupportedRegistrationMethods.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/SheshaFrameworkModule.cs (3 hunks)
💤 Files with no reviewable changes (9)
  • shesha-core/src/Shesha.Application/UserManagements/Configurations/UserManagementSettings.cs
  • shesha-core/src/Shesha.Framework/Configuration/IPasswordComplexitySettings.cs
  • shesha-core/src/Shesha.Application/Persons/PersonAccountDto.cs
  • shesha-core/src/Shesha.Application/UserManagements/Configurations/IUserManagementSettings.cs
  • shesha-core/src/Shesha.Application/UserManagements/Configurations/UserManagementSettingNames.cs
  • shesha-core/src/Shesha.Framework/Configuration/Security/ISecuritySettings.cs
  • shesha-core/src/Shesha.Framework/Configuration/Security/SecuritySettings.cs
  • shesha-core/src/Shesha.Application/Otp/Configuration/IOtpSettings.cs
  • shesha-core/src/Shesha.Application/Otp/Configuration/OtpSettings.cs
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-05T17:11:17.267Z
Learnt from: teboho
Repo: shesha-io/shesha-framework PR: 3678
File: shesha-core/src/Shesha.Application/Otp/Configuration/OtpDefaults.cs:14-15
Timestamp: 2025-08-05T17:11:17.267Z
Learning: In the Shesha framework, the DefaultEmailBodyTemplate in OtpDefaults.cs contains a hard-coded localhost URL by design. This serves as a default that gets updated/overridden in production environments through their existing configuration management process.

Applied to files:

  • shesha-core/src/Shesha.Application/Notifications/NotificationTemplateProcessor.cs
  • shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs
  • shesha-core/src/Shesha.Application/Otp/OtpManager.cs
  • shesha-core/src/Shesha.Application/Otp/OtpAppService.cs
  • shesha-core/src/Shesha.Framework/Configuration/SheshaSettingNames.cs
  • shesha-core/src/Shesha.Framework/SheshaFrameworkModule.cs
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/DefaultAuthenticationSettings.cs
  • shesha-core/src/Shesha.Application/SheshaApplicationModule.cs
📚 Learning: 2025-10-25T09:24:59.417Z
Learnt from: teboho
Repo: shesha-io/shesha-framework PR: 4063
File: shesha-core/src/Shesha.Web.Host/appsettings.Docker.json:3-3
Timestamp: 2025-10-25T09:24:59.417Z
Learning: In the shesha-framework repository, for Docker-specific configuration files like appsettings.Docker.json used for local development, hardcoded credentials are acceptable for plug-and-play developer experience.

Applied to files:

  • shesha-core/src/Shesha.Framework/SheshaFrameworkModule.cs
🔇 Additional comments (26)
shesha-core/src/Shesha.Application/Authorization/Settings/Dto/AuthorizationSettingsDto.cs (1)

67-70: LGTM!

The new AutoLogoffAfterInactivity boolean property complements the existing AutoLogoffTimeout integer, providing a clear toggle for the auto-logoff feature.

shesha-core/src/Shesha.Application/SheshaApplicationModule.cs (1)

154-154: LGTM!

The service registration follows the existing patterns and uses the appropriate transient lifecycle.

shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/RefListCreationMode.cs (1)

12-38: LGTM!

The enum is well-designed with clear documentation for each creation mode. The ReferenceList attribute properly registers it for framework use.

shesha-core/src/Shesha.Framework/Domain/Enums/SupportedRegistrationMethods.cs (3)

17-17: LGTM - Clarified display name.

The display name change from "Email Address" to "Email OTP" better clarifies the registration method involves OTP verification, improving user understanding.


22-22: LGTM - Clarified display name.

The display name change from "Mobile Number" to "Mobile OTP" better clarifies the registration method involves OTP verification, improving user understanding.


29-33: LGTM - New registration method added.

The addition of EmailLink = 5 provides an alternative email-based registration method using verification links instead of OTP codes, expanding the available authentication options.

shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs (1)

10-15: LGTM - Dependency updated to consolidated settings.

The constructor correctly migrates from IOtpSettings to IUserManagementSettings, aligning with the PR's consolidation objective.

shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettingNames.cs (1)

1-9: LGTM - Clean constants definition.

The UserManagementSettingNames class provides standardized setting name keys for the consolidated user management configuration surface. The implementation is clean and follows established patterns.

shesha-core/src/Shesha.Application/Otp/OtpManager.cs (5)

21-30: LGTM - Dependency updated to consolidated settings.

The constructor correctly migrates from IOtpSettings to IUserManagementSettings, maintaining the same functionality while aligning with the PR's consolidation objective.


40-40: LGTM - Settings retrieval path updated.

The settings retrieval correctly uses _userManagementSettings.DefaultAuthentication.GetValueAsync(), consistent with the configuration consolidation.


93-93: LGTM - Settings retrieval path updated.

The settings retrieval correctly uses _userManagementSettings.DefaultAuthentication.GetValueAsync(), consistent with the configuration consolidation.


165-165: LGTM - Settings retrieval path updated.

The settings retrieval correctly uses _userManagementSettings.DefaultAuthentication.GetValueAsync(), consistent with the configuration consolidation.


189-189: LGTM - Settings retrieval path updated.

The settings retrieval correctly uses _userManagementSettings.DefaultAuthentication.GetValueAsync(), consistent with the configuration consolidation.

shesha-core/src/Shesha.Application/SecurityQuestions/QuestionAnswersAppService.cs (2)

38-38: [rewritten comment]
[classification tag]


18-26: LGTM - Dependency updated to consolidated settings.

The service shows correct injection of IUserManagementSettings in the constructor. However, verification of the ResetPasswordViaSecurityQuestionsNumQuestionsAllowed property availability in the migrated settings could not be completed due to repository access limitations.

shesha-core/src/Shesha.Application/Notifications/NotificationTemplateProcessor.cs (1)

97-104: Breaking change: Property type changed from string to complex object.

The PublicUrl property now returns FrontendApplicationRedirectsSettings? instead of string?, which is a breaking change for any mustache templates or code that accesses this property. Template expressions like {{frontEndApps.myApp.PublicUrl}} will now render an object representation instead of a URL string.

Consider either:

  1. Renaming the property to ApplicationRedirectsSettings to reflect its actual type, OR
  2. Adding a separate BaseUrl property that returns string? for backward compatibility

Verify that all mustache templates and notification templates using PublicUrl are updated to access the nested properties (e.g., {{frontEndApps.myApp.PublicUrl.BaseUrl}}), or confirm that backward compatibility measures were implemented.

shesha-core/src/Shesha.Framework/Configuration/IFrontendSettings.cs (1)

23-27: Unable to verify breaking change claim due to repository access limitations.

The breaking change assertion about removal of DefaultUrl and PublicUrl properties cannot be verified without access to the repository history and codebase search capabilities. To properly assess this issue, provide:

  • Git commit or diff showing the removed properties from IFrontendSettings.cs
  • Confirmation that these properties existed in the previous version
  • Evidence of where references to these properties have been migrated or updated
shesha-core/src/Shesha.Framework/Configuration/SheshaSettingNames.cs (2)

25-29: LGTM! New setting name constants added.

The new constants SuccessLoginRedirectPath, ApplicationRedirects, and DefaultAuthenticationSettings follow the established naming conventions and support the authentication settings consolidation.


19-21: Verify breaking change: renamed setting name constants.

Renaming DefaultUrlBaseUrl and PublicUrlDefaultPath changes the underlying string values from "Shesha.DefaultUrl" to "Shesha.BaseUrl" and "Shesha.PublicUrl" to "Shesha.DefaultPath". This may affect persisted settings or external consumers referencing the old names. Ensure any config migrations or deprecation handling is in place.

shesha-core/src/Shesha.Application/Users/UserAppService.cs (2)

56-83: LGTM! Dependency injection properly wired.

The IUserManagementSettings is correctly injected and stored in a private field, following the established pattern.


289-304: LGTM! Settings access migrated correctly.

The retrieval of authentication settings from _userManagementSettings.DefaultAuthentication and subsequent use for feature toggles is correctly implemented.

shesha-core/src/Shesha.Framework/SheshaFrameworkModule.cs (2)

131-136: LGTM! Security settings simplified.

The SecuritySettings default now only configures DefaultEndpointAccess, which aligns with moving password/lockout settings to the consolidated IUserManagementSettings interface.


144-149: Consider adding DefaultPath to the default initialization.

FrontendApplicationRedirectsSettings has four properties, but only three are initialized here. The DefaultPath property is missing from the defaults. If it's intentionally omitted, this is fine; otherwise, consider adding a sensible default.

shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/IUserManagementSettings.cs (1)

7-30: Well-structured settings interface consolidation.

The interface cleanly consolidates authentication-related settings into a single access point. The use of IsClientSpecific = true on all settings is appropriate for tenant-specific configurations, and the editor form names follow a consistent naming convention.

shesha-core/src/Shesha.Framework/Authorization/Users/UserManager.cs (1)

351-368: LGTM for async initialization.

The async version correctly reads settings from DefaultAuthentication and applies appropriate null-coalescing defaults for lockout and password complexity options.

shesha-core/src/Shesha.Application/UserManagements/UserManagementAppService.cs (1)

487-523: Dynamic default role assignment logic looks sound; just be mindful of potential duplicate role assignments

The AssignDefaultRolesAsync helper correctly:

  • Extracts the person Id via reflection, which works for any Person‑derived dynamic type.
  • Skips null/empty role ids.
  • Checks _roleAppointedPersonRepository for an existing appointment before calling _roleAppointedPersonService.CreateAsync, avoiding duplicates.

This is generally solid. Two minor considerations:

  • If _roleAppointedPersonService.CreateAsync has side effects or heavy logic, you might want to refactor to a batch‑oriented service in future, but that’s an optimisation, not a blocker here.
  • If there is a unique constraint at the database level on (RoleId, PersonId), this pattern is safe from race conditions in single‑request flows but can still theoretically race under concurrent registrations for the same person; the DB constraint would be the final guard.

No changes strictly required now; just keep these aspects in mind.

Comment thread shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs
Comment thread shesha-core/src/Shesha.Application/Shesha.Application.csproj Outdated
ntuthukomsane-boxfusion and others added 13 commits December 9, 2025 11:10
…nd/RefListCreationMode.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…nd/UserManagementSettings.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…nd/UserManagementSettings.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…AuthorizationSettingsDto.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/DefaultAuthenticationSettings.cs (2)

30-34: Empty XML documentation comment for UserEmailAsUsername.

The <summary> tag is empty. Add a meaningful description.

         /// <summary>
-        /// 
+        /// Specifies whether the user's email address should be used as their username.
         /// </summary>
         [Display(Name = "Use email as username")]
         public bool UserEmailAsUsername { get; set; }

106-137: Non-nullable string properties may cause NullReferenceException.

Alphabet, DefaultSubjectTemplate, DefaultBodyTemplate, DefaultEmailSubjectTemplate, and DefaultEmailBodyTemplate are declared as non-nullable string but have no default values. When settings are deserialized without these values, they will be null, potentially causing NREs.

Either make them nullable or provide default values:

-        public string Alphabet { get; set; }
+        public string Alphabet { get; set; } = string.Empty;
         ...
-        public string DefaultSubjectTemplate { get; set; }
+        public string DefaultSubjectTemplate { get; set; } = string.Empty;
         ...
-        public string DefaultBodyTemplate { get; set; }
+        public string DefaultBodyTemplate { get; set; } = string.Empty;
         ...
-        public string DefaultEmailSubjectTemplate { get; set; }
+        public string DefaultEmailSubjectTemplate { get; set; } = string.Empty;
         ...
-        public string DefaultEmailBodyTemplate { get; set; }
+        public string DefaultEmailBodyTemplate { get; set; } = string.Empty;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26c55cd and 69cbae0.

📒 Files selected for processing (6)
  • shesha-core/src/Shesha.Application/Authorization/Settings/AuthorizationSettingsAppService.cs (1 hunks)
  • shesha-core/src/Shesha.Application/Authorization/Settings/Dto/AuthorizationSettingsDto.cs (3 hunks)
  • shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs (1 hunks)
  • shesha-core/src/Shesha.Application/ShaRoleAppointedPersons/Dto/ShaRoleAppointedPersonMapProfile.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/DefaultAuthenticationSettings.cs (1 hunks)
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettings.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-05T17:11:17.267Z
Learnt from: teboho
Repo: shesha-io/shesha-framework PR: 3678
File: shesha-core/src/Shesha.Application/Otp/Configuration/OtpDefaults.cs:14-15
Timestamp: 2025-08-05T17:11:17.267Z
Learning: In the Shesha framework, the DefaultEmailBodyTemplate in OtpDefaults.cs contains a hard-coded localhost URL by design. This serves as a default that gets updated/overridden in production environments through their existing configuration management process.

Applied to files:

  • shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs
  • shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/DefaultAuthenticationSettings.cs
🔇 Additional comments (4)
shesha-core/src/Shesha.Application/ShaRoleAppointedPersons/Dto/ShaRoleAppointedPersonMapProfile.cs (1)

13-17: RoleId may no longer be explicitly mapped on the DTO

The current CreateMap<ShaRoleAppointedPerson, ShaRoleAppointedPersonDto>() only configures Person. If the previous version explicitly mapped RoleId from e.Role.Id, this mapping is no longer present. Verify whether:

  1. ShaRoleAppointedPersonDto has a RoleId property and whether it is still being populated
  2. ShaRoleAppointedPerson exposes Role navigation (so AutoMapper flattening could apply) or only a scalar RoleId
  3. Any code depends on RoleId being populated on the DTO

If consumers require RoleId and it is not being auto-mapped via conventions, restore the mapping alongside the Person configuration.

shesha-core/src/Shesha.Framework/Configuration/Security/Frontend/UserManagementSettings.cs (1)

9-48: LGTM! All previous review comments have been addressed.

The class is well-structured with proper XML documentation, nullable annotations where appropriate, and default initialization for DefaultRoles. Good use of Display attributes for UI binding.

shesha-core/src/Shesha.Application/Otp/OtpGenerator.cs (1)

17-31: LGTM! Previous optimization feedback addressed.

The settings are now retrieved once and cached in authSettings. Good use of StringBuilder for efficient PIN generation.

Note: Consider adding a null/empty guard for alphabet to prevent IndexOutOfRangeException if the setting is not configured:

             var authSettings = _userManagementSettings.DefaultAuthentication.GetValue();
             var alphabet = authSettings.Alphabet;
             var passwordLength = authSettings.PasswordLength;
+
+            if (string.IsNullOrEmpty(alphabet))
+                throw new InvalidOperationException("OTP alphabet is not configured.");
 
             for (int i = 0; i < passwordLength; i++)
shesha-core/src/Shesha.Application/Authorization/Settings/Dto/AuthorizationSettingsDto.cs (1)

1-96: LGTM!

The DTO is well-structured with proper XML documentation. The new AutoLogoffAfterInactivity property and Display attributes are appropriately added. Previous feedback about unused imports has been addressed.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69cbae0 and e542efc.

📒 Files selected for processing (2)
  • shesha-core/src/Shesha.Application/Authorization/Settings/AuthorizationSettingsAppService.cs (1 hunks)
  • shesha-core/src/Shesha.Application/ShaRoleAppointedPersons/Dto/ShaRoleAppointedPersonMapProfile.cs (1 hunks)
🔇 Additional comments (2)
shesha-core/src/Shesha.Application/ShaRoleAppointedPersons/Dto/ShaRoleAppointedPersonMapProfile.cs (1)

23-27: LGTM!

The Entity→DTO mapping correctly transforms the Person entity to an EntityReferenceDto<Guid?> with display name and type information. The null check is appropriate.

shesha-core/src/Shesha.Application/Authorization/Settings/AuthorizationSettingsAppService.cs (1)

64-68: Verify whether GeneralFrontendSecuritySettings has other properties that should be preserved.

This code creates a new GeneralFrontendSecuritySettings object with only two properties from the DTO (AutoLogoffAfterInactivity and AutoLogoffTimeout). If GeneralFrontendSecuritySettings has additional properties not included here, they will be lost when this object is saved. Check the class definition to confirm all properties are being set, or consider using a merge/update pattern similar to the fix applied to DefaultAuthenticationSettings.

…orizationSettingsAppService.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…tionRedirectsSettings.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@shesha-core/src/Shesha.Framework/Configuration/FrontendApplicationRedirectsSettings.cs`:
- Line 32: Update the Display attribute description to fix the typo: change
"authentications" to "authentication" in the Description string on the Display
attribute applied to the property annotated with Name = "Not authenticated
redirect path" in FrontendApplicationRedirectsSettings (the Display attribute
contains the Description to update).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@shesha-core/src/Shesha.Framework/Authorization/Users/UserManager.cs`:
- Around line 287-293: The code adds a ValidationResult and immediately calls
validationResults.ThrowValidationExceptionIfAny(existing logger L), so the
subsequent throw new InvalidOperationException(message) is unreachable; remove
that redundant throw (delete the throw new InvalidOperationException(message)
line) or, if you want an explicit safety net, replace it with a clear comment or
a Debug/Trace.Fail call after ThrowValidationExceptionIfAny to document the
intent; locate symbols: existingUser, validationResults,
ThrowValidationExceptionIfAny and message in UserManager.cs to apply the change.

Comment thread shesha-core/src/Shesha.Framework/Authorization/Users/UserManager.cs
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@shesha-core/src/Shesha.Framework/Migrations/M20251215130900.cs`:
- Around line 14-316: The migration currently transforms Shesha.UserManagement
(user_mgmt_cursor) and Shesha.Security (security_cursor) before processing
OTP/DefaultAuthentication (otp_cursor), which causes fields like
requireEmailVerification, userEmailAsUsername, supportedRegistrationMethods and
resetPassword* to be lost; fix by reordering the SQL blocks so the otp_cursor
section (Step 3 that reads `@OldOtpValue`, `@ContextUserManagementValue`,
`@ContextSecurityValue` and builds `@NewDefaultAuthValue` / inserts/updates
DefaultAuthenticationSettings) runs before the user_mgmt_cursor (Step 1 that
updates Shesha.UserManagement) and security_cursor (Step 2 that updates
Shesha.Security), and apply the same reorder in the PostgreSQL branch so
otp-based merging reads original JSON values rather than the already-transformed
structures.
- Around line 84-91: The variables `@AutoLogoffTimeout`,
`@UseResetPasswordViaEmailLink`, `@ResetPasswordEmailLinkLifetime`,
`@UseResetPasswordViaSmsOtp`, `@ResetPasswordSmsOtpLifetime`,
`@UseResetPasswordViaSecurityQuestions` and
`@ResetPasswordViaSecurityQuestionsNumQuestionsAllowed` are declared in the outer
scope but only assigned inside the security cursor and never used after the
cursor closes; remove these outer declarations and instead declare any needed
copies inside the cursor loop (or inline the assignments into loop-local
variables) so there are no dead outer-scope variables, and delete or refactor
the assignments on lines that set those names (currently in the cursor body) to
use the new loop-local variable names.

Comment thread shesha-core/src/Shesha.Framework/Migrations/M20251215130900.cs Outdated
Comment thread shesha-core/src/Shesha.Framework/Migrations/M20251215130900.cs Outdated
…nd/DefaultAuthenticationSettings.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…entAppService.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…tionRedirectsSettings.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…er.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@IvanIlyichev IvanIlyichev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ntuthukomsane-boxfusion. Please address the following:

  1. Review all inline comments.
  2. Ensure settings are properly organized and behave as intended. For example:
  • Enable authentication with local username/password? is disabled by default and not actually used by the application.
  • It is unclear why this setting is placed under Account creation.
  • Account creation and New User Registration appear to be redundant. These sections should likely be merged and moved outside of Authentication.
  • The General group currently contains only session-related settings; renaming it to User Session would be more appropriate.

The current structure of the Default Authentication settings group mirrors the layout of the login form, which is not a logical approach. Instead, we should extract distinct functional blocks. This will allow for more graceful extensibility and result in a more intuitive UI for administrators. For instance, OTP functionality—which is expected to be enhanced and widely used across various modules for confirmations—should be treated as a standalone block.

Image

Comment thread shesha-core/src/Shesha.Framework/Authorization/Users/UserManager.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants