mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 09:32:48 -05:00
[AC-1283] AC Team code ownership moves: Organization (pt 2) (#3486)
* move remaining Organization domain files * namespaces will be updated in a separate commit
This commit is contained in:
28
src/Core/AdminConsole/Context/CurrentContextOrganization.cs
Normal file
28
src/Core/AdminConsole/Context/CurrentContextOrganization.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Context;
|
||||
|
||||
public class CurrentContextOrganization
|
||||
{
|
||||
public CurrentContextOrganization() { }
|
||||
|
||||
public CurrentContextOrganization(OrganizationUserOrganizationDetails orgUser)
|
||||
{
|
||||
Id = orgUser.OrganizationId;
|
||||
Type = orgUser.Type;
|
||||
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(orgUser.Permissions);
|
||||
AccessSecretsManager = orgUser.AccessSecretsManager && orgUser.UseSecretsManager && orgUser.Enabled;
|
||||
LimitCollectionCreationDeletion = orgUser.LimitCollectionCreationDeletion;
|
||||
AllowAdminAccessToAllCollectionItems = orgUser.AllowAdminAccessToAllCollectionItems;
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public OrganizationUserType Type { get; set; }
|
||||
public Permissions Permissions { get; set; } = new();
|
||||
public bool AccessSecretsManager { get; set; }
|
||||
public bool LimitCollectionCreationDeletion { get; set; }
|
||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||
}
|
7
src/Core/AdminConsole/Enums/OrganizationStatusType.cs
Normal file
7
src/Core/AdminConsole/Enums/OrganizationStatusType.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Bit.Core.Enums;
|
||||
|
||||
public enum OrganizationStatusType : byte
|
||||
{
|
||||
Pending = 0,
|
||||
Created = 1
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
|
||||
namespace Bit.Core.Models.Data.Organizations;
|
||||
|
||||
public class OrganizationAbility
|
||||
{
|
||||
public OrganizationAbility() { }
|
||||
|
||||
public OrganizationAbility(Organization organization)
|
||||
{
|
||||
Id = organization.Id;
|
||||
UseEvents = organization.UseEvents;
|
||||
Use2fa = organization.Use2fa;
|
||||
Using2fa = organization.Use2fa && organization.TwoFactorProviders != null &&
|
||||
organization.TwoFactorProviders != "{}";
|
||||
UsersGetPremium = organization.UsersGetPremium;
|
||||
Enabled = organization.Enabled;
|
||||
UseSso = organization.UseSso;
|
||||
UseKeyConnector = organization.UseKeyConnector;
|
||||
UseScim = organization.UseScim;
|
||||
UseResetPassword = organization.UseResetPassword;
|
||||
UseCustomPermissions = organization.UseCustomPermissions;
|
||||
UsePolicies = organization.UsePolicies;
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public bool UseEvents { get; set; }
|
||||
public bool Use2fa { get; set; }
|
||||
public bool Using2fa { get; set; }
|
||||
public bool UsersGetPremium { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public bool UseSso { get; set; }
|
||||
public bool UseKeyConnector { get; set; }
|
||||
public bool UseScim { get; set; }
|
||||
public bool UseResetPassword { get; set; }
|
||||
public bool UseCustomPermissions { get; set; }
|
||||
public bool UsePolicies { get; set; }
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.OrganizationConnectionConfigs;
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Business;
|
||||
|
||||
namespace Bit.Core.Models.Data.Organizations;
|
||||
|
||||
public class SelfHostedOrganizationDetails : Organization
|
||||
{
|
||||
public int OccupiedSeatCount { get; set; }
|
||||
public int CollectionCount { get; set; }
|
||||
public int GroupCount { get; set; }
|
||||
public IEnumerable<OrganizationUser> OrganizationUsers { get; set; }
|
||||
public IEnumerable<Policy> Policies { get; set; }
|
||||
public SsoConfig SsoConfig { get; set; }
|
||||
public IEnumerable<OrganizationConnection> ScimConnections { get; set; }
|
||||
|
||||
public bool CanUseLicense(OrganizationLicense license, out string exception)
|
||||
{
|
||||
if (license.Seats.HasValue && OccupiedSeatCount > license.Seats.Value)
|
||||
{
|
||||
exception = $"Your organization currently has {OccupiedSeatCount} seats filled. " +
|
||||
$"Your new license only has ({license.Seats.Value}) seats. Remove some users.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (license.MaxCollections.HasValue && CollectionCount > license.MaxCollections.Value)
|
||||
{
|
||||
exception = $"Your organization currently has {CollectionCount} collections. " +
|
||||
$"Your new license allows for a maximum of ({license.MaxCollections.Value}) collections. " +
|
||||
"Remove some collections.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!license.UseGroups && UseGroups && GroupCount > 1)
|
||||
{
|
||||
exception = $"Your organization currently has {GroupCount} groups. " +
|
||||
$"Your new license does not allow for the use of groups. Remove all groups.";
|
||||
return false;
|
||||
}
|
||||
|
||||
var enabledPolicyCount = Policies.Count(p => p.Enabled);
|
||||
if (!license.UsePolicies && UsePolicies && enabledPolicyCount > 0)
|
||||
{
|
||||
exception = $"Your organization currently has {enabledPolicyCount} enabled " +
|
||||
$"policies. Your new license does not allow for the use of policies. Disable all policies.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!license.UseSso && UseSso && SsoConfig is { Enabled: true })
|
||||
{
|
||||
exception = $"Your organization currently has a SSO configuration. " +
|
||||
$"Your new license does not allow for the use of SSO. Disable your SSO configuration.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!license.UseKeyConnector && UseKeyConnector && SsoConfig?.Data != null &&
|
||||
SsoConfig.GetData().MemberDecryptionType == MemberDecryptionType.KeyConnector)
|
||||
{
|
||||
exception = $"Your organization currently has Key Connector enabled. " +
|
||||
$"Your new license does not allow for the use of Key Connector. Disable your Key Connector.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!license.UseScim && UseScim && ScimConnections != null &&
|
||||
ScimConnections.Any(c => c.GetConfig<ScimConfig>() is { Enabled: true }))
|
||||
{
|
||||
exception = "Your new plan does not allow the SCIM feature. " +
|
||||
"Disable your SCIM configuration.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!license.UseCustomPermissions && UseCustomPermissions &&
|
||||
OrganizationUsers.Any(ou => ou.Type == OrganizationUserType.Custom))
|
||||
{
|
||||
exception = "Your new plan does not allow the Custom Permissions feature. " +
|
||||
"Disable your Custom Permissions configuration.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!license.UseResetPassword && UseResetPassword &&
|
||||
Policies.Any(p => p.Type == PolicyType.ResetPassword && p.Enabled))
|
||||
{
|
||||
exception = "Your new license does not allow the Password Reset feature. "
|
||||
+ "Disable your Password Reset policy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
exception = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public Organization ToOrganization()
|
||||
{
|
||||
// Any new Organization properties must be added here for them to flow through to self-hosted organizations
|
||||
return new Organization
|
||||
{
|
||||
Id = Id,
|
||||
Identifier = Identifier,
|
||||
Name = Name,
|
||||
BusinessName = BusinessName,
|
||||
BusinessAddress1 = BusinessAddress1,
|
||||
BusinessAddress2 = BusinessAddress2,
|
||||
BusinessAddress3 = BusinessAddress3,
|
||||
BusinessCountry = BusinessCountry,
|
||||
BusinessTaxNumber = BusinessTaxNumber,
|
||||
BillingEmail = BillingEmail,
|
||||
Plan = Plan,
|
||||
PlanType = PlanType,
|
||||
Seats = Seats,
|
||||
MaxCollections = MaxCollections,
|
||||
UsePolicies = UsePolicies,
|
||||
UseSso = UseSso,
|
||||
UseKeyConnector = UseKeyConnector,
|
||||
UseScim = UseScim,
|
||||
UseGroups = UseGroups,
|
||||
UseDirectory = UseDirectory,
|
||||
UseEvents = UseEvents,
|
||||
UseTotp = UseTotp,
|
||||
Use2fa = Use2fa,
|
||||
UseApi = UseApi,
|
||||
UseResetPassword = UseResetPassword,
|
||||
UseSecretsManager = UseSecretsManager,
|
||||
SelfHost = SelfHost,
|
||||
UsersGetPremium = UsersGetPremium,
|
||||
UseCustomPermissions = UseCustomPermissions,
|
||||
Storage = Storage,
|
||||
MaxStorageGb = MaxStorageGb,
|
||||
Gateway = Gateway,
|
||||
GatewayCustomerId = GatewayCustomerId,
|
||||
GatewaySubscriptionId = GatewaySubscriptionId,
|
||||
ReferenceData = ReferenceData,
|
||||
Enabled = Enabled,
|
||||
LicenseKey = LicenseKey,
|
||||
PublicKey = PublicKey,
|
||||
PrivateKey = PrivateKey,
|
||||
TwoFactorProviders = TwoFactorProviders,
|
||||
ExpirationDate = ExpirationDate,
|
||||
CreationDate = CreationDate,
|
||||
RevisionDate = RevisionDate,
|
||||
MaxAutoscaleSeats = MaxAutoscaleSeats,
|
||||
OwnersNotifiedOfAutoscaling = OwnersNotifiedOfAutoscaling,
|
||||
LimitCollectionCreationDeletion = LimitCollectionCreationDeletion,
|
||||
AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
|
||||
namespace Bit.Core.Repositories;
|
||||
|
||||
public interface IOrganizationRepository : IRepository<Organization, Guid>
|
||||
{
|
||||
Task<Organization> GetByIdentifierAsync(string identifier);
|
||||
Task<ICollection<Organization>> GetManyByEnabledAsync();
|
||||
Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId);
|
||||
Task<ICollection<Organization>> SearchAsync(string name, string userEmail, bool? paid, int skip, int take);
|
||||
Task UpdateStorageAsync(Guid id);
|
||||
Task<ICollection<OrganizationAbility>> GetManyAbilitiesAsync();
|
||||
Task<Organization> GetByLicenseKeyAsync(string licenseKey);
|
||||
Task<SelfHostedOrganizationDetails> GetSelfHostedOrganizationDetailsById(Guid id);
|
||||
Task<ICollection<Organization>> SearchUnassignedToProviderAsync(string name, string ownerEmail, int skip, int take);
|
||||
Task<IEnumerable<string>> GetOwnerEmailAddressesById(Guid organizationId);
|
||||
}
|
85
src/Core/AdminConsole/Services/IOrganizationService.cs
Normal file
85
src/Core/AdminConsole/Services/IOrganizationService.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Data;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public interface IOrganizationService
|
||||
{
|
||||
Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken, PaymentMethodType paymentMethodType,
|
||||
TaxInfo taxInfo);
|
||||
Task CancelSubscriptionAsync(Guid organizationId, bool? endOfPeriod = null);
|
||||
Task ReinstateSubscriptionAsync(Guid organizationId);
|
||||
Task<string> AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb);
|
||||
Task UpdateSubscription(Guid organizationId, int seatAdjustment, int? maxAutoscaleSeats);
|
||||
Task AutoAddSeatsAsync(Organization organization, int seatsToAdd, DateTime? prorationDate = null);
|
||||
Task<string> AdjustSeatsAsync(Guid organizationId, int seatAdjustment, DateTime? prorationDate = null);
|
||||
Task VerifyBankAsync(Guid organizationId, int amount1, int amount2);
|
||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup, bool provider = false);
|
||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationLicense license, User owner,
|
||||
string ownerKey, string collectionName, string publicKey, string privateKey);
|
||||
Task DeleteAsync(Organization organization);
|
||||
Task EnableAsync(Guid organizationId, DateTime? expirationDate);
|
||||
Task DisableAsync(Guid organizationId, DateTime? expirationDate);
|
||||
Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate);
|
||||
Task EnableAsync(Guid organizationId);
|
||||
Task UpdateAsync(Organization organization, bool updateBilling = false, EventType eventType = EventType.Organization_Updated);
|
||||
Task UpdateTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type);
|
||||
Task DisableTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type);
|
||||
Task<List<OrganizationUser>> InviteUsersAsync(Guid organizationId, Guid? invitingUserId,
|
||||
IEnumerable<(OrganizationUserInvite invite, string externalId)> invites);
|
||||
Task<List<OrganizationUser>> InviteUsersAsync(Guid organizationId, EventSystemUser systemUser,
|
||||
IEnumerable<(OrganizationUserInvite invite, string externalId)> invites);
|
||||
Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email,
|
||||
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<CollectionAccessSelection> collections, IEnumerable<Guid> groups);
|
||||
Task<OrganizationUser> InviteUserAsync(Guid organizationId, EventSystemUser systemUser, string email,
|
||||
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<CollectionAccessSelection> collections, IEnumerable<Guid> groups);
|
||||
Task<IEnumerable<Tuple<OrganizationUser, string>>> ResendInvitesAsync(Guid organizationId, Guid? invitingUserId, IEnumerable<Guid> organizationUsersId);
|
||||
Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId, bool initOrganization = false);
|
||||
Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
||||
Guid confirmingUserId, IUserService userService);
|
||||
Task<List<Tuple<OrganizationUser, string>>> ConfirmUsersAsync(Guid organizationId, Dictionary<Guid, string> keys,
|
||||
Guid confirmingUserId, IUserService userService);
|
||||
Task SaveUserAsync(OrganizationUser user, Guid? savingUserId, IEnumerable<CollectionAccessSelection> collections, IEnumerable<Guid> groups);
|
||||
[Obsolete("IDeleteOrganizationUserCommand should be used instead. To be removed by EC-607.")]
|
||||
Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid? deletingUserId);
|
||||
[Obsolete("IDeleteOrganizationUserCommand should be used instead. To be removed by EC-607.")]
|
||||
Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, EventSystemUser systemUser);
|
||||
Task DeleteUserAsync(Guid organizationId, Guid userId);
|
||||
Task<List<Tuple<OrganizationUser, string>>> DeleteUsersAsync(Guid organizationId,
|
||||
IEnumerable<Guid> organizationUserIds, Guid? deletingUserId);
|
||||
Task UpdateUserResetPasswordEnrollmentAsync(Guid organizationId, Guid userId, string resetPasswordKey, Guid? callingUserId);
|
||||
Task ImportAsync(Guid organizationId, Guid? importingUserId, IEnumerable<ImportedGroup> groups,
|
||||
IEnumerable<ImportedOrganizationUser> newUsers, IEnumerable<string> removeUserExternalIds,
|
||||
bool overwriteExisting);
|
||||
Task DeleteSsoUserAsync(Guid userId, Guid? organizationId);
|
||||
Task<Organization> UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey);
|
||||
Task<bool> HasConfirmedOwnersExceptAsync(Guid organizationId, IEnumerable<Guid> organizationUsersId, bool includeProvider = true);
|
||||
Task RevokeUserAsync(OrganizationUser organizationUser, Guid? revokingUserId);
|
||||
Task RevokeUserAsync(OrganizationUser organizationUser, EventSystemUser systemUser);
|
||||
Task<List<Tuple<OrganizationUser, string>>> RevokeUsersAsync(Guid organizationId,
|
||||
IEnumerable<Guid> organizationUserIds, Guid? revokingUserId);
|
||||
Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId, IUserService userService);
|
||||
Task RestoreUserAsync(OrganizationUser organizationUser, EventSystemUser systemUser, IUserService userService);
|
||||
Task<List<Tuple<OrganizationUser, string>>> RestoreUsersAsync(Guid organizationId,
|
||||
IEnumerable<Guid> organizationUserIds, Guid? restoringUserId, IUserService userService);
|
||||
Task CreatePendingOrganization(Organization organization, string ownerEmail, ClaimsPrincipal user, IUserService userService, bool salesAssistedTrialStarted);
|
||||
/// <summary>
|
||||
/// Update an Organization entry by setting the public/private keys, set it as 'Enabled' and move the Status from 'Pending' to 'Created'.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method must target a disabled Organization that has null keys and status as 'Pending'.
|
||||
/// </remarks>
|
||||
Task InitPendingOrganization(Guid userId, Guid organizationId, string publicKey, string privateKey, string collectionName);
|
||||
Task ReplaceAndUpdateCacheAsync(Organization org, EventType? orgEvent = null);
|
||||
|
||||
void ValidatePasswordManagerPlan(Models.StaticStore.Plan plan, OrganizationUpgrade upgrade);
|
||||
void ValidateSecretsManagerPlan(Models.StaticStore.Plan plan, OrganizationUpgrade upgrade);
|
||||
Task ValidateOrganizationUserUpdatePermissions(Guid organizationId, OrganizationUserType newType,
|
||||
OrganizationUserType? oldType, Permissions permissions);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user