1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -05:00

Merge branch 'main' into experiment/authorize-attribute

This commit is contained in:
Thomas Rittson 2025-03-27 09:54:54 +10:00 committed by GitHub
commit b840e2e318
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 10377 additions and 32 deletions

View File

@ -5,6 +5,7 @@ using Bit.Core;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Core.Vault.Commands.Interfaces;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Enums;
using Bit.Core.Vault.Queries;
using Microsoft.AspNetCore.Authorization;
@ -89,11 +90,28 @@ public class SecurityTaskController : Controller
public async Task<ListResponseModel<SecurityTasksResponseModel>> BulkCreateTasks(Guid orgId,
[FromBody] BulkCreateSecurityTasksRequestModel model)
{
var securityTasks = await _createManyTasksCommand.CreateAsync(orgId, model.Tasks);
// Retrieve existing pending security tasks for the organization
var pendingSecurityTasks = await _getTasksForOrganizationQuery.GetTasksAsync(orgId, SecurityTaskStatus.Pending);
await _createManyTaskNotificationsCommand.CreateAsync(orgId, securityTasks);
// Get the security tasks that are already associated with a cipher within the submitted model
var existingTasks = pendingSecurityTasks.Where(x => model.Tasks.Any(y => y.CipherId == x.CipherId)).ToList();
var response = securityTasks.Select(x => new SecurityTasksResponseModel(x)).ToList();
// Get tasks that need to be created
var tasksToCreateFromModel = model.Tasks.Where(x => !existingTasks.Any(y => y.CipherId == x.CipherId)).ToList();
ICollection<SecurityTask> newSecurityTasks = new List<SecurityTask>();
if (tasksToCreateFromModel.Count != 0)
{
newSecurityTasks = await _createManyTasksCommand.CreateAsync(orgId, tasksToCreateFromModel);
}
// Combine existing tasks and newly created tasks
var allTasks = existingTasks.Concat(newSecurityTasks);
await _createManyTaskNotificationsCommand.CreateAsync(orgId, allTasks);
var response = allTasks.Select(x => new SecurityTasksResponseModel(x)).ToList();
return new ListResponseModel<SecurityTasksResponseModel>(response);
}
}

View File

@ -0,0 +1,18 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
#nullable enable
namespace Bit.Core.AdminConsole.Entities;
public class OrganizationIntegration : ITableObject<Guid>
{
public Guid Id { get; set; }
public Guid OrganizationId { get; set; }
public IntegrationType Type { get; set; }
public string? Configuration { get; set; }
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
public void SetNewId() => Id = CoreHelpers.GenerateComb();
}

View File

@ -0,0 +1,19 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
#nullable enable
namespace Bit.Core.AdminConsole.Entities;
public class OrganizationIntegrationConfiguration : ITableObject<Guid>
{
public Guid Id { get; set; }
public Guid OrganizationIntegrationId { get; set; }
public EventType EventType { get; set; }
public string? Configuration { get; set; }
public string? Template { get; set; }
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
public void SetNewId() => Id = CoreHelpers.GenerateComb();
}

View File

@ -0,0 +1,7 @@
namespace Bit.Core.Enums;
public enum IntegrationType : int
{
Slack = 1,
Webhook = 2,
}

View File

@ -0,0 +1,26 @@
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
/// <summary>
/// Policy requirements for the Disable Personal Ownership policy.
/// </summary>
public class PersonalOwnershipPolicyRequirement : IPolicyRequirement
{
/// <summary>
/// Indicates whether Personal Ownership is disabled for the user. If true, members are required to save items to an organization.
/// </summary>
public bool DisablePersonalOwnership { get; init; }
}
public class PersonalOwnershipPolicyRequirementFactory : BasePolicyRequirementFactory<PersonalOwnershipPolicyRequirement>
{
public override PolicyType PolicyType => PolicyType.PersonalOwnership;
public override PersonalOwnershipPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
{
var result = new PersonalOwnershipPolicyRequirement { DisablePersonalOwnership = policyDetails.Any() };
return result;
}
}

View File

@ -34,5 +34,6 @@ public static class PolicyServiceCollectionExtensions
services.AddScoped<IPolicyRequirementFactory<IPolicyRequirement>, DisableSendPolicyRequirementFactory>();
services.AddScoped<IPolicyRequirementFactory<IPolicyRequirement>, SendOptionsPolicyRequirementFactory>();
services.AddScoped<IPolicyRequirementFactory<IPolicyRequirement>, ResetPasswordPolicyRequirementFactory>();
services.AddScoped<IPolicyRequirementFactory<IPolicyRequirement>, PersonalOwnershipPolicyRequirementFactory>();
}
}

