1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -05:00
This commit is contained in:
Brandon 2025-03-26 14:27:55 -04:00
parent 4642e2dd9f
commit ebd398c75a
No known key found for this signature in database
GPG Key ID: A0E0EF0B207BA40D
28 changed files with 83 additions and 47 deletions

View File

@ -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;

View File

@ -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;

View File

@ -122,6 +122,10 @@
<input type="checkbox" class="form-check-input" asp-for="UseSso" disabled='@(canEditPlan ? null : "disabled")'>
<label class="form-check-label" asp-for="UseSso"></label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" asp-for="UseOrganizationDomains" disabled='@(canEditPlan ? null : "disabled")'>
<label class="form-check-label" asp-for="UseOrganizationDomains"></label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" asp-for="UseKeyConnector" disabled='@(canEditPlan ? null : "disabled")'>
<label class="form-check-label" asp-for="UseKeyConnector"></label>

View File

@ -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;

View File

@ -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; }

View File

@ -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; }

View File

@ -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;

View File

@ -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; }

View File

@ -51,6 +51,7 @@ public class Organization : ITableObject<Guid>, 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; }

View File

@ -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; }
}

View File

@ -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; }

View File

@ -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; }
}

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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; }

View File

@ -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;

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema

View File

@ -1383,9 +1383,7 @@ public class UserService : UserManager<User>, 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 });
}
/// <inheritdoc cref="IsLegacyUser(string)"/>

View File

@ -106,7 +106,8 @@ public class OrganizationRepository : Repository<Core.AdminConsole.Entities.Orga
LimitCollectionDeletion = e.LimitCollectionDeletion,
LimitItemDeletion = e.LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = e.AllowAdminAccessToAllCollectionItems,
UseRiskInsights = e.UseRiskInsights
UseRiskInsights = e.UseRiskInsights,
UseOrganizationDomains = e.UseOrganizationDomains
}).ToListAsync();
}
}

View File

@ -71,6 +71,7 @@ public class OrganizationUserOrganizationDetailsViewQuery : IQuery<OrganizationU
LimitItemDeletion = o.LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = o.AllowAdminAccessToAllCollectionItems,
UseRiskInsights = o.UseRiskInsights,
UseOrganizationDomains = o.UseOrganizationDomains
};
return query;
}

View File

@ -49,7 +49,8 @@ public class ProviderUserOrganizationDetailsViewQuery : IQuery<ProviderUserOrgan
LimitItemDeletion = x.o.LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = x.o.AllowAdminAccessToAllCollectionItems,
UseRiskInsights = x.o.UseRiskInsights,
ProviderType = x.p.Type
ProviderType = x.p.Type,
UseOrganizationDomains = x.o.UseOrganizationDomains
});
}
}

View File

@ -1,4 +1,4 @@
CREATE VIEW [dbo].[OrganizationView]
CREATE VIEW [dbo].[OrganizationView]
AS
SELECT
*

View File

@ -25,13 +25,13 @@ public class GetOrganizationUsersManagementStatusQueryTests
}
[Theory, BitAutoData]
public async Task GetUsersOrganizationManagementStatusAsync_WithUseSsoEnabled_Success(
public async Task GetUsersOrganizationManagementStatusAsync_WithUseOrganizationdomainsEnabled_Success(
Organization organization,
ICollection<OrganizationUser> usersWithClaimedDomain,
SutProvider<GetOrganizationUsersManagementStatusQuery> sutProvider)
{
organization.Enabled = true;
organization.UseSso = true;
organization.UseOrganizationDomains = true;
var userIdWithoutClaimedDomain = Guid.NewGuid();
var userIdsToCheck = usersWithClaimedDomain.Select(u => u.Id).Concat(new List<Guid> { 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<OrganizationUser> usersWithClaimedDomain,
SutProvider<GetOrganizationUsersManagementStatusQuery> sutProvider)
{
organization.Enabled = true;
organization.UseSso = false;
organization.UseOrganizationDomains = false;
var userIdWithoutClaimedDomain = Guid.NewGuid();
var userIdsToCheck = usersWithClaimedDomain.Select(u => u.Id).Concat(new List<Guid> { userIdWithoutClaimedDomain }).ToList();

View File

@ -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<IGlobalSettings>();
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
}
}

View File

@ -357,7 +357,7 @@ public class UserServiceTests
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
{
organization.Enabled = true;
organization.UseSso = true;
organization.UseOrganizationDomains = true;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
@ -376,7 +376,7 @@ public class UserServiceTests
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
{
organization.Enabled = false;
organization.UseSso = true;
organization.UseOrganizationDomains = true;
sutProvider.GetDependency<IFeatureService>()
.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<UserService> sutProvider, Guid userId, Organization organization)
{
organization.Enabled = true;
organization.UseSso = false;
organization.UseOrganizationDomains = false;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)

View File

@ -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*/

View File

@ -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