Files
server/src/Api/Controllers/PoliciesController.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

156 lines
5.7 KiB
C#
Raw Normal View History

using Bit.Api.Models.Request;
2021-12-14 15:05:07 +00:00
using Bit.Api.Models.Response;
using Bit.Core.Context;
2020-01-20 08:53:09 -05:00
using Bit.Core.Enums;
using Bit.Core.Exceptions;
[AC-1070] Enforce master password policy on login (#2714) * [EC-1070] Add API endpoint to retrieve all policies for the current user The additional API endpoint is required to avoid forcing a full sync call before every login for master password policy enforcement on login. * [EC-1070] Add MasterPasswordPolicyData model * [EC-1070] Move PolicyResponseModel to Core project The response model is used by both the Identity and Api projects. * [EC-1070] Supply master password polices as a custom identity token response * [EC-1070] Include master password policies in 2FA token response * [EC-1070] Add response model to verify-password endpoint that includes master password policies * [AC-1070] Introduce MasterPasswordPolicyResponseModel * [AC-1070] Add policy service method to retrieve a user's master password policy * [AC-1070] User new policy service method - Update BaseRequestValidator - Update AccountsController for /verify-password endpoint - Update VerifyMasterPasswordResponseModel to accept MasterPasswordPolicyData * [AC-1070] Cleanup new policy service method - Use User object instead of Guid - Remove TODO message - Use `PolicyRepository.GetManyByTypeApplicableToUserIdAsync` instead of filtering locally * [AC-1070] Cleanup MasterPasswordPolicy models - Remove default values from both models - Add missing `RequireLower` - Fix mismatched properties in `CombineWith` method - Make properties nullable in response model * [AC-1070] Remove now un-used GET /policies endpoint * [AC-1070] Update policy service method to use GetManyByUserIdAsync * [AC-1070] Ensure existing value is not null before comparison * [AC-1070] Remove redundant VerifyMasterPasswordResponse model * [AC-1070] Fix service typo in constructor
2023-04-17 07:35:47 -07:00
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories;
2020-01-15 08:35:53 -05:00
using Bit.Core.Services;
using Bit.Core.Settings;
2020-01-15 08:35:53 -05:00
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
2020-01-15 08:35:53 -05:00
using Microsoft.AspNetCore.Mvc;
namespace Bit.Api.Controllers;
2022-08-29 16:06:55 -04:00
2020-01-15 08:35:53 -05:00
[Route("organizations/{orgId}/policies")]
[Authorize("Application")]
public class PoliciesController : Controller
{
private readonly IPolicyRepository _policyRepository;
2020-01-15 09:19:49 -05:00
private readonly IPolicyService _policyService;
2020-01-15 08:35:53 -05:00
private readonly IOrganizationService _organizationService;
private readonly IOrganizationUserRepository _organizationUserRepository;
2020-02-19 14:56:16 -05:00
private readonly IUserService _userService;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
2020-01-15 08:35:53 -05:00
private readonly IDataProtector _organizationServiceDataProtector;
2022-08-29 16:06:55 -04:00
2020-01-15 08:35:53 -05:00
public PoliciesController(
IPolicyRepository policyRepository,
IPolicyService policyService,
IOrganizationService organizationService,
IOrganizationUserRepository organizationUserRepository,
2020-02-19 14:56:16 -05:00
IUserService userService,
2020-01-15 08:35:53 -05:00
ICurrentContext currentContext,
GlobalSettings globalSettings,
IDataProtectionProvider dataProtectionProvider)
{
_policyRepository = policyRepository;
2020-01-15 09:19:49 -05:00
_policyService = policyService;
2020-02-19 14:56:16 -05:00
_organizationService = organizationService;
_organizationUserRepository = organizationUserRepository;
2020-02-19 14:56:16 -05:00
_userService = userService;
_currentContext = currentContext;
_globalSettings = globalSettings;
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
"OrganizationServiceDataProtector");
2022-08-29 16:06:55 -04:00
}
2020-01-15 08:35:53 -05:00
[HttpGet("{type}")]
public async Task<PolicyResponseModel> Get(string orgId, int type)
2022-08-29 16:06:55 -04:00
{
2020-01-15 08:35:53 -05:00
var orgIdGuid = new Guid(orgId);
if (!await _currentContext.ManagePolicies(orgIdGuid))
2020-01-15 08:35:53 -05:00
{
throw new NotFoundException();
2020-01-15 08:35:53 -05:00
}
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(orgIdGuid, (PolicyType)type);
if (policy == null)
{
throw new NotFoundException();
}
return new PolicyResponseModel(policy);
2022-08-29 16:06:55 -04:00
}
2020-01-15 08:35:53 -05:00
[HttpGet("")]
public async Task<ListResponseModel<PolicyResponseModel>> Get(string orgId)
2022-08-29 16:06:55 -04:00
{
2020-01-15 08:35:53 -05:00
var orgIdGuid = new Guid(orgId);
if (!await _currentContext.ManagePolicies(orgIdGuid))
{
throw new NotFoundException();
2022-08-29 16:06:55 -04:00
}
var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgIdGuid);
var responses = policies.Select(p => new PolicyResponseModel(p));
return new ListResponseModel<PolicyResponseModel>(responses);
}
[AllowAnonymous]
[HttpGet("token")]
public async Task<ListResponseModel<PolicyResponseModel>> GetByToken(string orgId, [FromQuery] string email,
2020-01-20 08:53:09 -05:00
[FromQuery] string token, [FromQuery] string organizationUserId)
2022-08-29 16:06:55 -04:00
{
var orgUserId = new Guid(organizationUserId);
var tokenValid = CoreHelpers.UserInviteTokenIsValid(_organizationServiceDataProtector, token,
email, orgUserId, _globalSettings);
if (!tokenValid)
2022-08-29 16:06:55 -04:00
{
2020-01-15 08:35:53 -05:00
throw new NotFoundException();
}
2020-01-20 08:53:09 -05:00
var orgIdGuid = new Guid(orgId);
var orgUser = await _organizationUserRepository.GetByIdAsync(orgUserId);
if (orgUser == null || orgUser.OrganizationId != orgIdGuid)
2020-01-15 08:35:53 -05:00
{
throw new NotFoundException();
}
2022-08-29 14:53:16 -04:00
2020-01-20 08:53:09 -05:00
var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgIdGuid);
var responses = policies.Where(p => p.Enabled).Select(p => new PolicyResponseModel(p));
return new ListResponseModel<PolicyResponseModel>(responses);
2020-01-15 08:35:53 -05:00
}
2020-02-19 14:56:16 -05:00
[AllowAnonymous]
[HttpGet("invited-user")]
public async Task<ListResponseModel<PolicyResponseModel>> GetByInvitedUser(string orgId, [FromQuery] string userId)
2022-08-29 16:06:55 -04:00
{
2020-02-19 14:56:16 -05:00
var user = await _userService.GetUserByIdAsync(new Guid(userId));
if (user == null)
2022-08-29 16:06:55 -04:00
{
2020-02-19 14:56:16 -05:00
throw new UnauthorizedAccessException();
2022-08-29 14:53:16 -04:00
}
2020-02-19 14:56:16 -05:00
var orgIdGuid = new Guid(orgId);
var orgUsersByUserId = await _organizationUserRepository.GetManyByUserAsync(user.Id);
var orgUser = orgUsersByUserId.SingleOrDefault(u => u.OrganizationId == orgIdGuid);
if (orgUser == null)
2022-08-29 14:53:16 -04:00
{
throw new NotFoundException();
2020-01-15 08:35:53 -05:00
}
2022-08-29 14:53:16 -04:00
if (orgUser.Status != OrganizationUserStatusType.Invited)
{
2020-02-19 14:56:16 -05:00
throw new UnauthorizedAccessException();
}
2022-08-29 16:06:55 -04:00
2020-01-20 08:53:09 -05:00
var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgIdGuid);
var responses = policies.Where(p => p.Enabled).Select(p => new PolicyResponseModel(p));
return new ListResponseModel<PolicyResponseModel>(responses);
2022-08-29 14:53:16 -04:00
}
[HttpPut("{type}")]
public async Task<PolicyResponseModel> Put(string orgId, int type, [FromBody] PolicyRequestModel model)
2022-08-29 16:06:55 -04:00
{
var orgIdGuid = new Guid(orgId);
if (!await _currentContext.ManagePolicies(orgIdGuid))
2022-08-29 16:06:55 -04:00
{
throw new NotFoundException();
2022-08-29 16:06:55 -04:00
}
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(new Guid(orgId), (PolicyType)type);
2020-01-15 08:35:53 -05:00
if (policy == null)
2022-08-29 16:06:55 -04:00
{
2020-01-15 08:35:53 -05:00
policy = model.ToPolicy(orgIdGuid);
}
2022-08-29 16:06:55 -04:00
else
{
2020-01-20 08:53:09 -05:00
policy = model.ToPolicy(policy);
2022-08-29 16:06:55 -04:00
}
var userId = _userService.GetProperUserId(User);
await _policyService.SaveAsync(policy, _userService, _organizationService, userId);
return new PolicyResponseModel(policy);
2020-01-15 08:35:53 -05:00
}
}