View File

@ -129,19 +129,25 @@ public static class FeatureFlagKeys
/* Auth Team */
public const string PM9112DeviceApprovalPersistence = "pm-9112-device-approval-persistence";
/* Key Management Team */
public const string SSHKeyItemVaultItem = "ssh-key-vault-item";
public const string SSHAgent = "ssh-agent";
public const string SSHVersionCheckQAOverride = "ssh-version-check-qa-override";
public const string Argon2Default = "argon2-default";
public const string PM4154BulkEncryptionService = "PM-4154-bulk-encryption-service";
public const string PrivateKeyRegeneration = "pm-12241-private-key-regeneration";
public const string UserkeyRotationV2 = "userkey-rotation-v2";
/* Unsorted */
public const string ReturnErrorOnExistingKeypair = "return-error-on-existing-keypair";
public const string UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection";
public const string DuoRedirect = "duo-redirect";
public const string AC2101UpdateTrialInitiationEmail = "AC-2101-update-trial-initiation-email";
public const string EmailVerification = "email-verification";
public const string EmailVerificationDisableTimingDelays = "email-verification-disable-timing-delays";
public const string PM4154BulkEncryptionService = "PM-4154-bulk-encryption-service";
public const string InlineMenuFieldQualification = "inline-menu-field-qualification";
public const string InlineMenuPositioningImprovements = "inline-menu-positioning-improvements";
public const string DeviceTrustLogging = "pm-8285-device-trust-logging";
public const string SSHKeyItemVaultItem = "ssh-key-vault-item";
public const string SSHAgent = "ssh-agent";
public const string SSHVersionCheckQAOverride = "ssh-version-check-qa-override";
public const string AuthenticatorTwoFactorToken = "authenticator-2fa-token";
public const string IdpAutoSubmitLogin = "idp-auto-submit-login";
public const string UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh";
@ -162,13 +168,10 @@ public static class FeatureFlagKeys
public const string NewDeviceVerification = "new-device-verification";
public const string MacOsNativeCredentialSync = "macos-native-credential-sync";
public const string InlineMenuTotp = "inline-menu-totp";
public const string PrivateKeyRegeneration = "pm-12241-private-key-regeneration";
public const string AppReviewPrompt = "app-review-prompt";
public const string ResellerManagedOrgAlert = "PM-15814-alert-owners-of-reseller-managed-orgs";
public const string Argon2Default = "argon2-default";
public const string UsePricingService = "use-pricing-service";
public const string RecordInstallationLastActivityDate = "installation-last-activity-date";
public const string UserkeyRotationV2 = "userkey-rotation-v2";
public const string EnablePasswordManagerSyncAndroid = "enable-password-manager-sync-android";
public const string EnablePasswordManagerSynciOS = "enable-password-manager-sync-ios";
public const string AccountDeprovisioningBanner = "pm-17120-account-deprovisioning-admin-console-banner";

View File

