Skip to content

Commit 44b6879

Browse files
authored
[PM-14245] Remove policy definitions feature flag (#5095)
* Remove PolicyService.SaveAsync and use command instead * Delete feature flag definition * Add public api integration tests
1 parent c9aa61b commit 44b6879

File tree

17 files changed

+292
-1128
lines changed

17 files changed

+292
-1128
lines changed

src/Api/AdminConsole/Controllers/PoliciesController.cs

+12-17
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
using Bit.Core.AdminConsole.Entities;
77
using Bit.Core.AdminConsole.Enums;
88
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
9+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
910
using Bit.Core.AdminConsole.Repositories;
10-
using Bit.Core.AdminConsole.Services;
1111
using Bit.Core.Auth.Models.Business.Tokenables;
1212
using Bit.Core.Context;
1313
using Bit.Core.Enums;
@@ -28,7 +28,6 @@ namespace Bit.Api.AdminConsole.Controllers;
2828
public class PoliciesController : Controller
2929
{
3030
private readonly IPolicyRepository _policyRepository;
31-
private readonly IPolicyService _policyService;
3231
private readonly IOrganizationUserRepository _organizationUserRepository;
3332
private readonly IUserService _userService;
3433
private readonly ICurrentContext _currentContext;
@@ -37,21 +36,21 @@ public class PoliciesController : Controller
3736
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
3837
private readonly IFeatureService _featureService;
3938
private readonly IOrganizationHasVerifiedDomainsQuery _organizationHasVerifiedDomainsQuery;
39+
private readonly ISavePolicyCommand _savePolicyCommand;
4040

4141
public PoliciesController(
4242
IPolicyRepository policyRepository,
43-
IPolicyService policyService,
4443
IOrganizationUserRepository organizationUserRepository,
4544
IUserService userService,
4645
ICurrentContext currentContext,
4746
GlobalSettings globalSettings,
4847
IDataProtectionProvider dataProtectionProvider,
4948
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
5049
IFeatureService featureService,
51-
IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery)
50+
IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery,
51+
ISavePolicyCommand savePolicyCommand)
5252
{
5353
_policyRepository = policyRepository;
54-
_policyService = policyService;
5554
_organizationUserRepository = organizationUserRepository;
5655
_userService = userService;
5756
_currentContext = currentContext;
@@ -62,6 +61,7 @@ public PoliciesController(
6261
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
6362
_featureService = featureService;
6463
_organizationHasVerifiedDomainsQuery = organizationHasVerifiedDomainsQuery;
64+
_savePolicyCommand = savePolicyCommand;
6565
}
6666

6767
[HttpGet("{type}")]
@@ -178,25 +178,20 @@ public async Task<PolicyResponseModel> GetMasterPasswordPolicy(Guid orgId)
178178
}
179179

180180
[HttpPut("{type}")]
181-
public async Task<PolicyResponseModel> Put(string orgId, int type, [FromBody] PolicyRequestModel model)
181+
public async Task<PolicyResponseModel> Put(Guid orgId, PolicyType type, [FromBody] PolicyRequestModel model)
182182
{
183-
var orgIdGuid = new Guid(orgId);
184-
if (!await _currentContext.ManagePolicies(orgIdGuid))
183+
if (!await _currentContext.ManagePolicies(orgId))
185184
{
186185
throw new NotFoundException();
187186
}
188-
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(new Guid(orgId), (PolicyType)type);
189-
if (policy == null)
190-
{
191-
policy = model.ToPolicy(orgIdGuid);
192-
}
193-
else
187+
188+
if (type != model.Type)
194189
{
195-
policy = model.ToPolicy(policy);
190+
throw new BadRequestException("Mismatched policy type");
196191
}
197192

198-
var userId = _userService.GetProperUserId(User);
199-
await _policyService.SaveAsync(policy, userId);
193+
var policyUpdate = await model.ToPolicyUpdateAsync(orgId, _currentContext);
194+
var policy = await _savePolicyCommand.SaveAsync(policyUpdate);
200195
return new PolicyResponseModel(policy);
201196
}
202197
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System.ComponentModel.DataAnnotations;
22
using System.Text.Json;
3-
using Bit.Core.AdminConsole.Entities;
43
using Bit.Core.AdminConsole.Enums;
4+
using Bit.Core.AdminConsole.Models.Data;
5+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
6+
using Bit.Core.Context;
57

68
namespace Bit.Api.AdminConsole.Models.Request;
79

@@ -13,19 +15,12 @@ public class PolicyRequestModel
1315
public bool? Enabled { get; set; }
1416
public Dictionary<string, object> Data { get; set; }
1517

16-
public Policy ToPolicy(Guid orgId)
18+
public async Task<PolicyUpdate> ToPolicyUpdateAsync(Guid organizationId, ICurrentContext currentContext) => new()
1719
{
18-
return ToPolicy(new Policy
19-
{
20-
Type = Type.Value,
21-
OrganizationId = orgId
22-
});
23-
}
24-
25-
public Policy ToPolicy(Policy existingPolicy)
26-
{
27-
existingPolicy.Enabled = Enabled.GetValueOrDefault();
28-
existingPolicy.Data = Data != null ? JsonSerializer.Serialize(Data) : null;
29-
return existingPolicy;
30-
}
20+
Type = Type!.Value,
21+
OrganizationId = organizationId,
22+
Data = Data != null ? JsonSerializer.Serialize(Data) : null,
23+
Enabled = Enabled.GetValueOrDefault(),
24+
PerformedBy = new StandardUser(currentContext.UserId!.Value, await currentContext.OrganizationOwner(organizationId))
25+
};
3126
}

