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,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Jobs;
using Bit.Core.Repositories;
using Bit.Core.Services;

View File

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Identity;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Builder;
@ -45,7 +46,7 @@ namespace Bit.Admin
services.AddSqlServerRepositories(globalSettings);
// Context
services.AddScoped<CurrentContext>();
services.AddScoped<ICurrentContext, CurrentContext>();
// Identity
services.AddPasswordlessIdentityServices<ReadOnlyEnvIdentityUserStore>(globalSettings);

View File

@ -8,6 +8,7 @@ using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using Bit.Api.Utilities;
using Bit.Core.Utilities;
using System.Collections.Generic;
@ -23,7 +24,7 @@ namespace Bit.Api.Controllers
private readonly ICollectionCipherRepository _collectionCipherRepository;
private readonly ICipherService _cipherService;
private readonly IUserService _userService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
public CiphersController(
@ -31,7 +32,7 @@ namespace Bit.Api.Controllers
ICollectionCipherRepository collectionCipherRepository,
ICipherService cipherService,
IUserService userService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings)
{
_cipherRepository = cipherRepository;

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Models.Table;
using System.Collections.Generic;
@ -20,13 +20,13 @@ namespace Bit.Api.Controllers
private readonly ICollectionRepository _collectionRepository;
private readonly ICollectionService _collectionService;
private readonly IUserService _userService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public CollectionsController(
ICollectionRepository collectionRepository,
ICollectionService collectionService,
IUserService userService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_collectionRepository = collectionRepository;
_collectionService = collectionService;

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Models.Data;
namespace Bit.Api.Controllers
@ -20,14 +20,14 @@ namespace Bit.Api.Controllers
private readonly ICipherRepository _cipherRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IEventRepository _eventRepository;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public EventsController(
IUserService userService,
ICipherRepository cipherRepository,
IOrganizationUserRepository organizationUserRepository,
IEventRepository eventRepository,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_userService = userService;
_cipherRepository = cipherRepository;

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using System.Collections.Generic;
namespace Bit.Api.Controllers
@ -18,12 +18,12 @@ namespace Bit.Api.Controllers
{
private readonly IGroupRepository _groupRepository;
private readonly IGroupService _groupService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public GroupsController(
IGroupRepository groupRepository,
IGroupService groupService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_groupRepository = groupRepository;
_groupService = groupService;

View File

@ -6,6 +6,7 @@ using System.Net.Http;
using System.Security.Cryptography;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using System.Net;
using Bit.Core.Exceptions;
using System.Linq;
@ -22,7 +23,7 @@ namespace Bit.Api.Controllers
private static HttpClient _httpClient;
private readonly IUserService _userService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly string _userAgent;
@ -33,7 +34,7 @@ namespace Bit.Api.Controllers
public HibpController(
IUserService userService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings)
{
_userService = userService;

View File

@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Bit.Core.Services;
using Microsoft.AspNetCore.Authorization;
using Bit.Core;
using Bit.Core.Context;
using System.Threading.Tasks;
using Bit.Core.Models.Business;
using Bit.Core.Exceptions;
@ -21,7 +21,7 @@ namespace Bit.Api.Controllers
private readonly IUserService _userService;
private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationService _organizationService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public LicensesController(
ILicensingService licensingService,
@ -29,7 +29,7 @@ namespace Bit.Api.Controllers
IUserService userService,
IOrganizationRepository organizationRepository,
IOrganizationService organizationService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_licensingService = licensingService;
_userRepository = userRepository;

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using System.Collections.Generic;
using Bit.Core.Models.Business;
@ -23,7 +23,7 @@ namespace Bit.Api.Controllers
private readonly ICollectionRepository _collectionRepository;
private readonly IGroupRepository _groupRepository;
private readonly IUserService _userService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public OrganizationUsersController(
IOrganizationRepository organizationRepository,
@ -32,7 +32,7 @@ namespace Bit.Api.Controllers
ICollectionRepository collectionRepository,
IGroupRepository groupRepository,
IUserService userService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;

View File

@ -9,6 +9,7 @@ using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using Bit.Api.Utilities;
using Bit.Core.Models.Business;
using Bit.Core.Utilities;
@ -24,7 +25,7 @@ namespace Bit.Api.Controllers
private readonly IOrganizationService _organizationService;
private readonly IUserService _userService;
private readonly IPaymentService _paymentService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly IPolicyRepository _policyRepository;
@ -34,7 +35,7 @@ namespace Bit.Api.Controllers
IOrganizationService organizationService,
IUserService userService,
IPaymentService paymentService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IPolicyRepository policyRepository)
{

View File

@ -8,6 +8,7 @@ using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.DataProtection;
@ -23,7 +24,7 @@ namespace Bit.Api.Controllers
private readonly IOrganizationService _organizationService;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IUserService _userService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly IDataProtector _organizationServiceDataProtector;
@ -33,7 +34,7 @@ namespace Bit.Api.Controllers
IOrganizationService organizationService,
IOrganizationUserRepository organizationUserRepository,
IUserService userService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IDataProtectionProvider dataProtectionProvider)
{

View File

@ -2,6 +2,7 @@
using Bit.Core.Services;
using Microsoft.AspNetCore.Authorization;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api;
using System.Threading.Tasks;
@ -21,14 +22,14 @@ namespace Bit.Api.Controllers
private readonly IPushRegistrationService _pushRegistrationService;
private readonly IPushNotificationService _pushNotificationService;
private readonly IWebHostEnvironment _environment;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
public PushController(
IPushRegistrationService pushRegistrationService,
IPushNotificationService pushNotificationService,
IWebHostEnvironment environment,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings)
{
_currentContext = currentContext;

View File

@ -10,6 +10,7 @@ using Bit.Core.Models.Table;
using Bit.Core.Enums;
using System.Linq;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Core.Utilities.Duo;
@ -25,7 +26,7 @@ namespace Bit.Api.Controllers
private readonly IOrganizationService _organizationService;
private readonly GlobalSettings _globalSettings;
private readonly UserManager<User> _userManager;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public TwoFactorController(
IUserService userService,
@ -33,7 +34,7 @@ namespace Bit.Api.Controllers
IOrganizationService organizationService,
GlobalSettings globalSettings,
UserManager<User> userManager,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_userService = userService;
_organizationRepository = organizationRepository;

View File

@ -2,7 +2,7 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Models.Api.Public;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -17,12 +17,12 @@ namespace Bit.Api.Public.Controllers
{
private readonly ICollectionRepository _collectionRepository;
private readonly ICollectionService _collectionService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public CollectionsController(
ICollectionRepository collectionRepository,
ICollectionService collectionService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_collectionRepository = collectionRepository;
_collectionService = collectionService;

View File

@ -2,7 +2,7 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Models.Api.Public;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
@ -17,12 +17,12 @@ namespace Bit.Api.Public.Controllers
{
private readonly IEventRepository _eventRepository;
private readonly ICipherRepository _cipherRepository;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public EventsController(
IEventRepository eventRepository,
ICipherRepository cipherRepository,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_eventRepository = eventRepository;
_cipherRepository = cipherRepository;

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Models.Api.Public;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -18,12 +18,12 @@ namespace Bit.Api.Public.Controllers
{
private readonly IGroupRepository _groupRepository;
private readonly IGroupService _groupService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public GroupsController(
IGroupRepository groupRepository,
IGroupService groupService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_groupRepository = groupRepository;
_groupService = groupService;

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Models.Api.Public;
using Bit.Core.Models.Business;
using Bit.Core.Repositories;
@ -21,14 +21,14 @@ namespace Bit.Api.Public.Controllers
private readonly IGroupRepository _groupRepository;
private readonly IOrganizationService _organizationService;
private readonly IUserService _userService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public MembersController(
IOrganizationUserRepository organizationUserRepository,
IGroupRepository groupRepository,
IOrganizationService organizationService,
IUserService userService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_organizationUserRepository = organizationUserRepository;
_groupRepository = groupRepository;

View File

@ -2,6 +2,7 @@
using System.Net;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Public;
using Bit.Core.Services;
@ -15,12 +16,12 @@ namespace Bit.Api.Public.Controllers
public class OrganizationController : Controller
{
private readonly IOrganizationService _organizationService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
public OrganizationController(
IOrganizationService organizationService,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings)
{
_organizationService = organizationService;

View File

@ -2,7 +2,7 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Models.Api.Public;
using Bit.Core.Repositories;
@ -20,14 +20,14 @@ namespace Bit.Api.Public.Controllers
private readonly IPolicyService _policyService;
private readonly IUserService _userService;
private readonly IOrganizationService _organizationService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public PoliciesController(
IPolicyRepository policyRepository,
IPolicyService policyService,
IUserService userService,
IOrganizationService organizationService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_policyRepository = policyRepository;
_policyService = policyService;

View File

@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Bit.Api.Utilities;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Identity;
using Newtonsoft.Json.Serialization;
using AspNetCoreRateLimit;
@ -54,7 +55,7 @@ namespace Bit.Api
services.AddSqlServerRepositories(globalSettings);
// Context
services.AddScoped<CurrentContext>();
services.AddScoped<ICurrentContext, CurrentContext>();
// Caching
services.AddMemoryCache();

View File

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Bit.Core;
using Bit.Core.Context;
using Stripe;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Http;
@ -46,7 +47,7 @@ namespace Bit.Billing
services.AddSingleton<BitPayClient>();
// Context
services.AddScoped<CurrentContext>();
services.AddScoped<ICurrentContext, CurrentContext>();
// Identity
services.AddCustomIdentityServices(globalSettings);

View File

@ -0,0 +1,24 @@
using System;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Utilities;
namespace Bit.Core.Context
{
public class CurrentContentOrganization
{
public CurrentContentOrganization() { }
public CurrentContentOrganization(OrganizationUser orgUser)
{
Id = orgUser.OrganizationId;
Type = orgUser.Type;
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(orgUser.Permissions);
}
public Guid Id { get; set; }
public OrganizationUserType Type { get; set; }
public Permissions Permissions { get; set; }
}
}

View File

@ -10,9 +10,9 @@ using System.Security.Claims;
using Bit.Core.Utilities;
using Bit.Core.Models.Data;
namespace Bit.Core
namespace Bit.Core.Context
{
public class CurrentContext
public class CurrentContext : ICurrentContext
{
private bool _builtHttpContext;
private bool _builtClaimsPrincipal;
@ -296,21 +296,5 @@ namespace Bit.Core
ManageUsers = hasClaim("manageusers")
};
}
public class CurrentContentOrganization
{
public CurrentContentOrganization() { }
public CurrentContentOrganization(OrganizationUser orgUser)
{
Id = orgUser.OrganizationId;
Type = orgUser.Type;
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(orgUser.Permissions);
}
public Guid Id { get; set; }
public OrganizationUserType Type { get; set; }
public Permissions Permissions { get; set; }
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Microsoft.AspNetCore.Http;
namespace Bit.Core.Context
{
public interface ICurrentContext
{
HttpContext HttpContext { get; set; }
Guid? UserId { get; set; }
User User { get; set; }
string DeviceIdentifier { get; set; }
DeviceType? DeviceType { get; set; }
string IpAddress { get; set; }
List<CurrentContentOrganization> Organizations { get; set; }
Guid? InstallationId { get; set; }
Guid? OrganizationId { get; set; }
Task BuildAsync(HttpContext httpContext, GlobalSettings globalSettings);
Task BuildAsync(ClaimsPrincipal user, GlobalSettings globalSettings);
Task SetContextAsync(ClaimsPrincipal user);
bool OrganizationUser(Guid orgId);
bool OrganizationManager(Guid orgId);
bool OrganizationAdmin(Guid orgId);
bool OrganizationOwner(Guid orgId);
bool OrganizationCustom(Guid orgId);
bool AccessBusinessPortal(Guid orgId);
bool AccessEventLogs(Guid orgId);
bool AccessImportExport(Guid orgId);
bool AccessReports(Guid orgId);
bool ManageAllCollections(Guid orgId);
bool ManageAssignedCollections(Guid orgId);
bool ManageGroups(Guid orgId);
bool ManagePolicies(Guid orgId);
bool ManageSso(Guid orgId);
bool ManageUsers(Guid orgId);
Task<ICollection<CurrentContentOrganization>> OrganizationMembershipAsync(
IOrganizationUserRepository organizationUserRepository, Guid userId);
}
}

View File

@ -8,5 +8,6 @@
SingleOrg = 3,
RequireSso = 4,
PersonalOwnership = 5,
DisableSend = 6,
}
}

View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Context;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.Core.Identity
@ -18,12 +19,12 @@ namespace Bit.Core.Identity
{
private readonly IServiceProvider _serviceProvider;
private readonly IUserRepository _userRepository;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public UserStore(
IServiceProvider serviceProvider,
IUserRepository userRepository,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_serviceProvider = serviceProvider;
_userRepository = userRepository;

View File

@ -17,6 +17,7 @@ using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Bit.Core.Models.Api;
using Bit.Core.Context;
namespace Bit.Core.IdentityServer
{
@ -33,7 +34,7 @@ namespace Bit.Core.IdentityServer
private readonly IApplicationCacheService _applicationCacheService;
private readonly IMailService _mailService;
private readonly ILogger<ResourceOwnerPasswordValidator> _logger;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly IPolicyRepository _policyRepository;
@ -49,7 +50,7 @@ namespace Bit.Core.IdentityServer
IApplicationCacheService applicationCacheService,
IMailService mailService,
ILogger<ResourceOwnerPasswordValidator> logger,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IPolicyRepository policyRepository)
{

View File

@ -9,6 +9,7 @@ using IdentityModel;
using Bit.Core.Utilities;
using System.Security.Claims;
using Bit.Core.Services;
using Bit.Core.Context;
using System.Collections.ObjectModel;
namespace Bit.Core.IdentityServer
@ -21,7 +22,7 @@ namespace Bit.Core.IdentityServer
private readonly GlobalSettings _globalSettings;
private readonly StaticClientStore _staticClientStore;
private readonly ILicensingService _licensingService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly IOrganizationUserRepository _organizationUserRepository;
public ClientStore(
@ -31,7 +32,7 @@ namespace Bit.Core.IdentityServer
GlobalSettings globalSettings,
StaticClientStore staticClientStore,
ILicensingService licensingService,
CurrentContext currentContext,
ICurrentContext currentContext,
IOrganizationUserRepository organizationUserRepository)
{
_installationRepository = installationRepository;

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Bit.Core.Services;
using Bit.Core.Context;
using System.Linq;
using Bit.Core.Identity;
using Microsoft.Extensions.Logging;
@ -31,7 +32,7 @@ namespace Bit.Core.IdentityServer
IApplicationCacheService applicationCacheService,
IMailService mailService,
ILogger<ResourceOwnerPasswordValidator> logger,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IPolicyRepository policyRepository)
: base(userManager, deviceRepository, deviceService, userService, eventService,

View File

@ -9,6 +9,7 @@ using System.Linq;
using System;
using IdentityModel;
using Bit.Core.Utilities;
using Bit.Core.Context;
namespace Bit.Core.IdentityServer
{
@ -17,13 +18,13 @@ namespace Bit.Core.IdentityServer
private readonly IUserService _userService;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ILicensingService _licensingService;
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
public ProfileService(
IUserService userService,
IOrganizationUserRepository organizationUserRepository,
ILicensingService licensingService,
CurrentContext currentContext)
ICurrentContext currentContext)
{
_userService = userService;
_organizationUserRepository = organizationUserRepository;

View File

@ -8,6 +8,7 @@ using System.Security.Claims;
using System.Threading.Tasks;
using Bit.Core.Services;
using Bit.Core.Identity;
using Bit.Core.Context;
using Microsoft.Extensions.Logging;
namespace Bit.Core.IdentityServer
@ -30,7 +31,7 @@ namespace Bit.Core.IdentityServer
IApplicationCacheService applicationCacheService,
IMailService mailService,
ILogger<ResourceOwnerPasswordValidator> logger,
CurrentContext currentContext,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IPolicyRepository policyRepository)
: base(userManager, deviceRepository, deviceService, userService, eventService,

View File

@ -1,5 +1,6 @@
using System;
using Bit.Core.Enums;
using Bit.Core.Context;
namespace Bit.Core.Models.Data
{
@ -7,7 +8,7 @@ namespace Bit.Core.Models.Data
{
public EventMessage() { }
public EventMessage(CurrentContext currentContext)
public EventMessage(ICurrentContext currentContext)
: base()
{
IpAddress = currentContext.IpAddress;

View File

@ -585,6 +585,17 @@
<value>Require users to save vault items to an organization by removing the personal ownership option.</value>
</data>
<data name="PersonalOwnershipExemption" xml:space="preserve">
<value>Organization users that can manage the organization's policies are exempt from this policy's enforcement.</value>
</data>
<data name="DisableSend" xml:space="preserve">
<value>Disable Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSendDescription" xml:space="preserve">
<value>Do not allow users to create or edit a Bitwarden Send. Deleting an existing Send is still allowed.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSendExemption" xml:space="preserve">
<value>Organization Owners and Administrators are exempt from this policy's enforcement.</value>
</data>
<data name="DisableRequireSsoError" xml:space="preserve">

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(

View File

@ -15,6 +15,7 @@ using System.Globalization;
using System.Web;
using Microsoft.AspNetCore.DataProtection;
using Bit.Core.Enums;
using Bit.Core.Context;
using System.Threading.Tasks;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
@ -685,7 +686,7 @@ namespace Bit.Core.Utilities
return configDict;
}
public static List<KeyValuePair<string, string>> BuildIdentityClaims(User user, ICollection<CurrentContext.CurrentContentOrganization> orgs, bool isPremium)
public static List<KeyValuePair<string, string>> BuildIdentityClaims(User user, ICollection<CurrentContentOrganization> orgs, bool isPremium)
{
var claims = new List<KeyValuePair<string, string>>()
{

View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Bit.Core.Context;
namespace Bit.Core.Utilities
{
@ -12,7 +13,7 @@ namespace Bit.Core.Utilities
_next = next;
}
public async Task Invoke(HttpContext httpContext, CurrentContext currentContext, GlobalSettings globalSettings)
public async Task Invoke(HttpContext httpContext, ICurrentContext currentContext, GlobalSettings globalSettings)
{
await currentContext.BuildAsync(httpContext, globalSettings);
await _next.Invoke(httpContext);

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
@ -18,12 +18,12 @@ namespace Bit.Events.Controllers
[Authorize("Application")]
public class CollectController : Controller
{
private readonly CurrentContext _currentContext;
private readonly ICurrentContext _currentContext;
private readonly IEventService _eventService;
private readonly ICipherRepository _cipherRepository;
public CollectController(
CurrentContext currentContext,
ICurrentContext currentContext,
IEventService eventService,
ICipherRepository cipherRepository)
{

View File

@ -1,5 +1,6 @@
using System.Globalization;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Services;
using Bit.Core.Utilities;
using IdentityModel;
@ -35,7 +36,7 @@ namespace Bit.Events
services.AddSqlServerRepositories(globalSettings);
// Context
services.AddScoped<CurrentContext>();
services.AddScoped<ICurrentContext, CurrentContext>();
// Identity
services.AddIdentityAuthenticationServices(globalSettings, Environment, config =>

View File

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Utilities;
using AspNetCoreRateLimit;
using System.Globalization;
@ -49,7 +50,7 @@ namespace Bit.Identity
services.AddSqlServerRepositories(globalSettings);
// Context
services.AddScoped<CurrentContext>();
services.AddScoped<ICurrentContext, CurrentContext>();
// Caching
services.AddMemoryCache();

View File

@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Context;
using Microsoft.AspNetCore.Authorization;
namespace Bit.Notifications