@ -1,10 +1,13 @@
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Platform.Push;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.ImportFeatures.Interfaces;
using Bit.Core.Tools.Models.Business;
@ -26,7 +29,8 @@ public class ImportCiphersCommand : IImportCiphersCommand
private readonly ICollectionRepository _collectionRepository;
private readonly IReferenceEventService _referenceEventService;
private readonly ICurrentContext _currentContext;
private readonly IPolicyRequirementQuery _policyRequirementQuery;
private readonly IFeatureService _featureService;
public ImportCiphersCommand(
ICipherRepository cipherRepository,
@ -37,7 +41,9 @@ public class ImportCiphersCommand : IImportCiphersCommand
IPushNotificationService pushService,
IPolicyService policyService,
IReferenceEventService referenceEventService,
ICurrentContext currentContext)
ICurrentContext currentContext,
IPolicyRequirementQuery policyRequirementQuery,
IFeatureService featureService)
{
_cipherRepository = cipherRepository;
_folderRepository = folderRepository;
@ -48,9 +54,10 @@ public class ImportCiphersCommand : IImportCiphersCommand
_policyService = policyService;
_referenceEventService = referenceEventService;
_currentContext = currentContext;
_policyRequirementQuery = policyRequirementQuery;
_featureService = featureService;
}
public async Task ImportIntoIndividualVaultAsync(
List<Folder> folders,
List<CipherDetails> ciphers,
@ -58,8 +65,11 @@ public class ImportCiphersCommand : IImportCiphersCommand
Guid importingUserId)
{
// Make sure the user can save new ciphers to their personal vault
var anyPersonalOwnershipPolicies = await _policyService.AnyPoliciesApplicableToUserAsync(importingUserId, PolicyType.PersonalOwnership);
if (anyPersonalOwnershipPolicies)
var isPersonalVaultRestricted = _featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements)
? (await _policyRequirementQuery.GetAsync<PersonalOwnershipPolicyRequirement>(importingUserId)).DisablePersonalOwnership
: await _policyService.AnyPoliciesApplicableToUserAsync(importingUserId, PolicyType.PersonalOwnership);
if (isPersonalVaultRestricted)
{
throw new BadRequestException("You cannot import items into your personal vault because you are " +
"a member of an organization which forbids it.");

View File

@ -1,5 +1,7 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Context;
using Bit.Core.Enums;
@ -41,6 +43,8 @@ public class CipherService : ICipherService
private readonly IReferenceEventService _referenceEventService;
private readonly ICurrentContext _currentContext;
private readonly IGetCipherPermissionsForUserQuery _getCipherPermissionsForUserQuery;
private readonly IPolicyRequirementQuery _policyRequirementQuery;
private readonly IFeatureService _featureService;
public CipherService(
ICipherRepository cipherRepository,
@ -58,7 +62,9 @@ public class CipherService : ICipherService
GlobalSettings globalSettings,
IReferenceEventService referenceEventService,
ICurrentContext currentContext,
IGetCipherPermissionsForUserQuery getCipherPermissionsForUserQuery)
IGetCipherPermissionsForUserQuery getCipherPermissionsForUserQuery,
IPolicyRequirementQuery policyRequirementQuery,
IFeatureService featureService)
{
_cipherRepository = cipherRepository;
_folderRepository = folderRepository;
@ -76,6 +82,8 @@ public class CipherService : ICipherService
_referenceEventService = referenceEventService;
_currentContext = currentContext;
_getCipherPermissionsForUserQuery = getCipherPermissionsForUserQuery;
_policyRequirementQuery = policyRequirementQuery;
_featureService = featureService;
}
public async Task SaveAsync(Cipher cipher, Guid savingUserId, DateTime? lastKnownRevisionDate,
@ -143,9 +151,11 @@ public class CipherService : ICipherService
}
else
{
// Make sure the user can save new ciphers to their personal vault
var anyPersonalOwnershipPolicies = await _policyService.AnyPoliciesApplicableToUserAsync(savingUserId, PolicyType.PersonalOwnership);
if (anyPersonalOwnershipPolicies)
var isPersonalVaultRestricted = _featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements)
? (await _policyRequirementQuery.GetAsync<PersonalOwnershipPolicyRequirement>(savingUserId)).DisablePersonalOwnership
: await _policyService.AnyPoliciesApplicableToUserAsync(savingUserId, PolicyType.PersonalOwnership);
if (isPersonalVaultRestricted)
{
throw new BadRequestException("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.");
}

View File

@ -0,0 +1,17 @@
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bit.Infrastructure.EntityFramework.AdminConsole.Configurations;
public class OrganizationIntegrationConfigurationEntityTypeConfiguration : IEntityTypeConfiguration<OrganizationIntegrationConfiguration>
{
public void Configure(EntityTypeBuilder<OrganizationIntegrationConfiguration> builder)
{
builder
.Property(p => p.Id)
.ValueGeneratedNever();
builder.ToTable(nameof(OrganizationIntegrationConfiguration));
}
}

View File

@ -0,0 +1,26 @@
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bit.Infrastructure.EntityFramework.AdminConsole.Configurations;
public class OrganizationIntegrationEntityTypeConfiguration : IEntityTypeConfiguration<OrganizationIntegration>
{
public void Configure(EntityTypeBuilder<OrganizationIntegration> builder)
{
builder
.Property(p => p.Id)
.ValueGeneratedNever();
builder
.HasIndex(p => p.OrganizationId)
.IsClustered(false);
builder
.HasIndex(p => new { p.OrganizationId, p.Type })
.IsUnique()
.IsClustered(false);
builder.ToTable(nameof(OrganizationIntegration));
}
}

