mirror of
https://github.com/bitwarden/server
synced 2025-12-18 01:03:17 +00:00
Merge branch 'main' into SM-1571-DisableSMAdsForUsers
This commit is contained in:
4
.github/renovate.json5
vendored
4
.github/renovate.json5
vendored
@@ -41,6 +41,10 @@
|
|||||||
matchUpdateTypes: ["patch"],
|
matchUpdateTypes: ["patch"],
|
||||||
dependencyDashboardApproval: false,
|
dependencyDashboardApproval: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
matchSourceUrls: ["https://github.com/bitwarden/sdk-internal"],
|
||||||
|
groupName: "sdk-internal",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
matchManagers: ["dockerfile", "docker-compose"],
|
matchManagers: ["dockerfile", "docker-compose"],
|
||||||
commitMessagePrefix: "[deps] BRE:",
|
commitMessagePrefix: "[deps] BRE:",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using Bit.Core.AdminConsole.Entities;
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
@@ -41,8 +42,9 @@ public class PoliciesController : Controller
|
|||||||
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
|
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
|
||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
private readonly IFeatureService _featureService;
|
||||||
private readonly ISavePolicyCommand _savePolicyCommand;
|
private readonly ISavePolicyCommand _savePolicyCommand;
|
||||||
|
private readonly IVNextSavePolicyCommand _vNextSavePolicyCommand;
|
||||||
|
|
||||||
public PoliciesController(IPolicyRepository policyRepository,
|
public PoliciesController(IPolicyRepository policyRepository,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
@@ -53,7 +55,9 @@ public class PoliciesController : Controller
|
|||||||
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
|
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
|
||||||
IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery,
|
IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery,
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
ISavePolicyCommand savePolicyCommand)
|
IFeatureService featureService,
|
||||||
|
ISavePolicyCommand savePolicyCommand,
|
||||||
|
IVNextSavePolicyCommand vNextSavePolicyCommand)
|
||||||
{
|
{
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
@@ -65,7 +69,9 @@ public class PoliciesController : Controller
|
|||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
|
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
|
||||||
_organizationHasVerifiedDomainsQuery = organizationHasVerifiedDomainsQuery;
|
_organizationHasVerifiedDomainsQuery = organizationHasVerifiedDomainsQuery;
|
||||||
|
_featureService = featureService;
|
||||||
_savePolicyCommand = savePolicyCommand;
|
_savePolicyCommand = savePolicyCommand;
|
||||||
|
_vNextSavePolicyCommand = vNextSavePolicyCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{type}")]
|
[HttpGet("{type}")]
|
||||||
@@ -221,7 +227,9 @@ public class PoliciesController : Controller
|
|||||||
{
|
{
|
||||||
var savePolicyRequest = await model.ToSavePolicyModelAsync(orgId, _currentContext);
|
var savePolicyRequest = await model.ToSavePolicyModelAsync(orgId, _currentContext);
|
||||||
|
|
||||||
var policy = await _savePolicyCommand.VNextSaveAsync(savePolicyRequest);
|
var policy = _featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor) ?
|
||||||
|
await _vNextSavePolicyCommand.SaveAsync(savePolicyRequest) :
|
||||||
|
await _savePolicyCommand.VNextSaveAsync(savePolicyRequest);
|
||||||
|
|
||||||
return new PolicyResponseModel(policy);
|
return new PolicyResponseModel(policy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ using System.Net;
|
|||||||
using Bit.Api.AdminConsole.Public.Models.Request;
|
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
using Bit.Api.AdminConsole.Public.Models.Response;
|
using Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
using Bit.Api.Models.Public.Response;
|
using Bit.Api.Models.Public.Response;
|
||||||
|
using Bit.Core;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.AdminConsole.Services;
|
using Bit.Core.AdminConsole.Services;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@@ -22,18 +26,24 @@ public class PoliciesController : Controller
|
|||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly IPolicyService _policyService;
|
private readonly IPolicyService _policyService;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
|
private readonly IFeatureService _featureService;
|
||||||
private readonly ISavePolicyCommand _savePolicyCommand;
|
private readonly ISavePolicyCommand _savePolicyCommand;
|
||||||
|
private readonly IVNextSavePolicyCommand _vNextSavePolicyCommand;
|
||||||
|
|
||||||
public PoliciesController(
|
public PoliciesController(
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
IPolicyService policyService,
|
IPolicyService policyService,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
ISavePolicyCommand savePolicyCommand)
|
IFeatureService featureService,
|
||||||
|
ISavePolicyCommand savePolicyCommand,
|
||||||
|
IVNextSavePolicyCommand vNextSavePolicyCommand)
|
||||||
{
|
{
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_policyService = policyService;
|
_policyService = policyService;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
|
_featureService = featureService;
|
||||||
_savePolicyCommand = savePolicyCommand;
|
_savePolicyCommand = savePolicyCommand;
|
||||||
|
_vNextSavePolicyCommand = vNextSavePolicyCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -86,9 +96,18 @@ public class PoliciesController : Controller
|
|||||||
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
|
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
|
||||||
[ProducesResponseType((int)HttpStatusCode.NotFound)]
|
[ProducesResponseType((int)HttpStatusCode.NotFound)]
|
||||||
public async Task<IActionResult> Put(PolicyType type, [FromBody] PolicyUpdateRequestModel model)
|
public async Task<IActionResult> Put(PolicyType type, [FromBody] PolicyUpdateRequestModel model)
|
||||||
|
{
|
||||||
|
Policy policy;
|
||||||
|
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor))
|
||||||
|
{
|
||||||
|
var savePolicyModel = model.ToSavePolicyModel(_currentContext.OrganizationId!.Value, type);
|
||||||
|
policy = await _vNextSavePolicyCommand.SaveAsync(savePolicyModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var policyUpdate = model.ToPolicyUpdate(_currentContext.OrganizationId!.Value, type);
|
var policyUpdate = model.ToPolicyUpdate(_currentContext.OrganizationId!.Value, type);
|
||||||
var policy = await _savePolicyCommand.SaveAsync(policyUpdate);
|
policy = await _savePolicyCommand.SaveAsync(policyUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
var response = new PolicyResponseModel(policy);
|
var response = new PolicyResponseModel(policy);
|
||||||
return new JsonResult(response);
|
return new JsonResult(response);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace Bit.Api.AdminConsole.Public.Models.Request;
|
|||||||
|
|
||||||
public class PolicyUpdateRequestModel : PolicyBaseModel
|
public class PolicyUpdateRequestModel : PolicyBaseModel
|
||||||
{
|
{
|
||||||
|
public Dictionary<string, object>? Metadata { get; set; }
|
||||||
|
|
||||||
public PolicyUpdate ToPolicyUpdate(Guid organizationId, PolicyType type)
|
public PolicyUpdate ToPolicyUpdate(Guid organizationId, PolicyType type)
|
||||||
{
|
{
|
||||||
var serializedData = PolicyDataValidator.ValidateAndSerialize(Data, type);
|
var serializedData = PolicyDataValidator.ValidateAndSerialize(Data, type);
|
||||||
@@ -21,4 +23,22 @@ public class PolicyUpdateRequestModel : PolicyBaseModel
|
|||||||
PerformedBy = new SystemUser(EventSystemUser.PublicApi)
|
PerformedBy = new SystemUser(EventSystemUser.PublicApi)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SavePolicyModel ToSavePolicyModel(Guid organizationId, PolicyType type)
|
||||||
|
{
|
||||||
|
var serializedData = PolicyDataValidator.ValidateAndSerialize(Data, type);
|
||||||
|
|
||||||
|
var policyUpdate = new PolicyUpdate
|
||||||
|
{
|
||||||
|
Type = type,
|
||||||
|
OrganizationId = organizationId,
|
||||||
|
Data = serializedData,
|
||||||
|
Enabled = Enabled.GetValueOrDefault()
|
||||||
|
};
|
||||||
|
|
||||||
|
var performedBy = new SystemUser(EventSystemUser.PublicApi);
|
||||||
|
var metadata = PolicyDataValidator.ValidateAndDeserializeMetadata(Metadata, type);
|
||||||
|
|
||||||
|
return new SavePolicyModel(policyUpdate, performedBy, metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Bit.Core.AdminConsole.Models.Data;
|
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -24,7 +25,9 @@ public class VerifyOrganizationDomainCommand(
|
|||||||
IEventService eventService,
|
IEventService eventService,
|
||||||
IGlobalSettings globalSettings,
|
IGlobalSettings globalSettings,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
|
IFeatureService featureService,
|
||||||
ISavePolicyCommand savePolicyCommand,
|
ISavePolicyCommand savePolicyCommand,
|
||||||
|
IVNextSavePolicyCommand vNextSavePolicyCommand,
|
||||||
IMailService mailService,
|
IMailService mailService,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@@ -131,15 +134,26 @@ public class VerifyOrganizationDomainCommand(
|
|||||||
await SendVerifiedDomainUserEmailAsync(domain);
|
await SendVerifiedDomainUserEmailAsync(domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EnableSingleOrganizationPolicyAsync(Guid organizationId, IActingUser actingUser) =>
|
private async Task EnableSingleOrganizationPolicyAsync(Guid organizationId, IActingUser actingUser)
|
||||||
await savePolicyCommand.SaveAsync(
|
{
|
||||||
new PolicyUpdate
|
var policyUpdate = new PolicyUpdate
|
||||||
{
|
{
|
||||||
OrganizationId = organizationId,
|
OrganizationId = organizationId,
|
||||||
Type = PolicyType.SingleOrg,
|
Type = PolicyType.SingleOrg,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
PerformedBy = actingUser
|
PerformedBy = actingUser
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor))
|
||||||
|
{
|
||||||
|
var savePolicyModel = new SavePolicyModel(policyUpdate, actingUser);
|
||||||
|
await vNextSavePolicyCommand.SaveAsync(savePolicyModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await savePolicyCommand.SaveAsync(policyUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SendVerifiedDomainUserEmailAsync(OrganizationDomain domain)
|
private async Task SendVerifiedDomainUserEmailAsync(OrganizationDomain domain)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,4 +5,18 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
|||||||
|
|
||||||
public record SavePolicyModel(PolicyUpdate PolicyUpdate, IActingUser? PerformedBy, IPolicyMetadataModel Metadata)
|
public record SavePolicyModel(PolicyUpdate PolicyUpdate, IActingUser? PerformedBy, IPolicyMetadataModel Metadata)
|
||||||
{
|
{
|
||||||
|
public SavePolicyModel(PolicyUpdate PolicyUpdate)
|
||||||
|
: this(PolicyUpdate, null, new EmptyMetadataModel())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SavePolicyModel(PolicyUpdate PolicyUpdate, IActingUser performedBy)
|
||||||
|
: this(PolicyUpdate, performedBy, new EmptyMetadataModel())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SavePolicyModel(PolicyUpdate PolicyUpdate, IPolicyMetadataModel metadata)
|
||||||
|
: this(PolicyUpdate, null, metadata)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
|
|
||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data;
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Auth.Enums;
|
using Bit.Core.Auth.Enums;
|
||||||
@@ -24,7 +26,9 @@ public class SsoConfigService : ISsoConfigService
|
|||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
private readonly IEventService _eventService;
|
private readonly IEventService _eventService;
|
||||||
|
private readonly IFeatureService _featureService;
|
||||||
private readonly ISavePolicyCommand _savePolicyCommand;
|
private readonly ISavePolicyCommand _savePolicyCommand;
|
||||||
|
private readonly IVNextSavePolicyCommand _vNextSavePolicyCommand;
|
||||||
|
|
||||||
public SsoConfigService(
|
public SsoConfigService(
|
||||||
ISsoConfigRepository ssoConfigRepository,
|
ISsoConfigRepository ssoConfigRepository,
|
||||||
@@ -32,14 +36,18 @@ public class SsoConfigService : ISsoConfigService
|
|||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
IEventService eventService,
|
IEventService eventService,
|
||||||
ISavePolicyCommand savePolicyCommand)
|
IFeatureService featureService,
|
||||||
|
ISavePolicyCommand savePolicyCommand,
|
||||||
|
IVNextSavePolicyCommand vNextSavePolicyCommand)
|
||||||
{
|
{
|
||||||
_ssoConfigRepository = ssoConfigRepository;
|
_ssoConfigRepository = ssoConfigRepository;
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
_eventService = eventService;
|
_eventService = eventService;
|
||||||
|
_featureService = featureService;
|
||||||
_savePolicyCommand = savePolicyCommand;
|
_savePolicyCommand = savePolicyCommand;
|
||||||
|
_vNextSavePolicyCommand = vNextSavePolicyCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveAsync(SsoConfig config, Organization organization)
|
public async Task SaveAsync(SsoConfig config, Organization organization)
|
||||||
@@ -67,13 +75,12 @@ public class SsoConfigService : ISsoConfigService
|
|||||||
// Automatically enable account recovery, SSO required, and single org policies if trusted device encryption is selected
|
// Automatically enable account recovery, SSO required, and single org policies if trusted device encryption is selected
|
||||||
if (config.GetData().MemberDecryptionType == MemberDecryptionType.TrustedDeviceEncryption)
|
if (config.GetData().MemberDecryptionType == MemberDecryptionType.TrustedDeviceEncryption)
|
||||||
{
|
{
|
||||||
|
var singleOrgPolicy = new PolicyUpdate
|
||||||
await _savePolicyCommand.SaveAsync(new()
|
|
||||||
{
|
{
|
||||||
OrganizationId = config.OrganizationId,
|
OrganizationId = config.OrganizationId,
|
||||||
Type = PolicyType.SingleOrg,
|
Type = PolicyType.SingleOrg,
|
||||||
Enabled = true
|
Enabled = true
|
||||||
});
|
};
|
||||||
|
|
||||||
var resetPasswordPolicy = new PolicyUpdate
|
var resetPasswordPolicy = new PolicyUpdate
|
||||||
{
|
{
|
||||||
@@ -82,14 +89,27 @@ public class SsoConfigService : ISsoConfigService
|
|||||||
Enabled = true,
|
Enabled = true,
|
||||||
};
|
};
|
||||||
resetPasswordPolicy.SetDataModel(new ResetPasswordDataModel { AutoEnrollEnabled = true });
|
resetPasswordPolicy.SetDataModel(new ResetPasswordDataModel { AutoEnrollEnabled = true });
|
||||||
await _savePolicyCommand.SaveAsync(resetPasswordPolicy);
|
|
||||||
|
|
||||||
await _savePolicyCommand.SaveAsync(new()
|
var requireSsoPolicy = new PolicyUpdate
|
||||||
{
|
{
|
||||||
OrganizationId = config.OrganizationId,
|
OrganizationId = config.OrganizationId,
|
||||||
Type = PolicyType.RequireSso,
|
Type = PolicyType.RequireSso,
|
||||||
Enabled = true
|
Enabled = true
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor))
|
||||||
|
{
|
||||||
|
var performedBy = new SystemUser(EventSystemUser.Unknown);
|
||||||
|
await _vNextSavePolicyCommand.SaveAsync(new SavePolicyModel(singleOrgPolicy, performedBy));
|
||||||
|
await _vNextSavePolicyCommand.SaveAsync(new SavePolicyModel(resetPasswordPolicy, performedBy));
|
||||||
|
await _vNextSavePolicyCommand.SaveAsync(new SavePolicyModel(requireSsoPolicy, performedBy));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _savePolicyCommand.SaveAsync(singleOrgPolicy);
|
||||||
|
await _savePolicyCommand.SaveAsync(resetPasswordPolicy);
|
||||||
|
await _savePolicyCommand.SaveAsync(requireSsoPolicy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await LogEventsAsync(config, oldConfig);
|
await LogEventsAsync(config, oldConfig);
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ public static class FeatureFlagKeys
|
|||||||
public const string AutomaticConfirmUsers = "pm-19934-auto-confirm-organization-users";
|
public const string AutomaticConfirmUsers = "pm-19934-auto-confirm-organization-users";
|
||||||
public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache";
|
public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache";
|
||||||
public const string AccountRecoveryCommand = "pm-25581-prevent-provider-account-recovery";
|
public const string AccountRecoveryCommand = "pm-25581-prevent-provider-account-recovery";
|
||||||
|
public const string PolicyValidatorsRefactor = "pm-26423-refactor-policy-side-effects";
|
||||||
|
|
||||||
/* Auth Team */
|
/* Auth Team */
|
||||||
public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence";
|
public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence";
|
||||||
|
|||||||
@@ -35,4 +35,10 @@ public interface ISecurityTaskRepository : IRepository<SecurityTask, Guid>
|
|||||||
/// <param name="organizationId">The id of the organization</param>
|
/// <param name="organizationId">The id of the organization</param>
|
||||||
/// <returns>A collection of security task metrics</returns>
|
/// <returns>A collection of security task metrics</returns>
|
||||||
Task<SecurityTaskMetrics> GetTaskMetricsAsync(Guid organizationId);
|
Task<SecurityTaskMetrics> GetTaskMetricsAsync(Guid organizationId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks all tasks associated with the respective ciphers as complete.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipherIds">Collection of cipher IDs</param>
|
||||||
|
Task MarkAsCompleteByCipherIds(IEnumerable<Guid> cipherIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public class CipherService : ICipherService
|
|||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
private readonly ICollectionCipherRepository _collectionCipherRepository;
|
private readonly ICollectionCipherRepository _collectionCipherRepository;
|
||||||
|
private readonly ISecurityTaskRepository _securityTaskRepository;
|
||||||
private readonly IPushNotificationService _pushService;
|
private readonly IPushNotificationService _pushService;
|
||||||
private readonly IAttachmentStorageService _attachmentStorageService;
|
private readonly IAttachmentStorageService _attachmentStorageService;
|
||||||
private readonly IEventService _eventService;
|
private readonly IEventService _eventService;
|
||||||
@@ -53,6 +54,7 @@ public class CipherService : ICipherService
|
|||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
ICollectionCipherRepository collectionCipherRepository,
|
ICollectionCipherRepository collectionCipherRepository,
|
||||||
|
ISecurityTaskRepository securityTaskRepository,
|
||||||
IPushNotificationService pushService,
|
IPushNotificationService pushService,
|
||||||
IAttachmentStorageService attachmentStorageService,
|
IAttachmentStorageService attachmentStorageService,
|
||||||
IEventService eventService,
|
IEventService eventService,
|
||||||
@@ -71,6 +73,7 @@ public class CipherService : ICipherService
|
|||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
_collectionCipherRepository = collectionCipherRepository;
|
_collectionCipherRepository = collectionCipherRepository;
|
||||||
|
_securityTaskRepository = securityTaskRepository;
|
||||||
_pushService = pushService;
|
_pushService = pushService;
|
||||||
_attachmentStorageService = attachmentStorageService;
|
_attachmentStorageService = attachmentStorageService;
|
||||||
_eventService = eventService;
|
_eventService = eventService;
|
||||||
@@ -724,6 +727,7 @@ public class CipherService : ICipherService
|
|||||||
cipherDetails.ArchivedDate = null;
|
cipherDetails.ArchivedDate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _securityTaskRepository.MarkAsCompleteByCipherIds([cipherDetails.Id]);
|
||||||
await _cipherRepository.UpsertAsync(cipherDetails);
|
await _cipherRepository.UpsertAsync(cipherDetails);
|
||||||
await _eventService.LogCipherEventAsync(cipherDetails, EventType.Cipher_SoftDeleted);
|
await _eventService.LogCipherEventAsync(cipherDetails, EventType.Cipher_SoftDeleted);
|
||||||
|
|
||||||
@@ -750,6 +754,8 @@ public class CipherService : ICipherService
|
|||||||
await _cipherRepository.SoftDeleteAsync(deletingCiphers.Select(c => c.Id), deletingUserId);
|
await _cipherRepository.SoftDeleteAsync(deletingCiphers.Select(c => c.Id), deletingUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _securityTaskRepository.MarkAsCompleteByCipherIds(deletingCiphers.Select(c => c.Id));
|
||||||
|
|
||||||
var events = deletingCiphers.Select(c =>
|
var events = deletingCiphers.Select(c =>
|
||||||
new Tuple<Cipher, EventType, DateTime?>(c, EventType.Cipher_SoftDeleted, null));
|
new Tuple<Cipher, EventType, DateTime?>(c, EventType.Cipher_SoftDeleted, null));
|
||||||
foreach (var eventsBatch in events.Chunk(100))
|
foreach (var eventsBatch in events.Chunk(100))
|
||||||
|
|||||||
@@ -85,4 +85,19 @@ public class SecurityTaskRepository : Repository<SecurityTask, Guid>, ISecurityT
|
|||||||
|
|
||||||
return tasksList;
|
return tasksList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task MarkAsCompleteByCipherIds(IEnumerable<Guid> cipherIds)
|
||||||
|
{
|
||||||
|
if (!cipherIds.Any())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await using var connection = new SqlConnection(ConnectionString);
|
||||||
|
await connection.ExecuteAsync(
|
||||||
|
$"[{Schema}].[SecurityTask_MarkCompleteByCipherIds]",
|
||||||
|
new { CipherIds = cipherIds.ToGuidIdArrayTVP() },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,4 +96,24 @@ public class SecurityTaskRepository : Repository<Core.Vault.Entities.SecurityTas
|
|||||||
|
|
||||||
return metrics ?? new Core.Vault.Entities.SecurityTaskMetrics(0, 0);
|
return metrics ?? new Core.Vault.Entities.SecurityTaskMetrics(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task MarkAsCompleteByCipherIds(IEnumerable<Guid> cipherIds)
|
||||||
|
{
|
||||||
|
if (!cipherIds.Any())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var scope = ServiceScopeFactory.CreateScope();
|
||||||
|
var dbContext = GetDatabaseContext(scope);
|
||||||
|
|
||||||
|
var cipherIdsList = cipherIds.ToList();
|
||||||
|
|
||||||
|
await dbContext.SecurityTasks
|
||||||
|
.Where(st => st.CipherId.HasValue && cipherIdsList.Contains(st.CipherId.Value) && st.Status != SecurityTaskStatus.Completed)
|
||||||
|
.ExecuteUpdateAsync(st => st
|
||||||
|
.SetProperty(s => s.Status, SecurityTaskStatus.Completed)
|
||||||
|
.SetProperty(s => s.RevisionDate, DateTime.UtcNow));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[SecurityTask_MarkCompleteByCipherIds]
|
||||||
|
@CipherIds AS [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
[dbo].[SecurityTask]
|
||||||
|
SET
|
||||||
|
[Status] = 1, -- completed
|
||||||
|
[RevisionDate] = SYSUTCDATETIME()
|
||||||
|
WHERE
|
||||||
|
[CipherId] IN (SELECT [Id] FROM @CipherIds)
|
||||||
|
AND [Status] <> 1 -- Not already completed
|
||||||
|
END
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using Bit.Api.AdminConsole.Public.Controllers;
|
||||||
|
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
using Bit.Core;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
using NSubstitute;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Api.Test.AdminConsole.Public.Controllers;
|
||||||
|
|
||||||
|
[ControllerCustomize(typeof(PoliciesController))]
|
||||||
|
[SutProviderCustomize]
|
||||||
|
public class PoliciesControllerTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task Put_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
|
||||||
|
Guid organizationId,
|
||||||
|
PolicyType policyType,
|
||||||
|
PolicyUpdateRequestModel model,
|
||||||
|
Policy policy,
|
||||||
|
SutProvider<PoliciesController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
policy.Data = null;
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.OrganizationId.Returns(organizationId);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||||
|
.Returns(true);
|
||||||
|
sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.SaveAsync(Arg.Any<SavePolicyModel>())
|
||||||
|
.Returns(policy);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.Put(policyType, model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
|
||||||
|
m.PolicyUpdate.OrganizationId == organizationId &&
|
||||||
|
m.PolicyUpdate.Type == policyType &&
|
||||||
|
m.PolicyUpdate.Enabled == model.Enabled.GetValueOrDefault() &&
|
||||||
|
m.PerformedBy is SystemUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task Put_WhenPolicyValidatorsRefactorDisabled_UsesLegacySavePolicyCommand(
|
||||||
|
Guid organizationId,
|
||||||
|
PolicyType policyType,
|
||||||
|
PolicyUpdateRequestModel model,
|
||||||
|
Policy policy,
|
||||||
|
SutProvider<PoliciesController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
policy.Data = null;
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.OrganizationId.Returns(organizationId);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||||
|
.Returns(false);
|
||||||
|
sutProvider.GetDependency<ISavePolicyCommand>()
|
||||||
|
.SaveAsync(Arg.Any<PolicyUpdate>())
|
||||||
|
.Returns(policy);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.Put(policyType, model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<ISavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<PolicyUpdate>(p =>
|
||||||
|
p.OrganizationId == organizationId &&
|
||||||
|
p.Type == policyType &&
|
||||||
|
p.Enabled == model.Enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Bit.Api.AdminConsole.Controllers;
|
using Bit.Api.AdminConsole.Controllers;
|
||||||
|
using Bit.Api.AdminConsole.Models.Request;
|
||||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
using Bit.Core;
|
||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
@@ -455,4 +460,98 @@ public class PoliciesControllerTests
|
|||||||
Assert.Equal(enabledPolicy.Type, expectedPolicy.Type);
|
Assert.Equal(enabledPolicy.Type, expectedPolicy.Type);
|
||||||
Assert.Equal(enabledPolicy.Enabled, expectedPolicy.Enabled);
|
Assert.Equal(enabledPolicy.Enabled, expectedPolicy.Enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task PutVNext_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
|
||||||
|
SutProvider<PoliciesController> sutProvider, Guid orgId,
|
||||||
|
SavePolicyRequest model, Policy policy, Guid userId)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
policy.Data = null;
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.UserId
|
||||||
|
.Returns(userId);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.OrganizationOwner(orgId)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.SaveAsync(Arg.Any<SavePolicyModel>())
|
||||||
|
.Returns(policy);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await sutProvider.Sut.PutVNext(orgId, model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<SavePolicyModel>(
|
||||||
|
m => m.PolicyUpdate.OrganizationId == orgId &&
|
||||||
|
m.PolicyUpdate.Type == model.Policy.Type &&
|
||||||
|
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
|
||||||
|
m.PerformedBy.UserId == userId &&
|
||||||
|
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ISavePolicyCommand>()
|
||||||
|
.DidNotReceiveWithAnyArgs()
|
||||||
|
.VNextSaveAsync(default);
|
||||||
|
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(policy.Id, result.Id);
|
||||||
|
Assert.Equal(policy.Type, result.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task PutVNext_WhenPolicyValidatorsRefactorDisabled_UsesSavePolicyCommand(
|
||||||
|
SutProvider<PoliciesController> sutProvider, Guid orgId,
|
||||||
|
SavePolicyRequest model, Policy policy, Guid userId)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
policy.Data = null;
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.UserId
|
||||||
|
.Returns(userId);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.OrganizationOwner(orgId)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ISavePolicyCommand>()
|
||||||
|
.VNextSaveAsync(Arg.Any<SavePolicyModel>())
|
||||||
|
.Returns(policy);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await sutProvider.Sut.PutVNext(orgId, model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<ISavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.VNextSaveAsync(Arg.Is<SavePolicyModel>(
|
||||||
|
m => m.PolicyUpdate.OrganizationId == orgId &&
|
||||||
|
m.PolicyUpdate.Type == model.Policy.Type &&
|
||||||
|
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
|
||||||
|
m.PerformedBy.UserId == userId &&
|
||||||
|
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.DidNotReceiveWithAnyArgs()
|
||||||
|
.SaveAsync(default);
|
||||||
|
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(policy.Id, result.Id);
|
||||||
|
Assert.Equal(policy.Type, result.Type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Bit.Core.AdminConsole.Models.Data;
|
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -191,6 +192,37 @@ public class VerifyOrganizationDomainCommandTests
|
|||||||
x.PerformedBy.UserId == userId));
|
x.PerformedBy.UserId == userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UserVerifyOrganizationDomainAsync_WhenPolicyValidatorsRefactorFlagEnabled_UsesVNextSavePolicyCommand(
|
||||||
|
OrganizationDomain domain, Guid userId, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||||
|
.GetClaimedDomainsByDomainNameAsync(domain.DomainName)
|
||||||
|
.Returns([]);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IDnsResolverService>()
|
||||||
|
.ResolveAsync(domain.DomainName, domain.Txt)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>()
|
||||||
|
.UserId.Returns(userId);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
|
||||||
|
m.PolicyUpdate.Type == PolicyType.SingleOrg &&
|
||||||
|
m.PolicyUpdate.OrganizationId == domain.OrganizationId &&
|
||||||
|
m.PolicyUpdate.Enabled &&
|
||||||
|
m.PerformedBy is StandardUser &&
|
||||||
|
m.PerformedBy.UserId == userId));
|
||||||
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task UserVerifyOrganizationDomainAsync_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled(
|
public async Task UserVerifyOrganizationDomainAsync_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled(
|
||||||
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public class FreeFamiliesForEnterprisePolicyValidatorTests
|
|||||||
.GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(organizationSponsorships);
|
.Returns(organizationSponsorships);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ public class FreeFamiliesForEnterprisePolicyValidatorTests
|
|||||||
.GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(organizationSponsorships);
|
.Returns(organizationSponsorships);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(false);
|
.Returns(false);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -58,7 +58,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -84,7 +84,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -110,7 +110,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
var collectionRepository = Substitute.For<ICollectionRepository>();
|
var collectionRepository = Substitute.For<ICollectionRepository>();
|
||||||
|
|
||||||
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -199,7 +199,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
var collectionRepository = Substitute.For<ICollectionRepository>();
|
var collectionRepository = Substitute.For<ICollectionRepository>();
|
||||||
|
|
||||||
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -238,7 +238,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, metadata);
|
var policyRequest = new SavePolicyModel(policyUpdate, metadata);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -286,7 +286,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(false);
|
.Returns(false);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -312,7 +312,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -338,7 +338,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -364,7 +364,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
var collectionRepository = Substitute.For<ICollectionRepository>();
|
var collectionRepository = Substitute.For<ICollectionRepository>();
|
||||||
|
|
||||||
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -404,7 +404,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
var collectionRepository = Substitute.For<ICollectionRepository>();
|
var collectionRepository = Substitute.For<ICollectionRepository>();
|
||||||
|
|
||||||
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
var sut = ArrangeSut(factory, policyRepository, collectionRepository);
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
@@ -436,7 +436,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
|
|||||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var policyRequest = new SavePolicyModel(policyUpdate, null, metadata);
|
var policyRequest = new SavePolicyModel(policyUpdate, metadata);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class RequireSsoPolicyValidatorTests
|
|||||||
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(ssoConfig);
|
.Returns(ssoConfig);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase);
|
||||||
@@ -109,7 +109,7 @@ public class RequireSsoPolicyValidatorTests
|
|||||||
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(ssoConfig);
|
.Returns(ssoConfig);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.Contains("Trusted device encryption is on", result, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Trusted device encryption is on", result, StringComparison.OrdinalIgnoreCase);
|
||||||
@@ -129,7 +129,7 @@ public class RequireSsoPolicyValidatorTests
|
|||||||
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(ssoConfig);
|
.Returns(ssoConfig);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.True(string.IsNullOrEmpty(result));
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public class ResetPasswordPolicyValidatorTests
|
|||||||
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(ssoConfig);
|
.Returns(ssoConfig);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.Contains("Trusted device encryption is on and requires this policy.", result, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Trusted device encryption is on and requires this policy.", result, StringComparison.OrdinalIgnoreCase);
|
||||||
@@ -118,7 +118,7 @@ public class ResetPasswordPolicyValidatorTests
|
|||||||
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(ssoConfig);
|
.Returns(ssoConfig);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.True(string.IsNullOrEmpty(result));
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public class SingleOrgPolicyValidatorTests
|
|||||||
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
.GetByOrganizationIdAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(ssoConfig);
|
.Returns(ssoConfig);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase);
|
||||||
@@ -186,7 +186,7 @@ public class SingleOrgPolicyValidatorTests
|
|||||||
.HasVerifiedDomainsAsync(policyUpdate.OrganizationId)
|
.HasVerifiedDomainsAsync(policyUpdate.OrganizationId)
|
||||||
.Returns(false);
|
.Returns(false);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.True(string.IsNullOrEmpty(result));
|
||||||
@@ -256,7 +256,7 @@ public class SingleOrgPolicyValidatorTests
|
|||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
||||||
.Returns(new CommandResult());
|
.Returns(new CommandResult());
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public class TwoFactorAuthenticationPolicyValidatorTests
|
|||||||
(orgUserDetailUserWithout2Fa, false),
|
(orgUserDetailUserWithout2Fa, false),
|
||||||
});
|
});
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||||
sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy));
|
sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy));
|
||||||
@@ -228,7 +228,7 @@ public class TwoFactorAuthenticationPolicyValidatorTests
|
|||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
||||||
.Returns(new CommandResult());
|
.Returns(new CommandResult());
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ public class SavePolicyCommandTests
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var sutProvider = SutProviderFactory();
|
var sutProvider = SutProviderFactory();
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
sutProvider.GetDependency<IPolicyRepository>()
|
||||||
@@ -332,7 +332,7 @@ public class SavePolicyCommandTests
|
|||||||
|
|
||||||
|
|
||||||
var sutProvider = SutProviderFactory();
|
var sutProvider = SutProviderFactory();
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
sutProvider.GetDependency<IPolicyRepository>()
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, policyUpdate.Type)
|
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, policyUpdate.Type)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
fakePolicyValidationEvent
|
fakePolicyValidationEvent
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var newPolicy = new Policy
|
var newPolicy = new Policy
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
fakePolicyValidationEvent
|
fakePolicyValidationEvent
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
sutProvider.GetDependency<IPolicyRepository>()
|
||||||
@@ -117,7 +117,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var sutProvider = SutProviderFactory();
|
var sutProvider = SutProviderFactory();
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
sutProvider.GetDependency<IApplicationCacheService>()
|
sutProvider.GetDependency<IApplicationCacheService>()
|
||||||
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
|
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
|
||||||
@@ -137,7 +137,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var sutProvider = SutProviderFactory();
|
var sutProvider = SutProviderFactory();
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
sutProvider.GetDependency<IApplicationCacheService>()
|
sutProvider.GetDependency<IApplicationCacheService>()
|
||||||
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
|
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
|
||||||
@@ -167,7 +167,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
new FakeSingleOrgDependencyEvent()
|
new FakeSingleOrgDependencyEvent()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var requireSsoPolicy = new Policy
|
var requireSsoPolicy = new Policy
|
||||||
{
|
{
|
||||||
@@ -202,7 +202,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
new FakeSingleOrgDependencyEvent()
|
new FakeSingleOrgDependencyEvent()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var requireSsoPolicy = new Policy
|
var requireSsoPolicy = new Policy
|
||||||
{
|
{
|
||||||
@@ -237,7 +237,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
new FakeSingleOrgDependencyEvent()
|
new FakeSingleOrgDependencyEvent()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var requireSsoPolicy = new Policy
|
var requireSsoPolicy = new Policy
|
||||||
{
|
{
|
||||||
@@ -271,7 +271,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
new FakeSingleOrgDependencyEvent()
|
new FakeSingleOrgDependencyEvent()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
ArrangeOrganization(sutProvider, policyUpdate);
|
ArrangeOrganization(sutProvider, policyUpdate);
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
sutProvider.GetDependency<IPolicyRepository>()
|
||||||
@@ -302,7 +302,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
new FakeVaultTimeoutDependencyEvent()
|
new FakeVaultTimeoutDependencyEvent()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
ArrangeOrganization(sutProvider, policyUpdate);
|
ArrangeOrganization(sutProvider, policyUpdate);
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
sutProvider.GetDependency<IPolicyRepository>()
|
||||||
@@ -331,7 +331,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
new FakeSingleOrgDependencyEvent()
|
new FakeSingleOrgDependencyEvent()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
ArrangeOrganization(sutProvider, policyUpdate);
|
ArrangeOrganization(sutProvider, policyUpdate);
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
sutProvider.GetDependency<IPolicyRepository>()
|
||||||
@@ -356,7 +356,7 @@ public class VNextSavePolicyCommandTests
|
|||||||
fakePolicyValidationEvent
|
fakePolicyValidationEvent
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
var singleOrgPolicy = new Policy
|
var singleOrgPolicy = new Policy
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data;
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Auth.Enums;
|
using Bit.Core.Auth.Enums;
|
||||||
@@ -12,6 +14,7 @@ using Bit.Core.Auth.Services;
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
|
using Bit.Core.Services;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
@@ -364,4 +367,54 @@ public class SsoConfigServiceTests
|
|||||||
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
|
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
|
||||||
.UpsertAsync(default);
|
.UpsertAsync(default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task SaveAsync_Tde_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
|
||||||
|
SutProvider<SsoConfigService> sutProvider, Organization organization)
|
||||||
|
{
|
||||||
|
var ssoConfig = new SsoConfig
|
||||||
|
{
|
||||||
|
Id = default,
|
||||||
|
Data = new SsoConfigurationData
|
||||||
|
{
|
||||||
|
MemberDecryptionType = MemberDecryptionType.TrustedDeviceEncryption,
|
||||||
|
}.Serialize(),
|
||||||
|
Enabled = true,
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
};
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
|
||||||
|
m.PolicyUpdate.Type == PolicyType.SingleOrg &&
|
||||||
|
m.PolicyUpdate.OrganizationId == organization.Id &&
|
||||||
|
m.PolicyUpdate.Enabled &&
|
||||||
|
m.PerformedBy is SystemUser));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
|
||||||
|
m.PolicyUpdate.Type == PolicyType.ResetPassword &&
|
||||||
|
m.PolicyUpdate.GetDataModel<ResetPasswordDataModel>().AutoEnrollEnabled &&
|
||||||
|
m.PolicyUpdate.OrganizationId == organization.Id &&
|
||||||
|
m.PolicyUpdate.Enabled &&
|
||||||
|
m.PerformedBy is SystemUser));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
|
||||||
|
m.PolicyUpdate.Type == PolicyType.RequireSso &&
|
||||||
|
m.PolicyUpdate.OrganizationId == organization.Id &&
|
||||||
|
m.PolicyUpdate.Enabled &&
|
||||||
|
m.PerformedBy is SystemUser));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
|
||||||
|
.UpsertAsync(default);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2286,6 +2286,63 @@ public class CipherServiceTests
|
|||||||
.PushSyncCiphersAsync(deletingUserId);
|
.PushSyncCiphersAsync(deletingUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task SoftDeleteAsync_CallsMarkAsCompleteByCipherIds(
|
||||||
|
Guid deletingUserId, CipherDetails cipherDetails, SutProvider<CipherService> sutProvider)
|
||||||
|
{
|
||||||
|
cipherDetails.UserId = deletingUserId;
|
||||||
|
cipherDetails.OrganizationId = null;
|
||||||
|
cipherDetails.DeletedDate = null;
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IUserService>()
|
||||||
|
.GetUserByIdAsync(deletingUserId)
|
||||||
|
.Returns(new User
|
||||||
|
{
|
||||||
|
Id = deletingUserId,
|
||||||
|
});
|
||||||
|
|
||||||
|
await sutProvider.Sut.SoftDeleteAsync(cipherDetails, deletingUserId);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ISecurityTaskRepository>()
|
||||||
|
.Received(1)
|
||||||
|
.MarkAsCompleteByCipherIds(Arg.Is<IEnumerable<Guid>>(ids =>
|
||||||
|
ids.Count() == 1 && ids.First() == cipherDetails.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task SoftDeleteManyAsync_CallsMarkAsCompleteByCipherIds(
|
||||||
|
Guid deletingUserId, List<CipherDetails> ciphers, SutProvider<CipherService> sutProvider)
|
||||||
|
{
|
||||||
|
var cipherIds = ciphers.Select(c => c.Id).ToArray();
|
||||||
|
|
||||||
|
foreach (var cipher in ciphers)
|
||||||
|
{
|
||||||
|
cipher.UserId = deletingUserId;
|
||||||
|
cipher.OrganizationId = null;
|
||||||
|
cipher.Edit = true;
|
||||||
|
cipher.DeletedDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IUserService>()
|
||||||
|
.GetUserByIdAsync(deletingUserId)
|
||||||
|
.Returns(new User
|
||||||
|
{
|
||||||
|
Id = deletingUserId,
|
||||||
|
});
|
||||||
|
sutProvider.GetDependency<ICipherRepository>()
|
||||||
|
.GetManyByUserIdAsync(deletingUserId)
|
||||||
|
.Returns(ciphers);
|
||||||
|
|
||||||
|
await sutProvider.Sut.SoftDeleteManyAsync(cipherIds, deletingUserId, null, false);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ISecurityTaskRepository>()
|
||||||
|
.Received(1)
|
||||||
|
.MarkAsCompleteByCipherIds(Arg.Is<IEnumerable<Guid>>(ids =>
|
||||||
|
ids.Count() == cipherIds.Length && ids.All(id => cipherIds.Contains(id))));
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AssertNoActionsAsync(SutProvider<CipherService> sutProvider)
|
private async Task AssertNoActionsAsync(SutProvider<CipherService> sutProvider)
|
||||||
{
|
{
|
||||||
await sutProvider.GetDependency<ICipherRepository>().DidNotReceiveWithAnyArgs().GetManyOrganizationDetailsByOrganizationIdAsync(default);
|
await sutProvider.GetDependency<ICipherRepository>().DidNotReceiveWithAnyArgs().GetManyOrganizationDetailsByOrganizationIdAsync(default);
|
||||||
|
|||||||
@@ -345,4 +345,110 @@ public class SecurityTaskRepositoryTests
|
|||||||
Assert.Equal(0, metrics.CompletedTasks);
|
Assert.Equal(0, metrics.CompletedTasks);
|
||||||
Assert.Equal(0, metrics.TotalTasks);
|
Assert.Equal(0, metrics.TotalTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DatabaseTheory, DatabaseData]
|
||||||
|
public async Task MarkAsCompleteByCipherIds_MarksPendingTasksAsCompleted(
|
||||||
|
IOrganizationRepository organizationRepository,
|
||||||
|
ICipherRepository cipherRepository,
|
||||||
|
ISecurityTaskRepository securityTaskRepository)
|
||||||
|
{
|
||||||
|
var organization = await organizationRepository.CreateAsync(new Organization
|
||||||
|
{
|
||||||
|
Name = "Test Org",
|
||||||
|
PlanType = PlanType.EnterpriseAnnually,
|
||||||
|
Plan = "Test Plan",
|
||||||
|
BillingEmail = "billing@email.com"
|
||||||
|
});
|
||||||
|
|
||||||
|
var cipher1 = await cipherRepository.CreateAsync(new Cipher
|
||||||
|
{
|
||||||
|
Type = CipherType.Login,
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
Data = "",
|
||||||
|
});
|
||||||
|
|
||||||
|
var cipher2 = await cipherRepository.CreateAsync(new Cipher
|
||||||
|
{
|
||||||
|
Type = CipherType.Login,
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
Data = "",
|
||||||
|
});
|
||||||
|
|
||||||
|
var task1 = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||||
|
{
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
CipherId = cipher1.Id,
|
||||||
|
Status = SecurityTaskStatus.Pending,
|
||||||
|
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||||
|
});
|
||||||
|
|
||||||
|
var task2 = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||||
|
{
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
CipherId = cipher2.Id,
|
||||||
|
Status = SecurityTaskStatus.Pending,
|
||||||
|
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||||
|
});
|
||||||
|
|
||||||
|
await securityTaskRepository.MarkAsCompleteByCipherIds([cipher1.Id, cipher2.Id]);
|
||||||
|
|
||||||
|
var updatedTask1 = await securityTaskRepository.GetByIdAsync(task1.Id);
|
||||||
|
var updatedTask2 = await securityTaskRepository.GetByIdAsync(task2.Id);
|
||||||
|
|
||||||
|
Assert.Equal(SecurityTaskStatus.Completed, updatedTask1.Status);
|
||||||
|
Assert.Equal(SecurityTaskStatus.Completed, updatedTask2.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseTheory, DatabaseData]
|
||||||
|
public async Task MarkAsCompleteByCipherIds_OnlyUpdatesSpecifiedCiphers(
|
||||||
|
IOrganizationRepository organizationRepository,
|
||||||
|
ICipherRepository cipherRepository,
|
||||||
|
ISecurityTaskRepository securityTaskRepository)
|
||||||
|
{
|
||||||
|
var organization = await organizationRepository.CreateAsync(new Organization
|
||||||
|
{
|
||||||
|
Name = "Test Org",
|
||||||
|
PlanType = PlanType.EnterpriseAnnually,
|
||||||
|
Plan = "Test Plan",
|
||||||
|
BillingEmail = "billing@email.com"
|
||||||
|
});
|
||||||
|
|
||||||
|
var cipher1 = await cipherRepository.CreateAsync(new Cipher
|
||||||
|
{
|
||||||
|
Type = CipherType.Login,
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
Data = "",
|
||||||
|
});
|
||||||
|
|
||||||
|
var cipher2 = await cipherRepository.CreateAsync(new Cipher
|
||||||
|
{
|
||||||
|
Type = CipherType.Login,
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
Data = "",
|
||||||
|
});
|
||||||
|
|
||||||
|
var taskToUpdate = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||||
|
{
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
CipherId = cipher1.Id,
|
||||||
|
Status = SecurityTaskStatus.Pending,
|
||||||
|
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||||
|
});
|
||||||
|
|
||||||
|
var taskToKeep = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||||
|
{
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
CipherId = cipher2.Id,
|
||||||
|
Status = SecurityTaskStatus.Pending,
|
||||||
|
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||||
|
});
|
||||||
|
|
||||||
|
await securityTaskRepository.MarkAsCompleteByCipherIds([cipher1.Id]);
|
||||||
|
|
||||||
|
var updatedTask = await securityTaskRepository.GetByIdAsync(taskToUpdate.Id);
|
||||||
|
var unchangedTask = await securityTaskRepository.GetByIdAsync(taskToKeep.Id);
|
||||||
|
|
||||||
|
Assert.Equal(SecurityTaskStatus.Completed, updatedTask.Status);
|
||||||
|
Assert.Equal(SecurityTaskStatus.Pending, unchangedTask.Status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
CREATE OR ALTER PROCEDURE [dbo].[SecurityTask_MarkCompleteByCipherIds]
|
||||||
|
@CipherIds AS [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
[dbo].[SecurityTask]
|
||||||
|
SET
|
||||||
|
[Status] = 1, -- Completed
|
||||||
|
[RevisionDate] = SYSUTCDATETIME()
|
||||||
|
WHERE
|
||||||
|
[CipherId] IN (SELECT [Id] FROM @CipherIds)
|
||||||
|
AND [Status] <> 1 -- Not already completed
|
||||||
|
END
|
||||||
Reference in New Issue
Block a user