src/Api/AdminConsole/Public/Controllers/PoliciesController.cs

+8-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Bit.Api.AdminConsole.Public.Models.Response;
44
using Bit.Api.Models.Public.Response;
55
using Bit.Core.AdminConsole.Enums;
6+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
67
using Bit.Core.AdminConsole.Repositories;
78
using Bit.Core.AdminConsole.Services;
89
using Bit.Core.Context;
@@ -18,15 +19,18 @@ public class PoliciesController : Controller
1819
private readonly IPolicyRepository _policyRepository;
1920
private readonly IPolicyService _policyService;
2021
private readonly ICurrentContext _currentContext;
22+
private readonly ISavePolicyCommand _savePolicyCommand;
2123

2224
public PoliciesController(
2325
IPolicyRepository policyRepository,
2426
IPolicyService policyService,
25-
ICurrentContext currentContext)
27+
ICurrentContext currentContext,
28+
ISavePolicyCommand savePolicyCommand)
2629
{
2730
_policyRepository = policyRepository;
2831
_policyService = policyService;
2932
_currentContext = currentContext;
33+
_savePolicyCommand = savePolicyCommand;
3034
}
3135

3236
/// <summary>
@@ -80,17 +84,9 @@ public async Task<IActionResult> List()
8084
[ProducesResponseType((int)HttpStatusCode.NotFound)]
8185
public async Task<IActionResult> Put(PolicyType type, [FromBody] PolicyUpdateRequestModel model)
8286
{
83-
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(
84-
_currentContext.OrganizationId.Value, type);
85-
if (policy == null)
86-
{
87-
policy = model.ToPolicy(_currentContext.OrganizationId.Value, type);
88-
}
89-
else
90-
{
91-
policy = model.ToPolicy(policy);
92-
}
93-
await _policyService.SaveAsync(policy, null);
87+
var policyUpdate = model.ToPolicyUpdate(_currentContext.OrganizationId!.Value, type);
88+
var policy = await _savePolicyCommand.SaveAsync(policyUpdate);
89+
9490
var response = new PolicyResponseModel(policy);
9591
return new JsonResult(response);
9692
}
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
11
using System.Text.Json;
2-
using Bit.Core.AdminConsole.Entities;
32
using Bit.Core.AdminConsole.Enums;
3+
using Bit.Core.AdminConsole.Models.Data;
4+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
5+
using Bit.Core.Enums;
46

57
namespace Bit.Api.AdminConsole.Public.Models.Request;
68

79
public class PolicyUpdateRequestModel : PolicyBaseModel
810
{
9-
public Policy ToPolicy(Guid orgId, PolicyType type)
11+
public PolicyUpdate ToPolicyUpdate(Guid organizationId, PolicyType type) => new()
1012
{
11-
return ToPolicy(new Policy
12-
{
13-
OrganizationId = orgId,
14-
Enabled = Enabled.GetValueOrDefault(),
15-
Data = Data != null ? JsonSerializer.Serialize(Data) : null,
16-
Type = type
17-
});
18-
}
19-
20-
public virtual Policy ToPolicy(Policy existingPolicy)
21-
{
22-
existingPolicy.Enabled = Enabled.GetValueOrDefault();
23-
existingPolicy.Data = Data != null ? JsonSerializer.Serialize(Data) : null;
24-
return existingPolicy;
25-
}
13+
Type = type,
14+
OrganizationId = organizationId,
15+
Data = Data != null ? JsonSerializer.Serialize(Data) : null,
16+
Enabled = Enabled.GetValueOrDefault(),
17+
PerformedBy = new SystemUser(EventSystemUser.PublicApi)
18+
};
2619
}