View File

@ -0,0 +1,16 @@
using AutoMapper;
namespace Bit.Infrastructure.EntityFramework.AdminConsole.Models;
public class OrganizationIntegration : Core.AdminConsole.Entities.OrganizationIntegration
{
public virtual Organization Organization { get; set; }
}
public class OrganizationIntegrationMapperProfile : Profile
{
public OrganizationIntegrationMapperProfile()
{
CreateMap<Core.AdminConsole.Entities.OrganizationIntegration, OrganizationIntegration>().ReverseMap();
}
}

View File

@ -0,0 +1,16 @@
using AutoMapper;
namespace Bit.Infrastructure.EntityFramework.AdminConsole.Models;
public class OrganizationIntegrationConfiguration : Core.AdminConsole.Entities.OrganizationIntegrationConfiguration
{
public virtual OrganizationIntegration OrganizationIntegration { get; set; }
}
public class OrganizationIntegrationConfigurationMapperProfile : Profile
{
public OrganizationIntegrationConfigurationMapperProfile()
{
CreateMap<Core.AdminConsole.Entities.OrganizationIntegrationConfiguration, OrganizationIntegrationConfiguration>().ReverseMap();
}
}

View File

@ -0,0 +1,22 @@
CREATE PROCEDURE [dbo].[OrganizationIntegrationConfiguration_ReadManyByEventTypeOrganizationIdIntegrationType]
@EventType SMALLINT,
@OrganizationId UNIQUEIDENTIFIER,
@IntegrationType SMALLINT
AS
BEGIN
SET NOCOUNT ON
SELECT
oic.*
FROM
[dbo].[OrganizationIntegrationConfigurationView] oic
INNER JOIN
[dbo].[OrganizationIntegration] oi ON oi.[Id] = oic.[OrganizationIntegrationId]
WHERE
oic.[EventType] = @EventType
AND
oi.[OrganizationId] = @OrganizationId
AND
oi.[Type] = @IntegrationType
END
GO

View File

@ -0,0 +1,20 @@
CREATE TABLE [dbo].[OrganizationIntegration]
(
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[Type] SMALLINT NOT NULL,
[Configuration] VARCHAR (MAX) NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationIntegration] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationIntegration_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_OrganizationIntegration_OrganizationId]
ON [dbo].[OrganizationIntegration]([OrganizationId] ASC);
GO
CREATE UNIQUE INDEX [IX_OrganizationIntegration_Organization_Type]
ON [dbo].[OrganizationIntegration]([OrganizationId], [Type]);
GO

View File

@ -0,0 +1,13 @@
CREATE TABLE [dbo].[OrganizationIntegrationConfiguration]
(
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationIntegrationId] UNIQUEIDENTIFIER NOT NULL,
[EventType] SMALLINT NOT NULL,
[Configuration] VARCHAR (MAX) NULL,
[Template] VARCHAR (MAX) NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationIntegrationConfiguration] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationIntegrationConfiguration_OrganizationIntegration] FOREIGN KEY ([OrganizationIntegrationId]) REFERENCES [dbo].[OrganizationIntegration] ([Id])
);
GO

View File

@ -0,0 +1,6 @@
CREATE VIEW [dbo].[OrganizationIntegrationConfigurationView]
AS
SELECT
*
FROM
[dbo].[OrganizationIntegrationConfiguration]

View File

@ -0,0 +1,6 @@
CREATE VIEW [dbo].[OrganizationIntegrationView]
AS
SELECT
*
FROM
[dbo].[OrganizationIntegration]

View File

@ -0,0 +1,31 @@
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.Test.AdminConsole.AutoFixture;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
[SutProviderCustomize]
public class PersonalOwnershipPolicyRequirementFactoryTests
{
[Theory, BitAutoData]
public void DisablePersonalOwnership_WithNoPolicies_ReturnsFalse(SutProvider<PersonalOwnershipPolicyRequirementFactory> sutProvider)
{
var actual = sutProvider.Sut.Create([]);
Assert.False(actual.DisablePersonalOwnership);
}
[Theory, BitAutoData]
public void DisablePersonalOwnership_WithPersonalOwnershipPolicies_ReturnsTrue(
[PolicyDetails(PolicyType.PersonalOwnership)] PolicyDetails[] policies,
SutProvider<PersonalOwnershipPolicyRequirementFactory> sutProvider)
{
var actual = sutProvider.Sut.Create(policies);
Assert.True(actual.DisablePersonalOwnership);
}
}

