mirror of
https://github.com/bitwarden/server.git
synced 2025-02-23 03:01:23 +01:00
refactor policy apis
This commit is contained in:
parent
c5ae1b8283
commit
f3f1ac57d2
@ -8,6 +8,7 @@ using Bit.Core.Models.Api;
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers
|
namespace Bit.Api.Controllers
|
||||||
{
|
{
|
||||||
@ -29,11 +30,16 @@ namespace Bit.Api.Controllers
|
|||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{type}")]
|
||||||
public async Task<PolicyResponseModel> Get(string orgId, string id)
|
public async Task<PolicyResponseModel> Get(string orgId, int type)
|
||||||
{
|
{
|
||||||
var policy = await _policyRepository.GetByIdAsync(new Guid(id));
|
var orgIdGuid = new Guid(orgId);
|
||||||
if(policy == null || !_currentContext.OrganizationAdmin(policy.OrganizationId))
|
if(!_currentContext.OrganizationAdmin(orgIdGuid))
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(orgIdGuid, (PolicyType)type);
|
||||||
|
if(policy == null)
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
@ -55,45 +61,26 @@ namespace Bit.Api.Controllers
|
|||||||
return new ListResponseModel<PolicyResponseModel>(responses);
|
return new ListResponseModel<PolicyResponseModel>(responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("")]
|
[HttpPut("{type}")]
|
||||||
public async Task<PolicyResponseModel> Post(string orgId, [FromBody]PolicyRequestModel model)
|
public async Task<PolicyResponseModel> Put(string orgId, int type, [FromBody]PolicyRequestModel model)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(orgId);
|
var orgIdGuid = new Guid(orgId);
|
||||||
if(!_currentContext.OrganizationAdmin(orgIdGuid))
|
if(!_currentContext.OrganizationAdmin(orgIdGuid))
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(new Guid(orgId), (PolicyType)type);
|
||||||
|
if(policy == null)
|
||||||
|
{
|
||||||
|
policy = model.ToPolicy(orgIdGuid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
policy = model.ToPolicy(policy);
|
||||||
|
}
|
||||||
|
|
||||||
var policy = model.ToPolicy(orgIdGuid);
|
|
||||||
await _policyService.SaveAsync(policy);
|
await _policyService.SaveAsync(policy);
|
||||||
return new PolicyResponseModel(policy);
|
return new PolicyResponseModel(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
[HttpPost("{id}")]
|
|
||||||
public async Task<PolicyResponseModel> Put(string orgId, string id, [FromBody]PolicyRequestModel model)
|
|
||||||
{
|
|
||||||
var policy = await _policyRepository.GetByIdAsync(new Guid(id));
|
|
||||||
if(policy == null || !_currentContext.OrganizationAdmin(policy.OrganizationId))
|
|
||||||
{
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
await _policyService.SaveAsync(model.ToPolicy(policy));
|
|
||||||
return new PolicyResponseModel(policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
[HttpPost("{id}/delete")]
|
|
||||||
public async Task Delete(string orgId, string id)
|
|
||||||
{
|
|
||||||
var policy = await _policyRepository.GetByIdAsync(new Guid(id));
|
|
||||||
if(policy == null || !_currentContext.OrganizationAdmin(policy.OrganizationId))
|
|
||||||
{
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
await _policyService.DeleteAsync(policy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Api.Public;
|
using Bit.Core.Models.Api.Public;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
@ -33,17 +34,17 @@ namespace Bit.Api.Public.Controllers
|
|||||||
/// Retrieve a policy.
|
/// Retrieve a policy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Retrieves the details of an existing policy. You need only supply the unique group identifier
|
/// Retrieves the details of a policy.
|
||||||
/// that was returned upon policy creation.
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="id">The identifier of the policy to be retrieved.</param>
|
/// <param name="type">The type of policy to be retrieved.</param>
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{type}")]
|
||||||
[ProducesResponseType(typeof(GroupResponseModel), (int)HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(GroupResponseModel), (int)HttpStatusCode.OK)]
|
||||||
[ProducesResponseType((int)HttpStatusCode.NotFound)]
|
[ProducesResponseType((int)HttpStatusCode.NotFound)]
|
||||||
public async Task<IActionResult> Get(Guid id)
|
public async Task<IActionResult> Get(PolicyType type)
|
||||||
{
|
{
|
||||||
var policy = await _policyRepository.GetByIdAsync(id);
|
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(
|
||||||
if(policy == null || policy.OrganizationId != _currentContext.OrganizationId)
|
_currentContext.OrganizationId.Value, type);
|
||||||
|
if(policy == null)
|
||||||
{
|
{
|
||||||
return new NotFoundResult();
|
return new NotFoundResult();
|
||||||
}
|
}
|
||||||
@ -67,69 +68,34 @@ namespace Bit.Api.Public.Controllers
|
|||||||
return new JsonResult(response);
|
return new JsonResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a policy.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Creates a new policy object.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="model">The request model.</param>
|
|
||||||
[HttpPost]
|
|
||||||
[ProducesResponseType(typeof(PolicyResponseModel), (int)HttpStatusCode.OK)]
|
|
||||||
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
|
|
||||||
public async Task<IActionResult> Post([FromBody]PolicyCreateRequestModel model)
|
|
||||||
{
|
|
||||||
var policy = model.ToPolicy(_currentContext.OrganizationId.Value);
|
|
||||||
await _policyService.SaveAsync(policy);
|
|
||||||
var response = new PolicyResponseModel(policy);
|
|
||||||
return new JsonResult(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update a policy.
|
/// Update a policy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Updates the specified policy object. If a property is not provided,
|
/// Updates the specified policy. If a property is not provided,
|
||||||
/// the value of the existing property will be reset.
|
/// the value of the existing property will be reset.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="id">The identifier of the policy to be updated.</param>
|
/// <param name="type">The type of policy to be updated.</param>
|
||||||
/// <param name="model">The request model.</param>
|
/// <param name="model">The request model.</param>
|
||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
[ProducesResponseType(typeof(PolicyResponseModel), (int)HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(PolicyResponseModel), (int)HttpStatusCode.OK)]
|
||||||
[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(Guid id, [FromBody]PolicyUpdateRequestModel model)
|
public async Task<IActionResult> Put(PolicyType type, [FromBody]PolicyUpdateRequestModel model)
|
||||||
{
|
{
|
||||||
var existingPolicy = await _policyRepository.GetByIdAsync(id);
|
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(
|
||||||
if(existingPolicy == null || existingPolicy.OrganizationId != _currentContext.OrganizationId)
|
_currentContext.OrganizationId.Value, type);
|
||||||
|
if(policy == null)
|
||||||
{
|
{
|
||||||
return new NotFoundResult();
|
policy = model.ToPolicy(_currentContext.OrganizationId.Value);
|
||||||
}
|
}
|
||||||
var updatedPolicy = model.ToPolicy(existingPolicy);
|
else
|
||||||
await _policyService.SaveAsync(updatedPolicy);
|
{
|
||||||
var response = new PolicyResponseModel(updatedPolicy);
|
policy = model.ToPolicy(policy);
|
||||||
|
}
|
||||||
|
await _policyService.SaveAsync(policy);
|
||||||
|
var response = new PolicyResponseModel(policy);
|
||||||
return new JsonResult(response);
|
return new JsonResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delete a policy.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Permanently deletes a policy. This cannot be undone.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="id">The identifier of the policy to be deleted.</param>
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
||||||
[ProducesResponseType((int)HttpStatusCode.NotFound)]
|
|
||||||
public async Task<IActionResult> Delete(Guid id)
|
|
||||||
{
|
|
||||||
var policy = await _policyRepository.GetByIdAsync(id);
|
|
||||||
if(policy == null || policy.OrganizationId != _currentContext.OrganizationId)
|
|
||||||
{
|
|
||||||
return new NotFoundResult();
|
|
||||||
}
|
|
||||||
await _policyRepository.DeleteAsync(policy);
|
|
||||||
return new OkResult();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ namespace Bit.Core.Models.Api.Public
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data for the policy.
|
/// Data for the policy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StringLength(300)]
|
|
||||||
public Dictionary<string, object> Data { get; set; }
|
public Dictionary<string, object> Data { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Bit.Core.Models.Table;
|
|
||||||
|
|
||||||
namespace Bit.Core.Models.Api.Public
|
|
||||||
{
|
|
||||||
public class PolicyCreateRequestModel : PolicyUpdateRequestModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of policy.
|
|
||||||
/// </summary>
|
|
||||||
[Required]
|
|
||||||
public Enums.PolicyType? Type { get; set; }
|
|
||||||
|
|
||||||
public Policy ToPolicy(Guid orgId)
|
|
||||||
{
|
|
||||||
return ToPolicy(new Policy
|
|
||||||
{
|
|
||||||
OrganizationId = orgId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,19 @@
|
|||||||
using Bit.Core.Models.Table;
|
using System;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Api.Public
|
namespace Bit.Core.Models.Api.Public
|
||||||
{
|
{
|
||||||
public class PolicyUpdateRequestModel : PolicyBaseModel
|
public class PolicyUpdateRequestModel : PolicyBaseModel
|
||||||
{
|
{
|
||||||
|
public Policy ToPolicy(Guid orgId)
|
||||||
|
{
|
||||||
|
return ToPolicy(new Policy
|
||||||
|
{
|
||||||
|
OrganizationId = orgId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public virtual Policy ToPolicy(Policy existingPolicy)
|
public virtual Policy ToPolicy(Policy existingPolicy)
|
||||||
{
|
{
|
||||||
existingPolicy.Enabled = Enabled.GetValueOrDefault();
|
existingPolicy.Enabled = Enabled.GetValueOrDefault();
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories
|
namespace Bit.Core.Repositories
|
||||||
{
|
{
|
||||||
public interface IPolicyRepository : IRepository<Policy, Guid>
|
public interface IPolicyRepository : IRepository<Policy, Guid>
|
||||||
{
|
{
|
||||||
|
Task<Policy> GetByOrganizationIdTypeAsync(Guid organizationId, PolicyType type);
|
||||||
Task<ICollection<Policy>> GetManyByOrganizationIdAsync(Guid organizationId);
|
Task<ICollection<Policy>> GetManyByOrganizationIdAsync(Guid organizationId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Data.SqlClient;
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories.SqlServer
|
namespace Bit.Core.Repositories.SqlServer
|
||||||
{
|
{
|
||||||
@ -18,6 +19,18 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
public PolicyRepository(string connectionString, string readOnlyConnectionString)
|
public PolicyRepository(string connectionString, string readOnlyConnectionString)
|
||||||
: base(connectionString, readOnlyConnectionString)
|
: base(connectionString, readOnlyConnectionString)
|
||||||
{ }
|
{ }
|
||||||
|
public async Task<Policy> GetByOrganizationIdTypeAsync(Guid organizationId, PolicyType type)
|
||||||
|
{
|
||||||
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<Policy>(
|
||||||
|
$"[{Schema}].[{Table}_ReadByOrganizationIdType]",
|
||||||
|
new { OrganizationId = organizationId, Type = (byte)type },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.SingleOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Policy>> GetManyByOrganizationIdAsync(Guid organizationId)
|
public async Task<ICollection<Policy>> GetManyByOrganizationIdAsync(Guid organizationId)
|
||||||
{
|
{
|
||||||
|
@ -259,5 +259,6 @@
|
|||||||
<Build Include="dbo\Stored Procedures\Policy_ReadByOrganizationId.sql" />
|
<Build Include="dbo\Stored Procedures\Policy_ReadByOrganizationId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Policy_Update.sql" />
|
<Build Include="dbo\Stored Procedures\Policy_Update.sql" />
|
||||||
<Build Include="dbo\Views\PolicyView.sql" />
|
<Build Include="dbo\Views\PolicyView.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\Policy_ReadByOrganizationIdType.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Policy_ReadByOrganizationIdType]
|
||||||
|
@OrganizationId UNIQUEIDENTIFIER,
|
||||||
|
@Type TINYINT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT TOP 1
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[PolicyView]
|
||||||
|
WHERE
|
||||||
|
[OrganizationId] = @OrganizationId
|
||||||
|
AND [Type] = @Type
|
||||||
|
END
|
@ -2,7 +2,7 @@
|
|||||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||||
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
|
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
|
||||||
[Type] TINYINT NOT NULL,
|
[Type] TINYINT NOT NULL,
|
||||||
[Data] NVARCHAR (MAX) NOT NULL,
|
[Data] NVARCHAR (MAX) NULL,
|
||||||
[Enabled] BIT NOT NULL,
|
[Enabled] BIT NOT NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
@ -12,6 +12,6 @@
|
|||||||
|
|
||||||
|
|
||||||
GO
|
GO
|
||||||
CREATE NONCLUSTERED INDEX [IX_Policy_OrganizationId_Enabled]
|
CREATE UNIQUE NONCLUSTERED INDEX [IX_Policy_OrganizationId_Type]
|
||||||
ON [dbo].[Policy]([OrganizationId] ASC, [Enabled] ASC);
|
ON [dbo].[Policy]([OrganizationId] ASC, [Type] ASC);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ BEGIN
|
|||||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||||
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
|
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
|
||||||
[Type] TINYINT NOT NULL,
|
[Type] TINYINT NOT NULL,
|
||||||
[Data] NVARCHAR (MAX) NOT NULL,
|
[Data] NVARCHAR (MAX) NULL,
|
||||||
[Enabled] BIT NOT NULL,
|
[Enabled] BIT NOT NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
@ -12,8 +12,8 @@ BEGIN
|
|||||||
CONSTRAINT [FK_Policy_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) ON DELETE CASCADE
|
CONSTRAINT [FK_Policy_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE NONCLUSTERED INDEX [IX_Policy_OrganizationId_Enabled]
|
CREATE UNIQUE NONCLUSTERED INDEX [IX_Policy_OrganizationId_Type]
|
||||||
ON [dbo].[Policy]([OrganizationId] ASC, [Enabled] ASC);
|
ON [dbo].[Policy]([OrganizationId] ASC, [Type] ASC);
|
||||||
END
|
END
|
||||||
GO
|
GO
|
||||||
|
|
||||||
@ -128,6 +128,29 @@ BEGIN
|
|||||||
END
|
END
|
||||||
GO
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[Policy_ReadByOrganizationIdType]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[Policy_ReadByOrganizationIdType]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[Policy_ReadByOrganizationIdType]
|
||||||
|
@OrganizationId UNIQUEIDENTIFIER,
|
||||||
|
@Type TINYINT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT TOP 1
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[PolicyView]
|
||||||
|
WHERE
|
||||||
|
[OrganizationId] = @OrganizationId
|
||||||
|
AND [Type] = @Type
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
IF OBJECT_ID('[dbo].[Policy_Update]') IS NOT NULL
|
IF OBJECT_ID('[dbo].[Policy_Update]') IS NOT NULL
|
||||||
BEGIN
|
BEGIN
|
||||||
DROP PROCEDURE [dbo].[Policy_Update]
|
DROP PROCEDURE [dbo].[Policy_Update]
|
||||||
|
Loading…
Reference in New Issue
Block a user