1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -05:00

Add disable send policy (#1130)

* Add Disable Send policy

* Test DisableSend policy

* PR Review

* Update tests for using CurrentContext

This required making an interface for CurrentContext and mocking out
the members used. The interface can be expanded as needed for tests.

I moved CurrentContext to a folder, which changes the namespace
and causes a lot of file touches, but most are just adding a reference

* Fix failing test

* Update exemption to include all exempt users

* Move all CurrentContext usages to ICurrentContext

* PR review. Match messaging with Web
This commit is contained in:
Matt Gibson
2021-02-04 12:54:21 -06:00
committed by GitHub
parent 19e7ce8519
commit edd4bc2623
60 changed files with 437 additions and 99 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Newtonsoft.Json;
@ -181,7 +182,7 @@ namespace Bit.Core.Services
}
var currentContext = _httpContextAccessor?.HttpContext?.
RequestServices.GetService(typeof(CurrentContext)) as CurrentContext;
RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
return currentContext?.DeviceIdentifier;
}

View File

@ -6,6 +6,7 @@ using Bit.Core.Models.Data;
using System.Linq;
using System.Collections.Generic;
using Bit.Core.Models.Table;
using Bit.Core.Context;
namespace Bit.Core.Services
{
@ -14,14 +15,14 @@ namespace Bit.Core.Services
private readonly IEventWriteService _eventWriteService;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
public EventService(
IEventWriteService eventWriteService,
IOrganizationUserRepository organizationUserRepository,
IApplicationCacheService applicationCacheService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings)
{
_eventWriteService = eventWriteService;

View File

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Bit.Core.Models.Table;
using Microsoft.Azure.NotificationHubs;
using Bit.Core.Context;
using Bit.Core.Enums;
using Newtonsoft.Json;
using System.Collections.Generic;
@ -206,7 +207,7 @@ namespace Bit.Core.Services
}
var currentContext = _httpContextAccessor?.HttpContext?.
RequestServices.GetService(typeof(CurrentContext)) as CurrentContext;
RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
return currentContext?.DeviceIdentifier;
}

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Newtonsoft.Json;
@ -187,7 +188,7 @@ namespace Bit.Core.Services
}
var currentContext = _httpContextAccessor?.HttpContext?.
RequestServices.GetService(typeof(CurrentContext)) as CurrentContext;
RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
return currentContext?.DeviceIdentifier;
}

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Microsoft.AspNetCore.Http;
@ -198,7 +199,7 @@ namespace Bit.Core.Services
private async Task AddCurrentContextAsync(PushSendRequestModel request, bool addIdentifier)
{
var currentContext = _httpContextAccessor?.HttpContext?.
RequestServices.GetService(typeof(CurrentContext)) as CurrentContext;
RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
if (!string.IsNullOrWhiteSpace(currentContext?.DeviceIdentifier))
{
var device = await _deviceRepository.GetByIdentifierAsync(currentContext.DeviceIdentifier);

View File

@ -1,6 +1,9 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
@ -14,12 +17,14 @@ namespace Bit.Core.Services
{
private readonly ISendRepository _sendRepository;
private readonly IUserRepository _userRepository;
private readonly IPolicyRepository _policyRepository;
private readonly IUserService _userService;
private readonly IOrganizationRepository _organizationRepository;
private readonly ISendFileStorageService _sendFileStorageService;
private readonly IPasswordHasher<User> _passwordHasher;
private readonly IPushNotificationService _pushService;
private readonly GlobalSettings _globalSettings;
private readonly ICurrentContext _currentContext;
public SendService(
ISendRepository sendRepository,
@ -29,20 +34,27 @@ namespace Bit.Core.Services
ISendFileStorageService sendFileStorageService,
IPasswordHasher<User> passwordHasher,
IPushNotificationService pushService,
GlobalSettings globalSettings)
GlobalSettings globalSettings,
IPolicyRepository policyRepository,
ICurrentContext currentContext)
{
_sendRepository = sendRepository;
_userRepository = userRepository;
_userService = userService;
_policyRepository = policyRepository;
_organizationRepository = organizationRepository;
_sendFileStorageService = sendFileStorageService;
_passwordHasher = passwordHasher;
_pushService = pushService;
_globalSettings = globalSettings;
_currentContext = currentContext;
}
public async Task SaveSendAsync(Send send)
{
// Make sure user can save Sends
await ValidateUserCanSaveAsync(send.UserId);
if (send.Id == default(Guid))
{
await _sendRepository.CreateAsync(send);
@ -58,7 +70,7 @@ namespace Bit.Core.Services
public async Task CreateSendAsync(Send send, SendFileData data, Stream stream, long requestLength)
{
if (send.Type != Enums.SendType.File)
if (send.Type != SendType.File)
{
throw new BadRequestException("Send is not of type \"file\".");
}
@ -174,5 +186,28 @@ namespace Bit.Core.Services
{
return _passwordHasher.HashPassword(new User(), password);
}
private async Task ValidateUserCanSaveAsync(Guid? userId)
{
if (!userId.HasValue || (!_currentContext.Organizations?.Any() ?? true))
{
return;
}
var policies = await _policyRepository.GetManyByUserIdAsync(userId.Value);
if (policies == null)
{
return;
}
foreach (var policy in policies.Where(p => p.Enabled && p.Type == PolicyType.DisableSend))
{
if (!_currentContext.ManagePolicies(policy.OrganizationId))
{
throw new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.");
}
}
}
}
}

View File

@ -14,6 +14,7 @@ using Bit.Core.Models.Business;
using U2fLib = U2F.Core.Crypto.U2F;
using U2F.Core.Models;
using U2F.Core.Utils;
using Bit.Core.Context;
using Bit.Core.Exceptions;
using Bit.Core.Utilities;
using System.IO;
@ -46,7 +47,7 @@ namespace Bit.Core.Services
private readonly IPolicyRepository _policyRepository;
private readonly IDataProtector _organizationServiceDataProtector;
private readonly IReferenceEventService _referenceEventService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly IOrganizationService _organizationService;
@ -74,7 +75,7 @@ namespace Bit.Core.Services
IPaymentService paymentService,
IPolicyRepository policyRepository,
IReferenceEventService referenceEventService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IOrganizationService organizationService)
: base(