View File

@ -1,10 +1,13 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Platform.Push;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.AutoFixture.CipherFixtures;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.ImportFeatures;
@ -18,7 +21,6 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Tools.ImportFeatures;
[UserCipherCustomize]
@ -51,6 +53,34 @@ public class ImportCiphersAsyncCommandTests
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
}
[Theory, BitAutoData]
public async Task ImportIntoIndividualVaultAsync_WithPolicyRequirementsEnabled_WithDisablePersonalOwnershipPolicyDisabled_Success(
Guid importingUserId,
List<CipherDetails> ciphers,
SutProvider<ImportCiphersCommand> sutProvider)
{
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyRequirements)
.Returns(true);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<PersonalOwnershipPolicyRequirement>(importingUserId)
.Returns(new PersonalOwnershipPolicyRequirement { DisablePersonalOwnership = false });
sutProvider.GetDependency<IFolderRepository>()
.GetManyByUserIdAsync(importingUserId)
.Returns(new List<Folder>());
var folders = new List<Folder> { new Folder { UserId = importingUserId } };
var folderRelationships = new List<KeyValuePair<int, int>>();
await sutProvider.Sut.ImportIntoIndividualVaultAsync(folders, ciphers, folderRelationships, importingUserId);
await sutProvider.GetDependency<ICipherRepository>().Received(1).CreateAsync(ciphers, Arg.Any<List<Folder>>());
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
}
[Theory, BitAutoData]
public async Task ImportIntoIndividualVaultAsync_ThrowsBadRequestException(
List<Folder> folders,
@ -73,6 +103,32 @@ public class ImportCiphersAsyncCommandTests
Assert.Equal("You cannot import items into your personal vault because you are a member of an organization which forbids it.", exception.Message);
}
[Theory, BitAutoData]
public async Task ImportIntoIndividualVaultAsync_WithPolicyRequirementsEnabled_WithDisablePersonalOwnershipPolicyEnabled_ThrowsBadRequestException(
List<Folder> folders,
List<CipherDetails> ciphers,
SutProvider<ImportCiphersCommand> sutProvider)
{
var userId = Guid.NewGuid();
folders.ForEach(f => f.UserId = userId);
ciphers.ForEach(c => c.UserId = userId);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyRequirements)
.Returns(true);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<PersonalOwnershipPolicyRequirement>(userId)
.Returns(new PersonalOwnershipPolicyRequirement { DisablePersonalOwnership = true });
var folderRelationships = new List<KeyValuePair<int, int>>();
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.ImportIntoIndividualVaultAsync(folders, ciphers, folderRelationships, userId));
Assert.Equal("You cannot import items into your personal vault because you are a member of an organization which forbids it.", exception.Message);
}
[Theory, BitAutoData]
public async Task ImportIntoOrganizationalVaultAsync_Success(
Organization organization,

View File

@ -1,5 +1,9 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Billing.Enums;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -107,6 +111,98 @@ public class CipherServiceTests
await sutProvider.GetDependency<ICipherRepository>().Received(1).ReplaceAsync(cipherDetails);
}
[Theory]
[BitAutoData]
public async Task SaveDetailsAsync_PersonalVault_WithDisablePersonalOwnershipPolicyEnabled_Throws(
SutProvider<CipherService> sutProvider,
CipherDetails cipher,
Guid savingUserId)
{
cipher.Id = default;
cipher.UserId = savingUserId;
cipher.OrganizationId = null;
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(savingUserId, PolicyType.PersonalOwnership)
.Returns(true);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveDetailsAsync(cipher, savingUserId, null));
Assert.Contains("restricted from saving items to your personal vault", exception.Message);
}
[Theory]
[BitAutoData]
public async Task SaveDetailsAsync_PersonalVault_WithDisablePersonalOwnershipPolicyDisabled_Succeeds(
SutProvider<CipherService> sutProvider,
CipherDetails cipher,
Guid savingUserId)
{
cipher.Id = default;
cipher.UserId = savingUserId;
cipher.OrganizationId = null;
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(savingUserId, PolicyType.PersonalOwnership)
.Returns(false);
await sutProvider.Sut.SaveDetailsAsync(cipher, savingUserId, null);
await sutProvider.GetDependency<ICipherRepository>()
.Received(1)
.CreateAsync(cipher);
}
[Theory]
[BitAutoData]
public async Task SaveDetailsAsync_PersonalVault_WithPolicyRequirementsEnabled_WithDisablePersonalOwnershipPolicyEnabled_Throws(
SutProvider<CipherService> sutProvider,
CipherDetails cipher,
Guid savingUserId)
{
cipher.Id = default;
cipher.UserId = savingUserId;
cipher.OrganizationId = null;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyRequirements)
.Returns(true);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<PersonalOwnershipPolicyRequirement>(savingUserId)
.Returns(new PersonalOwnershipPolicyRequirement { DisablePersonalOwnership = true });
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveDetailsAsync(cipher, savingUserId, null));
Assert.Contains("restricted from saving items to your personal vault", exception.Message);
}
[Theory]
[BitAutoData]
public async Task SaveDetailsAsync_PersonalVault_WithPolicyRequirementsEnabled_WithDisablePersonalOwnershipPolicyDisabled_Succeeds(
SutProvider<CipherService> sutProvider,
CipherDetails cipher,
Guid savingUserId)
{
cipher.Id = default;
cipher.UserId = savingUserId;
cipher.OrganizationId = null;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyRequirements)
.Returns(true);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<PersonalOwnershipPolicyRequirement>(savingUserId)
.Returns(new PersonalOwnershipPolicyRequirement { DisablePersonalOwnership = false });
await sutProvider.Sut.SaveDetailsAsync(cipher, savingUserId, null);
await sutProvider.GetDependency<ICipherRepository>()
.Received(1)
.CreateAsync(cipher);
}
[Theory]
[BitAutoData("")]
[BitAutoData("Correct Time")]