src/Api/AdminConsole/Public/Models/Response/PolicyResponseModel.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
using System.ComponentModel.DataAnnotations;
2-
using System.Text.Json;
32
using Bit.Api.Models.Public.Response;
43
using Bit.Core.AdminConsole.Entities;
54
using Bit.Core.AdminConsole.Enums;
5+
using Newtonsoft.Json;
6+
using JsonSerializer = System.Text.Json.JsonSerializer;
67

78
namespace Bit.Api.AdminConsole.Public.Models.Response;
89

@@ -11,6 +12,9 @@ namespace Bit.Api.AdminConsole.Public.Models.Response;
1112
/// </summary>
1213
public class PolicyResponseModel : PolicyBaseModel, IResponseModel
1314
{
15+
[JsonConstructor]
16+
public PolicyResponseModel() { }
17+
1418
public PolicyResponseModel(Policy policy)
1519
{
1620
if (policy == null)

src/Core/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
using Bit.Core.AdminConsole.Entities;
2-
using Bit.Core.AdminConsole.Enums;
1+
using Bit.Core.AdminConsole.Enums;
32
using Bit.Core.AdminConsole.Models.Data;
43
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
5-
using Bit.Core.AdminConsole.Services;
4+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
5+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
66
using Bit.Core.Context;
77
using Bit.Core.Entities;
88
using Bit.Core.Enums;
@@ -19,9 +19,9 @@ public class VerifyOrganizationDomainCommand(
1919
IDnsResolverService dnsResolverService,
2020
IEventService eventService,
2121
IGlobalSettings globalSettings,
22-
IPolicyService policyService,
2322
IFeatureService featureService,
2423
ICurrentContext currentContext,
24+
ISavePolicyCommand savePolicyCommand,
2525
ILogger<VerifyOrganizationDomainCommand> logger)
2626
: IVerifyOrganizationDomainCommand
2727
{
@@ -125,10 +125,15 @@ private async Task EnableSingleOrganizationPolicyAsync(Guid organizationId, IAct
125125
{
126126
if (featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning))
127127
{
128-
await policyService.SaveAsync(
129-
new Policy { OrganizationId = organizationId, Type = PolicyType.SingleOrg, Enabled = true },
130-
savingUserId: actingUser is StandardUser standardUser ? standardUser.UserId : null,
131-
eventSystemUser: actingUser is SystemUser systemUser ? systemUser.SystemUserType : null);
128+
var policyUpdate = new PolicyUpdate
129+
{
130+
OrganizationId = organizationId,
131+
Type = PolicyType.SingleOrg,
132+
Enabled = true,
133+
PerformedBy = actingUser
134+
};
135+
136+
await savePolicyCommand.SaveAsync(policyUpdate);
132137
}
133138
}
134139
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
1+
using Bit.Core.AdminConsole.Entities;
2+
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
23

34
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies;
45

56
public interface ISavePolicyCommand
67
{
7-
Task SaveAsync(PolicyUpdate policy);
8+
Task<Policy> SaveAsync(PolicyUpdate policy);
89
}

src/Core/AdminConsole/OrganizationFeatures/Policies/Implementations/SavePolicyCommand.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public SavePolicyCommand(
4242
_policyValidators = policyValidatorsDict;
4343
}
4444

45-
public async Task SaveAsync(PolicyUpdate policyUpdate)
45+
public async Task<Policy> SaveAsync(PolicyUpdate policyUpdate)
4646
{
4747
var org = await _applicationCacheService.GetOrganizationAbilityAsync(policyUpdate.OrganizationId);
4848
if (org == null)
@@ -74,6 +74,8 @@ public async Task SaveAsync(PolicyUpdate policyUpdate)
7474

7575
await _policyRepository.UpsertAsync(policy);
7676
await _eventService.LogPolicyEventAsync(policy, EventType.Policy_Updated);
77+
78+
return policy;
7779
}
7880

7981
private async Task RunValidatorAsync(IPolicyValidator validator, PolicyUpdate policyUpdate)

src/Core/AdminConsole/Services/IPolicyService.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Bit.Core.AdminConsole.Entities;
2-
using Bit.Core.AdminConsole.Enums;
1+
using Bit.Core.AdminConsole.Enums;
32
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
43
using Bit.Core.Entities;
54
using Bit.Core.Enums;
@@ -9,8 +8,6 @@ namespace Bit.Core.AdminConsole.Services;
98

109
public interface IPolicyService
1110
{
12-
Task SaveAsync(Policy policy, Guid? savingUserId, EventSystemUser? eventSystemUser = null);
13-
1411
/// <summary>
1512
/// Get the combined master password policy options for the specified user.
1613
/// </summary>

0 commit comments

Comments
 (0)