diff --git a/src/Admin/AdminConsole/Controllers/OrganizationsController.cs b/src/Admin/AdminConsole/Controllers/OrganizationsController.cs index fdb4961d9b..3cb51cffa4 100644 --- a/src/Admin/AdminConsole/Controllers/OrganizationsController.cs +++ b/src/Admin/AdminConsole/Controllers/OrganizationsController.cs @@ -462,6 +462,7 @@ public class OrganizationsController : Controller organization.UsersGetPremium = model.UsersGetPremium; organization.UseSecretsManager = model.UseSecretsManager; organization.UseRiskInsights = model.UseRiskInsights; + organization.UseOrganizationDomains = model.UseOrganizationDomains; //secrets organization.SmSeats = model.SmSeats; diff --git a/src/Admin/AdminConsole/Models/OrganizationEditModel.cs b/src/Admin/AdminConsole/Models/OrganizationEditModel.cs index 1d23afd491..a3525c5fbe 100644 --- a/src/Admin/AdminConsole/Models/OrganizationEditModel.cs +++ b/src/Admin/AdminConsole/Models/OrganizationEditModel.cs @@ -76,6 +76,7 @@ public class OrganizationEditModel : OrganizationViewModel MaxCollections = org.MaxCollections; UsePolicies = org.UsePolicies; UseSso = org.UseSso; + UseOrganizationDomains = org.UseOrganizationDomains; UseKeyConnector = org.UseKeyConnector; UseScim = org.UseScim; UseGroups = org.UseGroups; @@ -132,6 +133,8 @@ public class OrganizationEditModel : OrganizationViewModel public bool UsePolicies { get; set; } [Display(Name = "SSO")] public bool UseSso { get; set; } + [Display(Name = "Use Organization Domains")] + public bool UseOrganizationDomains { get; set; } [Display(Name = "Key Connector with Customer Encryption")] public bool UseKeyConnector { get; set; } [Display(Name = "Groups")] @@ -212,6 +215,7 @@ public class OrganizationEditModel : OrganizationViewModel Has2fa = p.Has2fa, HasApi = p.HasApi, HasSso = p.HasSso, + HasOrganizationDomains = p.HasOrganizationDomains, HasKeyConnector = p.HasKeyConnector, HasScim = p.HasScim, HasResetPassword = p.HasResetPassword, @@ -285,6 +289,7 @@ public class OrganizationEditModel : OrganizationViewModel existingOrganization.MaxCollections = MaxCollections; existingOrganization.UsePolicies = UsePolicies; existingOrganization.UseSso = UseSso; + existingOrganization.UseOrganizationDomains = UseOrganizationDomains; existingOrganization.UseKeyConnector = UseKeyConnector; existingOrganization.UseScim = UseScim; existingOrganization.UseGroups = UseGroups; diff --git a/src/Admin/AdminConsole/Views/Shared/_OrganizationForm.cshtml b/src/Admin/AdminConsole/Views/Shared/_OrganizationForm.cshtml index aeff65c900..38940d110f 100644 --- a/src/Admin/AdminConsole/Views/Shared/_OrganizationForm.cshtml +++ b/src/Admin/AdminConsole/Views/Shared/_OrganizationForm.cshtml @@ -122,6 +122,10 @@ +
+ + +
diff --git a/src/Admin/AdminConsole/Views/Shared/_OrganizationFormScripts.cshtml b/src/Admin/AdminConsole/Views/Shared/_OrganizationFormScripts.cshtml index 98d4c0d900..0ce25c700f 100644 --- a/src/Admin/AdminConsole/Views/Shared/_OrganizationFormScripts.cshtml +++ b/src/Admin/AdminConsole/Views/Shared/_OrganizationFormScripts.cshtml @@ -69,6 +69,7 @@ document.getElementById('@(nameof(Model.UseGroups))').checked = plan.hasGroups; document.getElementById('@(nameof(Model.UsePolicies))').checked = plan.hasPolicies; document.getElementById('@(nameof(Model.UseSso))').checked = plan.hasSso; + document.getElementById('@(nameof(Model.UseOrganizationDomains))').checked = hasOrganizationDomains; document.getElementById('@(nameof(Model.UseScim))').checked = plan.hasScim; document.getElementById('@(nameof(Model.UseDirectory))').checked = plan.hasDirectory; document.getElementById('@(nameof(Model.UseEvents))').checked = plan.hasEvents; diff --git a/src/Api/AdminConsole/Models/Response/Organizations/OrganizationResponseModel.cs b/src/Api/AdminConsole/Models/Response/Organizations/OrganizationResponseModel.cs index 4dc4a4ec55..11a05a805f 100644 --- a/src/Api/AdminConsole/Models/Response/Organizations/OrganizationResponseModel.cs +++ b/src/Api/AdminConsole/Models/Response/Organizations/OrganizationResponseModel.cs @@ -40,6 +40,7 @@ public class OrganizationResponseModel : ResponseModel MaxStorageGb = organization.MaxStorageGb; UsePolicies = organization.UsePolicies; UseSso = organization.UseSso; + UseOrganizationDomains = organization.UseOrganizationDomains; UseKeyConnector = organization.UseKeyConnector; UseScim = organization.UseScim; UseGroups = organization.UseGroups; @@ -86,6 +87,7 @@ public class OrganizationResponseModel : ResponseModel public short? MaxStorageGb { get; set; } public bool UsePolicies { get; set; } public bool UseSso { get; set; } + public bool UseOrganizationDomains { get; set; } public bool UseKeyConnector { get; set; } public bool UseScim { get; set; } public bool UseGroups { get; set; } diff --git a/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs b/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs index 3a901f11c4..f36dd82abd 100644 --- a/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs +++ b/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs @@ -25,6 +25,7 @@ public class ProfileOrganizationResponseModel : ResponseModel Name = organization.Name; UsePolicies = organization.UsePolicies; UseSso = organization.UseSso; + UseOrganizationDomains = organization.UseOrganizationDomains; UseKeyConnector = organization.UseKeyConnector; UseScim = organization.UseScim; UseGroups = organization.UseGroups; @@ -86,6 +87,7 @@ public class ProfileOrganizationResponseModel : ResponseModel public string Name { get; set; } public bool UsePolicies { get; set; } public bool UseSso { get; set; } + public bool UseOrganizationDomains { get; set; } public bool UseKeyConnector { get; set; } public bool UseScim { get; set; } public bool UseGroups { get; set; } diff --git a/src/Api/AdminConsole/Models/Response/ProfileProviderOrganizationResponseModel.cs b/src/Api/AdminConsole/Models/Response/ProfileProviderOrganizationResponseModel.cs index d31cb5a77a..10002486bc 100644 --- a/src/Api/AdminConsole/Models/Response/ProfileProviderOrganizationResponseModel.cs +++ b/src/Api/AdminConsole/Models/Response/ProfileProviderOrganizationResponseModel.cs @@ -15,6 +15,7 @@ public class ProfileProviderOrganizationResponseModel : ProfileOrganizationRespo Name = organization.Name; UsePolicies = organization.UsePolicies; UseSso = organization.UseSso; + UseOrganizationDomains = organization.UseOrganizationDomains; UseKeyConnector = organization.UseKeyConnector; UseScim = organization.UseScim; UseGroups = organization.UseGroups; diff --git a/src/Api/Models/Response/PlanResponseModel.cs b/src/Api/Models/Response/PlanResponseModel.cs index 74bcb59661..f48a06b4ec 100644 --- a/src/Api/Models/Response/PlanResponseModel.cs +++ b/src/Api/Models/Response/PlanResponseModel.cs @@ -32,6 +32,7 @@ public class PlanResponseModel : ResponseModel HasTotp = plan.HasTotp; Has2fa = plan.Has2fa; HasSso = plan.HasSso; + HasOrganizationDomains = plan.HasOrganizationDomains; HasResetPassword = plan.HasResetPassword; UsersGetPremium = plan.UsersGetPremium; UpgradeSortOrder = plan.UpgradeSortOrder; @@ -71,6 +72,7 @@ public class PlanResponseModel : ResponseModel public bool Has2fa { get; set; } public bool HasApi { get; set; } public bool HasSso { get; set; } + public bool HasOrganizationDomains { get; set; } public bool HasResetPassword { get; set; } public bool UsersGetPremium { get; set; } diff --git a/src/Core/AdminConsole/Entities/Organization.cs b/src/Core/AdminConsole/Entities/Organization.cs index 54661e22a7..ad0e37e1e5 100644 --- a/src/Core/AdminConsole/Entities/Organization.cs +++ b/src/Core/AdminConsole/Entities/Organization.cs @@ -51,6 +51,7 @@ public class Organization : ITableObject, IStorableSubscriber, IRevisable, public short? MaxCollections { get; set; } public bool UsePolicies { get; set; } public bool UseSso { get; set; } + public bool UseOrganizationDomains { get; set; } public bool UseKeyConnector { get; set; } public bool UseScim { get; set; } public bool UseGroups { get; set; } diff --git a/src/Core/AdminConsole/Models/Data/Organizations/OrganizationAbility.cs b/src/Core/AdminConsole/Models/Data/Organizations/OrganizationAbility.cs index 62914f6fa8..888130d700 100644 --- a/src/Core/AdminConsole/Models/Data/Organizations/OrganizationAbility.cs +++ b/src/Core/AdminConsole/Models/Data/Organizations/OrganizationAbility.cs @@ -26,6 +26,7 @@ public class OrganizationAbility LimitItemDeletion = organization.LimitItemDeletion; AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems; UseRiskInsights = organization.UseRiskInsights; + UseOrganizationDomains = organization.UseOrganizationDomains; } public Guid Id { get; set; } @@ -45,4 +46,5 @@ public class OrganizationAbility public bool LimitItemDeletion { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool UseRiskInsights { get; set; } + public bool UseOrganizationDomains { get; set; } } diff --git a/src/Core/AdminConsole/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs b/src/Core/AdminConsole/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs index 18d68af220..eba9634bda 100644 --- a/src/Core/AdminConsole/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs +++ b/src/Core/AdminConsole/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs @@ -14,6 +14,7 @@ public class OrganizationUserOrganizationDetails public string Name { get; set; } public bool UsePolicies { get; set; } public bool UseSso { get; set; } + public bool UseOrganizationDomains { get; set; } public bool UseKeyConnector { get; set; } public bool UseScim { get; set; } public bool UseGroups { get; set; } diff --git a/src/Core/AdminConsole/Models/Data/Provider/ProviderUserOrganizationDetails.cs b/src/Core/AdminConsole/Models/Data/Provider/ProviderUserOrganizationDetails.cs index 57f176666a..b093bfd161 100644 --- a/src/Core/AdminConsole/Models/Data/Provider/ProviderUserOrganizationDetails.cs +++ b/src/Core/AdminConsole/Models/Data/Provider/ProviderUserOrganizationDetails.cs @@ -45,5 +45,6 @@ public class ProviderUserOrganizationDetails public bool LimitItemDeletion { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool UseRiskInsights { get; set; } + public bool UseOrganizationDomains { get; set; } public ProviderType ProviderType { get; set; } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs index 4ff6b87443..4358d5690e 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs @@ -24,9 +24,7 @@ public class GetOrganizationUsersManagementStatusQuery : IGetOrganizationUsersMa // Users can only be managed by an Organization that is enabled and can have organization domains var organizationAbility = await _applicationCacheService.GetOrganizationAbilityAsync(organizationId); - // TODO: Replace "UseSso" with a new organization ability like "UseOrganizationDomains" (PM-11622). - // Verified domains were tied to SSO, so we currently check the "UseSso" organization ability. - if (organizationAbility is { Enabled: true, UseSso: true }) + if (organizationAbility is { Enabled: true, UseOrganizationDomains: true }) { // Get all organization users with claimed domains by the organization var organizationUsersWithClaimedDomain = await _organizationUserRepository.GetManyByOrganizationWithClaimedDomainsAsync(organizationId); diff --git a/src/Core/AdminConsole/OrganizationFeatures/Organizations/CloudOrganizationSignUpCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/Organizations/CloudOrganizationSignUpCommand.cs index 60e090de2a..c5c8c7cff2 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/Organizations/CloudOrganizationSignUpCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/Organizations/CloudOrganizationSignUpCommand.cs @@ -82,6 +82,7 @@ public class CloudOrganizationSignUpCommand( (short?)null : (short)(plan.PasswordManager.BaseStorageGb.Value + signup.AdditionalStorageGb), UsePolicies = plan.HasPolicies, UseSso = plan.HasSso, + UseOrganizationDomains = plan.HasOrganizationDomains, UseGroups = plan.HasGroups, UseEvents = plan.HasEvents, UseDirectory = plan.HasDirectory, diff --git a/src/Core/AdminConsole/Services/Implementations/OrganizationService.cs b/src/Core/AdminConsole/Services/Implementations/OrganizationService.cs index 772b407951..c5f6f7a1dd 100644 --- a/src/Core/AdminConsole/Services/Implementations/OrganizationService.cs +++ b/src/Core/AdminConsole/Services/Implementations/OrganizationService.cs @@ -459,6 +459,7 @@ public class OrganizationService : IOrganizationService MaxStorageGb = 1, UsePolicies = plan.HasPolicies, UseSso = plan.HasSso, + UseOrganizationDomains = plan.HasOrganizationDomains, UseGroups = plan.HasGroups, UseEvents = plan.HasEvents, UseDirectory = plan.HasDirectory, diff --git a/src/Core/Billing/Models/StaticStore/Plan.cs b/src/Core/Billing/Models/StaticStore/Plan.cs index 5dbcd7ddc4..1ce5810011 100644 --- a/src/Core/Billing/Models/StaticStore/Plan.cs +++ b/src/Core/Billing/Models/StaticStore/Plan.cs @@ -24,6 +24,7 @@ public abstract record Plan public bool Has2fa { get; protected init; } public bool HasApi { get; protected init; } public bool HasSso { get; protected init; } + public bool HasOrganizationDomains { get; protected init; } public bool HasKeyConnector { get; protected init; } public bool HasScim { get; protected init; } public bool HasResetPassword { get; protected init; } diff --git a/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs b/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs index 09b766e885..cb37e478f7 100644 --- a/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs @@ -263,6 +263,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand organization.Use2fa = newPlan.Has2fa; organization.UseApi = newPlan.HasApi; organization.UseSso = newPlan.HasSso; + organization.UseOrganizationDomains = newPlan.HasOrganizationDomains; organization.UseKeyConnector = newPlan.HasKeyConnector; organization.UseScim = newPlan.HasScim; organization.UseResetPassword = newPlan.HasResetPassword; diff --git a/src/Core/Resources/SharedResources.en.resx b/src/Core/Resources/SharedResources.en.resx index 3ef0b54efe..90a791222f 100644 --- a/src/Core/Resources/SharedResources.en.resx +++ b/src/Core/Resources/SharedResources.en.resx @@ -1,17 +1,17 @@ - + - diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index 5076c8282e..4a02c3bfb2 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -1383,9 +1383,7 @@ public class UserService : UserManager, IUserService, IDisposable var organizationsWithVerifiedUserEmailDomain = await _organizationRepository.GetByVerifiedUserEmailDomainAsync(userId); // Organizations must be enabled and able to have verified domains. - // TODO: Replace "UseSso" with a new organization ability like "UseOrganizationDomains" (PM-11622). - // Verified domains were tied to SSO, so we currently check the "UseSso" organization ability. - return organizationsWithVerifiedUserEmailDomain.Where(organization => organization is { Enabled: true, UseSso: true }); + return organizationsWithVerifiedUserEmailDomain.Where(organization => organization is { Enabled: true, UseOrganizationDomains: true }); } /// diff --git a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs index 6fc42b699d..12cbb325e9 100644 --- a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs +++ b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs @@ -106,7 +106,8 @@ public class OrganizationRepository : Repository usersWithClaimedDomain, SutProvider sutProvider) { organization.Enabled = true; - organization.UseSso = true; + organization.UseOrganizationDomains = true; var userIdWithoutClaimedDomain = Guid.NewGuid(); var userIdsToCheck = usersWithClaimedDomain.Select(u => u.Id).Concat(new List { userIdWithoutClaimedDomain }).ToList(); @@ -51,13 +51,13 @@ public class GetOrganizationUsersManagementStatusQueryTests } [Theory, BitAutoData] - public async Task GetUsersOrganizationManagementStatusAsync_WithUseSsoDisabled_ReturnsAllFalse( + public async Task GetUsersOrganizationManagementStatusAsync_WithUseOrganizationDomainsDisabled_ReturnsAllFalse( Organization organization, ICollection usersWithClaimedDomain, SutProvider sutProvider) { organization.Enabled = true; - organization.UseSso = false; + organization.UseOrganizationDomains = false; var userIdWithoutClaimedDomain = Guid.NewGuid(); var userIdsToCheck = usersWithClaimedDomain.Select(u => u.Id).Concat(new List { userIdWithoutClaimedDomain }).ToList(); diff --git a/test/Core.Test/Models/Business/OrganizationLicenseTests.cs b/test/Core.Test/Models/Business/OrganizationLicenseTests.cs index 26945f533e..14bc2209e6 100644 --- a/test/Core.Test/Models/Business/OrganizationLicenseTests.cs +++ b/test/Core.Test/Models/Business/OrganizationLicenseTests.cs @@ -44,6 +44,7 @@ public class OrganizationLicenseTests // These licenses will naturally expire over time, but we still want them to be able to test license.Expires = DateTime.MaxValue; + GenerateLicenseFileJsonString(); var organization = OrganizationLicenseFileFixtures.OrganizationFactory(); var globalSettings = Substitute.For(); globalSettings.Installation.Returns(new GlobalSettings.InstallationSettings @@ -68,6 +69,7 @@ public class OrganizationLicenseTests var license = new OrganizationLicense(organization, null, installationId, licensingService); var result = JsonSerializer.Serialize(license, JsonHelpers.Indented).Replace("\"", "'"); + Console.Out.WriteLine(result); // Put a break after this line, then copy and paste the value of `result` into OrganizationLicenseFileFixtures } } diff --git a/test/Core.Test/Services/UserServiceTests.cs b/test/Core.Test/Services/UserServiceTests.cs index 3158c1595c..c720e6857f 100644 --- a/test/Core.Test/Services/UserServiceTests.cs +++ b/test/Core.Test/Services/UserServiceTests.cs @@ -357,7 +357,7 @@ public class UserServiceTests SutProvider sutProvider, Guid userId, Organization organization) { organization.Enabled = true; - organization.UseSso = true; + organization.UseOrganizationDomains = true; sutProvider.GetDependency() .IsEnabled(FeatureFlagKeys.AccountDeprovisioning) @@ -376,7 +376,7 @@ public class UserServiceTests SutProvider sutProvider, Guid userId, Organization organization) { organization.Enabled = false; - organization.UseSso = true; + organization.UseOrganizationDomains = true; sutProvider.GetDependency() .IsEnabled(FeatureFlagKeys.AccountDeprovisioning) @@ -391,11 +391,11 @@ public class UserServiceTests } [Theory, BitAutoData] - public async Task IsManagedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithOrganizationUseSsoFalse_ReturnsFalse( + public async Task IsManagedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithOrganizationUseOrganizationDomainsFalse_ReturnsFalse( SutProvider sutProvider, Guid userId, Organization organization) { organization.Enabled = true; - organization.UseSso = false; + organization.UseOrganizationDomains = false; sutProvider.GetDependency() .IsEnabled(FeatureFlagKeys.AccountDeprovisioning) diff --git a/util/Migrator/DbScripts/2025-03-24-00_AddUseOrganizationDomainsToOrganization.sql b/util/Migrator/DbScripts/2025-03-24-00_AddUseOrganizationDomainsToOrganization.sql index ca8ab12dec..af57cfeb3e 100644 --- a/util/Migrator/DbScripts/2025-03-24-00_AddUseOrganizationDomainsToOrganization.sql +++ b/util/Migrator/DbScripts/2025-03-24-00_AddUseOrganizationDomainsToOrganization.sql @@ -1,6 +1,6 @@ /* adds new column "UseOrganizationDomains" not nullable with default of 0 */ -ALTER TABLE [dbo].[Organization] ADD [UseOrgnizationDomains] bit NOT NULL CONSTRAINT [DF_Organization_UseOrganizationDomains] default (0) +ALTER TABLE [dbo].[Organization] ADD [UseOrganizationDomains] bit NOT NULL CONSTRAINT [DF_Organization_UseOrganizationDomains] default (0) GO /* add column to Organization_Create*/ diff --git a/util/Migrator/DbScripts/2025-03-24-01_AddUseOrganizationDomainsToViews.sql b/util/Migrator/DbScripts/2025-03-24-01_AddUseOrganizationDomainsToViews.sql index 066a2e26d5..a67ec6a5d7 100644 --- a/util/Migrator/DbScripts/2025-03-24-01_AddUseOrganizationDomainsToViews.sql +++ b/util/Migrator/DbScripts/2025-03-24-01_AddUseOrganizationDomainsToViews.sql @@ -118,3 +118,11 @@ INNER JOIN INNER JOIN [dbo].[Provider] P ON P.[Id] = PU.[ProviderId] GO + +CREATE OR ALTER VIEW [dbo].[OrganizationView] +AS +SELECT + * +FROM + [dbo].[Organization] +GO