View File

@ -0,0 +1,101 @@
-- OrganizationIntegration
-- Table
IF OBJECT_ID('[dbo].[OrganizationIntegration]') IS NULL
BEGIN
CREATE TABLE [dbo].[OrganizationIntegration]
(
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[Type] SMALLINT NOT NULL,
[Configuration] VARCHAR (MAX) NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationIntegration] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationIntegration_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id])
);
CREATE NONCLUSTERED INDEX [IX_OrganizationIntegration_OrganizationId]
ON [dbo].[OrganizationIntegration]([OrganizationId] ASC);
CREATE UNIQUE INDEX [IX_OrganizationIntegration_Organization_Type]
ON [dbo].[OrganizationIntegration]([OrganizationId], [Type]);
END
GO
-- View
IF EXISTS(SELECT *
FROM sys.views
WHERE [Name] = 'OrganizationIntegrationView')
BEGIN
DROP VIEW [dbo].[OrganizationIntegrationView];
END
GO
CREATE VIEW [dbo].[OrganizationIntegrationView]
AS
SELECT
*
FROM
[dbo].[OrganizationIntegration]
GO
-- OrganizationIntegrationConfiguration
-- Table
IF OBJECT_ID('[dbo].[OrganizationIntegrationConfiguration]') IS NULL
BEGIN
CREATE TABLE [dbo].[OrganizationIntegrationConfiguration]
(
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationIntegrationId] UNIQUEIDENTIFIER NOT NULL,
[EventType] SMALLINT NOT NULL,
[Configuration] VARCHAR (MAX) NULL,
[Template] VARCHAR (MAX) NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationIntegrationConfiguration] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationIntegrationConfiguration_OrganizationIntegration] FOREIGN KEY ([OrganizationIntegrationId]) REFERENCES [dbo].[OrganizationIntegration] ([Id])
);
END
GO
-- View
IF EXISTS(SELECT *
FROM sys.views
WHERE [Name] = 'OrganizationIntegrationConfigurationView')
BEGIN
DROP VIEW [dbo].[OrganizationIntegrationConfigurationView];
END
GO
CREATE VIEW [dbo].[OrganizationIntegrationConfigurationView]
AS
SELECT
*
FROM
[dbo].[OrganizationIntegrationConfiguration]
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationIntegrationConfiguration_ReadManyByEventTypeOrganizationIdIntegrationType]
@EventType SMALLINT,
@OrganizationId UNIQUEIDENTIFIER,
@IntegrationType SMALLINT
AS
BEGIN
SET NOCOUNT ON
SELECT
oic.*
FROM
[dbo].[OrganizationIntegrationConfigurationView] oic
INNER JOIN
[dbo].[OrganizationIntegration] oi ON oi.[Id] = oic.[OrganizationIntegrationId]
WHERE
oic.[EventType] = @EventType
AND
oi.[OrganizationId] = @OrganizationId
AND
oi.[Type] = @IntegrationType
END
GO

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class OrganizationIntegrations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "OrganizationIntegration",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Type = table.Column<int>(type: "int", nullable: false),
Configuration = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationIntegration", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationIntegration_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "OrganizationIntegrationConfiguration",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
OrganizationIntegrationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
EventType = table.Column<int>(type: "int", nullable: false),
Configuration = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
Template = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationIntegrationConfiguration", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationIntegrationConfiguration_OrganizationIntegration~",
column: x => x.OrganizationIntegrationId,
principalTable: "OrganizationIntegration",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegration_OrganizationId",
table: "OrganizationIntegration",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegration_OrganizationId_Type",
table: "OrganizationIntegration",
columns: new[] { "OrganizationId", "Type" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegrationConfiguration_OrganizationIntegration~",
table: "OrganizationIntegrationConfiguration",
column: "OrganizationIntegrationId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationIntegrationConfiguration");
migrationBuilder.DropTable(
name: "OrganizationIntegration");
}
}

View File

@ -217,6 +217,68 @@ namespace Bit.MySqlMigrations.Migrations
b.ToTable("Organization", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("char(36)");
b.Property<string>("Configuration")
.HasColumnType("longtext");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<Guid>("OrganizationId")
.HasColumnType("char(36)");
b.Property<DateTime>("RevisionDate")
.HasColumnType("datetime(6)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.HasIndex("OrganizationId", "Type")
.IsUnique()
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationIntegration", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegrationConfiguration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("char(36)");
b.Property<string>("Configuration")
.HasColumnType("longtext");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<int>("EventType")
.HasColumnType("int");
b.Property<Guid>("OrganizationIntegrationId")
.HasColumnType("char(36)");
b.Property<DateTime>("RevisionDate")
.HasColumnType("datetime(6)");
b.Property<string>("Template")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("OrganizationIntegrationId");
b.ToTable("OrganizationIntegrationConfiguration", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
{
b.Property<Guid>("Id")
@ -407,10 +469,6 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<DateTime?>("AuthenticationDate")
.HasColumnType("datetime(6)");
b.Property<string>("RequestCountryName")
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
@ -426,6 +484,10 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<string>("PublicKey")
.HasColumnType("longtext");
b.Property<string>("RequestCountryName")
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("RequestDeviceIdentifier")
.HasMaxLength(50)
.HasColumnType("varchar(50)");
@ -2259,6 +2321,28 @@ namespace Bit.MySqlMigrations.Migrations
b.HasDiscriminator().HasValue("user_service_account");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")
.WithMany()
.HasForeignKey("OrganizationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Organization");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegrationConfiguration", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", "OrganizationIntegration")
.WithMany()
.HasForeignKey("OrganizationIntegrationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("OrganizationIntegration");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class OrganizationIntegrations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "OrganizationIntegration",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<int>(type: "integer", nullable: false),
Configuration = table.Column<string>(type: "text", nullable: true),
CreationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RevisionDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationIntegration", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationIntegration_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "OrganizationIntegrationConfiguration",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OrganizationIntegrationId = table.Column<Guid>(type: "uuid", nullable: false),
EventType = table.Column<int>(type: "integer", nullable: false),
Configuration = table.Column<string>(type: "text", nullable: true),
Template = table.Column<string>(type: "text", nullable: true),
CreationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RevisionDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationIntegrationConfiguration", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationIntegrationConfiguration_OrganizationIntegratio~",
column: x => x.OrganizationIntegrationId,
principalTable: "OrganizationIntegration",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegration_OrganizationId",
table: "OrganizationIntegration",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegration_OrganizationId_Type",
table: "OrganizationIntegration",
columns: new[] { "OrganizationId", "Type" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegrationConfiguration_OrganizationIntegratio~",
table: "OrganizationIntegrationConfiguration",
column: "OrganizationIntegrationId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationIntegrationConfiguration");
migrationBuilder.DropTable(
name: "OrganizationIntegration");
}
}

View File

@ -220,6 +220,68 @@ namespace Bit.PostgresMigrations.Migrations
b.ToTable("Organization", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("Configuration")
.HasColumnType("text");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("OrganizationId")
.HasColumnType("uuid");
b.Property<DateTime>("RevisionDate")
.HasColumnType("timestamp with time zone");
b.Property<int>("Type")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.HasIndex("OrganizationId", "Type")
.IsUnique()
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationIntegration", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegrationConfiguration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("Configuration")
.HasColumnType("text");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<int>("EventType")
.HasColumnType("integer");
b.Property<Guid>("OrganizationIntegrationId")
.HasColumnType("uuid");
b.Property<DateTime>("RevisionDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Template")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("OrganizationIntegrationId");
b.ToTable("OrganizationIntegrationConfiguration", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
{
b.Property<Guid>("Id")
@ -410,10 +472,6 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<DateTime?>("AuthenticationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("RequestCountryName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp with time zone");
@ -429,6 +487,10 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<string>("PublicKey")
.HasColumnType("text");
b.Property<string>("RequestCountryName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("RequestDeviceIdentifier")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
@ -2265,6 +2327,28 @@ namespace Bit.PostgresMigrations.Migrations
b.HasDiscriminator().HasValue("user_service_account");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")
.WithMany()
.HasForeignKey("OrganizationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Organization");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegrationConfiguration", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", "OrganizationIntegration")
.WithMany()
.HasForeignKey("OrganizationIntegrationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("OrganizationIntegration");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class OrganizationIntegrations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "OrganizationIntegration",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
OrganizationId = table.Column<Guid>(type: "TEXT", nullable: false),
Type = table.Column<int>(type: "INTEGER", nullable: false),
Configuration = table.Column<string>(type: "TEXT", nullable: true),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false),
RevisionDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationIntegration", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationIntegration_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "OrganizationIntegrationConfiguration",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
OrganizationIntegrationId = table.Column<Guid>(type: "TEXT", nullable: false),
EventType = table.Column<int>(type: "INTEGER", nullable: false),
Configuration = table.Column<string>(type: "TEXT", nullable: true),
Template = table.Column<string>(type: "TEXT", nullable: true),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false),
RevisionDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationIntegrationConfiguration", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationIntegrationConfiguration_OrganizationIntegration_OrganizationIntegrationId",
column: x => x.OrganizationIntegrationId,
principalTable: "OrganizationIntegration",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegration_OrganizationId",
table: "OrganizationIntegration",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegration_OrganizationId_Type",
table: "OrganizationIntegration",
columns: new[] { "OrganizationId", "Type" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_OrganizationIntegrationConfiguration_OrganizationIntegrationId",
table: "OrganizationIntegrationConfiguration",
column: "OrganizationIntegrationId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationIntegrationConfiguration");
migrationBuilder.DropTable(
name: "OrganizationIntegration");
}
}

View File

@ -212,6 +212,68 @@ namespace Bit.SqliteMigrations.Migrations
b.ToTable("Organization", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("TEXT");
b.Property<string>("Configuration")
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<Guid>("OrganizationId")
.HasColumnType("TEXT");
b.Property<DateTime>("RevisionDate")
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.HasIndex("OrganizationId", "Type")
.IsUnique()
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationIntegration", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegrationConfiguration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("TEXT");
b.Property<string>("Configuration")
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<int>("EventType")
.HasColumnType("INTEGER");
b.Property<Guid>("OrganizationIntegrationId")
.HasColumnType("TEXT");
b.Property<DateTime>("RevisionDate")
.HasColumnType("TEXT");
b.Property<string>("Template")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("OrganizationIntegrationId");
b.ToTable("OrganizationIntegrationConfiguration", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
{
b.Property<Guid>("Id")
@ -402,10 +464,6 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<DateTime?>("AuthenticationDate")
.HasColumnType("TEXT");
b.Property<string>("RequestCountryName")
.HasMaxLength(200)
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
@ -421,6 +479,10 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<string>("PublicKey")
.HasColumnType("TEXT");
b.Property<string>("RequestCountryName")
.HasMaxLength(200)
.HasColumnType("TEXT");
b.Property<string>("RequestDeviceIdentifier")
.HasMaxLength(50)
.HasColumnType("TEXT");
@ -2248,6 +2310,28 @@ namespace Bit.SqliteMigrations.Migrations
b.HasDiscriminator().HasValue("user_service_account");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")
.WithMany()
.HasForeignKey("OrganizationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Organization");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegrationConfiguration", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.OrganizationIntegration", "OrganizationIntegration")
.WithMany()
.HasForeignKey("OrganizationIntegrationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("OrganizationIntegration");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")