mirror of
https://github.com/bitwarden/server.git
synced 2025-02-01 23:31:41 +01:00
[Provider] Create and access child organizations (#1427)
This commit is contained in:
parent
a6128c781a
commit
feb3106f37
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Enums.Provider;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Business.Provider;
|
||||
using Bit.Core.Models.Table;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
@ -27,17 +28,19 @@ namespace Bit.CommCore.Services
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
|
||||
public ProviderService(IProviderRepository providerRepository, IProviderUserRepository providerUserRepository,
|
||||
IProviderOrganizationRepository providerOrganizationRepository, IUserRepository userRepository,
|
||||
IUserService userService, IMailService mailService, IDataProtectionProvider dataProtectionProvider,
|
||||
IEventService eventService, GlobalSettings globalSettings)
|
||||
IUserService userService, IOrganizationService organizationService, IMailService mailService,
|
||||
IDataProtectionProvider dataProtectionProvider, IEventService eventService, GlobalSettings globalSettings)
|
||||
{
|
||||
_providerRepository = providerRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
_userRepository = userRepository;
|
||||
_userService = userService;
|
||||
_organizationService = organizationService;
|
||||
_mailService = mailService;
|
||||
_eventService = eventService;
|
||||
_globalSettings = globalSettings;
|
||||
@ -344,6 +347,21 @@ namespace Bit.CommCore.Services
|
||||
await _providerOrganizationRepository.CreateAsync(providerOrganization);
|
||||
}
|
||||
|
||||
public async Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup, User user)
|
||||
{
|
||||
var (organization, _) = await _organizationService.SignUpAsync(organizationSignup, true);
|
||||
|
||||
var providerOrganization = new ProviderOrganization
|
||||
{
|
||||
ProviderId = providerId,
|
||||
OrganizationId = organization.Id,
|
||||
Key = organizationSignup.OwnerKey,
|
||||
};
|
||||
|
||||
await _providerOrganizationRepository.CreateAsync(providerOrganization);
|
||||
return providerOrganization;
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
public Task RemoveOrganization(Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException();
|
||||
|
||||
|
@ -15,8 +15,8 @@ namespace Bit.Portal
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public EnterprisePortalCurrentContext(IServiceProvider serviceProvider)
|
||||
: base()
|
||||
public EnterprisePortalCurrentContext(IProviderOrganizationRepository providerOrganizationRepository,
|
||||
IServiceProvider serviceProvider) : base(providerOrganizationRepository)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
@ -19,15 +19,17 @@ namespace Bit.Admin.Controllers
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly IProviderService _providerService;
|
||||
|
||||
public ProvidersController(IProviderRepository providerRepository, IProviderUserRepository providerUserRepository,
|
||||
IProviderService providerService, GlobalSettings globalSettings)
|
||||
IProviderService providerService, GlobalSettings globalSettings, IApplicationCacheService applicationCacheService)
|
||||
{
|
||||
_providerRepository = providerRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_providerService = providerService;
|
||||
_globalSettings = globalSettings;
|
||||
_applicationCacheService = applicationCacheService;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index(string name = null, string userEmail = null, int page = 1, int count = 25)
|
||||
@ -102,6 +104,23 @@ namespace Bit.Admin.Controllers
|
||||
return View(new ProviderEditModel(provider, users));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
[SelfHosted(NotSelfHostedOnly = true)]
|
||||
public async Task<IActionResult> Edit(Guid id, ProviderEditModel model)
|
||||
{
|
||||
var provider = await _providerRepository.GetByIdAsync(id);
|
||||
if (provider == null)
|
||||
{
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
model.ToProvider(provider);
|
||||
await _providerRepository.ReplaceAsync(provider);
|
||||
await _applicationCacheService.UpsertProviderAbilityAsync(provider);
|
||||
return RedirectToAction("Edit", new { id });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Delete(Guid id)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Bit.Core.Enums.Provider;
|
||||
using Bit.Core.Models.Data;
|
||||
@ -8,6 +9,8 @@ namespace Bit.Admin.Models
|
||||
{
|
||||
public class ProviderEditModel : ProviderViewModel
|
||||
{
|
||||
public ProviderEditModel() { }
|
||||
|
||||
public ProviderEditModel(Provider provider, IEnumerable<ProviderUserUserDetails> providerUsers)
|
||||
: base(provider, providerUsers)
|
||||
{
|
||||
@ -15,16 +18,24 @@ namespace Bit.Admin.Models
|
||||
BusinessName = provider.BusinessName;
|
||||
BillingEmail = provider.BillingEmail;
|
||||
Enabled = provider.Enabled;
|
||||
UseEvents = provider.UseEvents;
|
||||
}
|
||||
|
||||
public string Administrators { get; set; }
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public string BillingEmail { get; set; }
|
||||
|
||||
public string BusinessName { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
[Display(Name = "Events")]
|
||||
public bool UseEvents { get; set; }
|
||||
|
||||
public Provider ToProvider(Provider existingProvider)
|
||||
{
|
||||
existingProvider.Name = Name;
|
||||
existingProvider.BusinessName = BusinessName;
|
||||
existingProvider.BillingEmail = BillingEmail?.ToLowerInvariant()?.Trim();
|
||||
existingProvider.UseEvents = UseEvents;
|
||||
existingProvider.Enabled = Enabled;
|
||||
return existingProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ namespace Bit.Admin.Models
|
||||
{
|
||||
public class ProviderViewModel
|
||||
{
|
||||
public ProviderViewModel() { }
|
||||
|
||||
public ProviderViewModel(Provider provider, IEnumerable<ProviderUserUserDetails> providerUsers)
|
||||
{
|
||||
Provider = provider;
|
||||
|
@ -39,6 +39,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Features</h2>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseEvents">
|
||||
<label class="form-check-label" asp-for="UseEvents"></label>
|
||||
</div>
|
||||
</form>
|
||||
<div class="d-flex mt-4">
|
||||
<button type="submit" class="btn btn-primary" form="edit-form">Save</button>
|
||||
|
@ -373,8 +373,11 @@ namespace Bit.Api.Controllers
|
||||
OrganizationUserStatusType.Confirmed);
|
||||
var providerUserDetails = await _providerUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||
ProviderUserStatusType.Confirmed);
|
||||
var providerUserOrganizationDetails =
|
||||
await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id,
|
||||
ProviderUserStatusType.Confirmed);
|
||||
var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
||||
await _userService.TwoFactorIsEnabledAsync(user));
|
||||
providerUserOrganizationDetails, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -399,7 +402,7 @@ namespace Bit.Api.Controllers
|
||||
}
|
||||
|
||||
await _userService.SaveUserAsync(model.ToUser(user));
|
||||
var response = new ProfileResponseModel(user, null, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
var response = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -550,7 +553,7 @@ namespace Bit.Api.Controllers
|
||||
BillingAddressCountry = model.Country,
|
||||
BillingAddressPostalCode = model.PostalCode,
|
||||
});
|
||||
var profile = new ProfileResponseModel(user, null, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
var profile = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
return new PaymentResponseModel
|
||||
{
|
||||
UserProfile = profile,
|
||||
|
@ -71,7 +71,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(new Guid(id));
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -119,7 +119,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = model.ToCipherDetails(userId);
|
||||
if (cipher.OrganizationId.HasValue && !_currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
if (cipher.OrganizationId.HasValue && !await _currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -134,7 +134,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = model.Cipher.ToCipherDetails(userId);
|
||||
if (cipher.OrganizationId.HasValue && !_currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
if (cipher.OrganizationId.HasValue && !await _currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -148,7 +148,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<CipherMiniResponseModel> PostAdmin([FromBody]CipherCreateRequestModel model)
|
||||
{
|
||||
var cipher = model.Cipher.ToOrganizationCipher();
|
||||
if (!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
if (!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -192,7 +192,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(new Guid(id));
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -211,7 +211,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var orgIdGuid = new Guid(organizationId);
|
||||
if (!_currentContext.ManageAllCollections(orgIdGuid) && !_currentContext.AccessReports(orgIdGuid))
|
||||
if (!await _currentContext.ManageAllCollections(orgIdGuid) && !await _currentContext.AccessReports(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -254,7 +254,7 @@ namespace Bit.Api.Controllers
|
||||
}
|
||||
|
||||
var orgId = new Guid(organizationId);
|
||||
if (!_currentContext.AccessImportExport(orgId))
|
||||
if (!await _currentContext.AccessImportExport(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -282,7 +282,7 @@ namespace Bit.Api.Controllers
|
||||
var cipherId = new Guid(id);
|
||||
var cipher = await _cipherRepository.GetByIdAsync(cipherId);
|
||||
if (cipher == null || cipher.UserId != userId ||
|
||||
!_currentContext.OrganizationUser(new Guid(model.Cipher.OrganizationId)))
|
||||
!await _currentContext.OrganizationUser(new Guid(model.Cipher.OrganizationId)))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -303,7 +303,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id), userId);
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
!await _currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -319,7 +319,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id));
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -349,7 +349,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id));
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -382,7 +382,7 @@ namespace Bit.Api.Controllers
|
||||
}
|
||||
|
||||
if (model == null || string.IsNullOrWhiteSpace(model.OrganizationId) ||
|
||||
!_currentContext.ManageAllCollections(new Guid(model.OrganizationId)))
|
||||
!await _currentContext.ManageAllCollections(new Guid(model.OrganizationId)))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -409,7 +409,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id));
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -438,7 +438,7 @@ namespace Bit.Api.Controllers
|
||||
}
|
||||
|
||||
if (model == null || string.IsNullOrWhiteSpace(model.OrganizationId) ||
|
||||
!_currentContext.ManageAllCollections(new Guid(model.OrganizationId)))
|
||||
!await _currentContext.ManageAllCollections(new Guid(model.OrganizationId)))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -467,7 +467,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(new Guid(id));
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -514,7 +514,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PutShareMany([FromBody]CipherBulkShareRequestModel model)
|
||||
{
|
||||
var organizationId = new Guid(model.Ciphers.First().OrganizationId);
|
||||
if (!_currentContext.OrganizationUser(organizationId))
|
||||
if (!await _currentContext.OrganizationUser(organizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -561,7 +561,7 @@ namespace Bit.Api.Controllers
|
||||
else
|
||||
{
|
||||
var orgId = new Guid(organizationId);
|
||||
if (!_currentContext.ManageAllCollections(orgId))
|
||||
if (!await _currentContext.ManageAllCollections(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -579,7 +579,7 @@ namespace Bit.Api.Controllers
|
||||
await _cipherRepository.GetByIdAsync(idGuid, userId);
|
||||
|
||||
if (cipher == null || (request.AdminRequest && (!cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -686,7 +686,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(idGuid);
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -717,7 +717,7 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id));
|
||||
if (cipher == null || cipher.UserId != userId || !_currentContext.OrganizationUser(organizationId))
|
||||
if (cipher == null || cipher.UserId != userId || !await _currentContext.OrganizationUser(organizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -752,7 +752,7 @@ namespace Bit.Api.Controllers
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetByIdAsync(idGuid);
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!_currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
!await _currentContext.ManageAllCollections(cipher.OrganizationId.Value))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -45,13 +45,13 @@ namespace Bit.Api.Controllers
|
||||
public async Task<CollectionGroupDetailsResponseModel> GetDetails(string orgId, string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!ManageAnyCollections(orgIdGuid) && !_currentContext.ManageUsers(orgIdGuid))
|
||||
if (!await ManageAnyCollections(orgIdGuid) && !await _currentContext.ManageUsers(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var idGuid = new Guid(id);
|
||||
if (_currentContext.ManageAllCollections(orgIdGuid))
|
||||
if (await _currentContext.ManageAllCollections(orgIdGuid))
|
||||
{
|
||||
var collectionDetails = await _collectionRepository.GetByIdWithGroupsAsync(idGuid);
|
||||
if (collectionDetails?.Item1 == null || collectionDetails.Item1.OrganizationId != orgIdGuid)
|
||||
@ -76,7 +76,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<CollectionResponseModel>> Get(string orgId)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!_currentContext.ManageAllCollections(orgIdGuid) && !_currentContext.ManageUsers(orgIdGuid))
|
||||
if (!await _currentContext.ManageAllCollections(orgIdGuid) && !await _currentContext.ManageUsers(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -108,14 +108,14 @@ namespace Bit.Api.Controllers
|
||||
public async Task<CollectionResponseModel> Post(string orgId, [FromBody]CollectionRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!ManageAnyCollections(orgIdGuid))
|
||||
if (!await ManageAnyCollections(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var collection = model.ToCollection(orgIdGuid);
|
||||
await _collectionService.SaveAsync(collection, model.Groups?.Select(g => g.ToSelectionReadOnly()),
|
||||
!_currentContext.ManageAllCollections(orgIdGuid) ? _currentContext.UserId : null);
|
||||
!await _currentContext.ManageAllCollections(orgIdGuid) ? _currentContext.UserId : null);
|
||||
return new CollectionResponseModel(collection);
|
||||
}
|
||||
|
||||
@ -154,12 +154,12 @@ namespace Bit.Api.Controllers
|
||||
|
||||
private async Task<Collection> GetCollectionAsync(Guid id, Guid orgId)
|
||||
{
|
||||
if (!ManageAnyCollections(orgId))
|
||||
if (!await ManageAnyCollections(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var collection = _currentContext.OrganizationAdmin(orgId) ?
|
||||
var collection = await _currentContext.OrganizationAdmin(orgId) ?
|
||||
await _collectionRepository.GetByIdAsync(id) :
|
||||
await _collectionRepository.GetByIdAsync(id, _currentContext.UserId.Value);
|
||||
if (collection == null || collection.OrganizationId != orgId)
|
||||
@ -170,9 +170,9 @@ namespace Bit.Api.Controllers
|
||||
return collection;
|
||||
}
|
||||
|
||||
private bool ManageAnyCollections(Guid orgId)
|
||||
private async Task<bool> ManageAnyCollections(Guid orgId)
|
||||
{
|
||||
return _currentContext.ManageAssignedCollections(orgId) || _currentContext.ManageAllCollections(orgId);
|
||||
return await _currentContext.ManageAssignedCollections(orgId) || await _currentContext.ManageAllCollections(orgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ namespace Bit.Api.Controllers
|
||||
var canView = false;
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
canView = _currentContext.AccessEventLogs(cipher.OrganizationId.Value);
|
||||
canView = await _currentContext.AccessEventLogs(cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
@ -86,7 +86,7 @@ namespace Bit.Api.Controllers
|
||||
[FromQuery]DateTime? start = null, [FromQuery]DateTime? end = null, [FromQuery]string continuationToken = null)
|
||||
{
|
||||
var orgId = new Guid(id);
|
||||
if (!_currentContext.AccessEventLogs(orgId))
|
||||
if (!await _currentContext.AccessEventLogs(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -104,7 +104,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
var organizationUser = await _organizationUserRepository.GetByIdAsync(new Guid(id));
|
||||
if (organizationUser == null || !organizationUser.UserId.HasValue ||
|
||||
!_currentContext.AccessEventLogs(organizationUser.OrganizationId))
|
||||
!await _currentContext.AccessEventLogs(organizationUser.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<GroupResponseModel> Get(string orgId, string id)
|
||||
{
|
||||
var group = await _groupRepository.GetByIdAsync(new Guid(id));
|
||||
if (group == null || !_currentContext.ManageGroups(group.OrganizationId))
|
||||
if (group == null || !await _currentContext.ManageGroups(group.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -46,7 +46,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<GroupDetailsResponseModel> GetDetails(string orgId, string id)
|
||||
{
|
||||
var groupDetails = await _groupRepository.GetByIdWithCollectionsAsync(new Guid(id));
|
||||
if (groupDetails?.Item1 == null || !_currentContext.ManageGroups(groupDetails.Item1.OrganizationId))
|
||||
if (groupDetails?.Item1 == null || !await _currentContext.ManageGroups(groupDetails.Item1.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -58,10 +58,10 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<GroupResponseModel>> Get(string orgId)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
var canAccess = _currentContext.ManageGroups(orgIdGuid) ||
|
||||
_currentContext.ManageAssignedCollections(orgIdGuid) ||
|
||||
_currentContext.ManageAllCollections(orgIdGuid) ||
|
||||
_currentContext.ManageUsers(orgIdGuid);
|
||||
var canAccess = await _currentContext.ManageGroups(orgIdGuid) ||
|
||||
await _currentContext.ManageAssignedCollections(orgIdGuid) ||
|
||||
await _currentContext.ManageAllCollections(orgIdGuid) ||
|
||||
await _currentContext.ManageUsers(orgIdGuid);
|
||||
|
||||
if (!canAccess)
|
||||
{
|
||||
@ -78,7 +78,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
var idGuid = new Guid(id);
|
||||
var group = await _groupRepository.GetByIdAsync(idGuid);
|
||||
if (group == null || !_currentContext.ManageGroups(group.OrganizationId))
|
||||
if (group == null || !await _currentContext.ManageGroups(group.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -91,7 +91,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<GroupResponseModel> Post(string orgId, [FromBody]GroupRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!_currentContext.ManageGroups(orgIdGuid))
|
||||
if (!await _currentContext.ManageGroups(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -106,7 +106,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<GroupResponseModel> Put(string orgId, string id, [FromBody]GroupRequestModel model)
|
||||
{
|
||||
var group = await _groupRepository.GetByIdAsync(new Guid(id));
|
||||
if (group == null || !_currentContext.ManageGroups(group.OrganizationId))
|
||||
if (group == null || !await _currentContext.ManageGroups(group.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -119,7 +119,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PutUsers(string orgId, string id, [FromBody]IEnumerable<Guid> model)
|
||||
{
|
||||
var group = await _groupRepository.GetByIdAsync(new Guid(id));
|
||||
if (group == null || !_currentContext.ManageGroups(group.OrganizationId))
|
||||
if (group == null || !await _currentContext.ManageGroups(group.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -131,7 +131,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Delete(string orgId, string id)
|
||||
{
|
||||
var group = await _groupRepository.GetByIdAsync(new Guid(id));
|
||||
if (group == null || !_currentContext.ManageGroups(group.OrganizationId))
|
||||
if (group == null || !await _currentContext.ManageGroups(group.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -144,7 +144,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Delete(string orgId, string id, string orgUserId)
|
||||
{
|
||||
var group = await _groupRepository.GetByIdAsync(new Guid(id));
|
||||
if (group == null || !_currentContext.ManageGroups(group.OrganizationId))
|
||||
if (group == null || !await _currentContext.ManageGroups(group.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<OrganizationUserDetailsResponseModel> Get(string orgId, string id)
|
||||
{
|
||||
var organizationUser = await _organizationUserRepository.GetByIdWithCollectionsAsync(new Guid(id));
|
||||
if (organizationUser == null || !_currentContext.ManageUsers(organizationUser.Item1.OrganizationId))
|
||||
if (organizationUser == null || !await _currentContext.ManageUsers(organizationUser.Item1.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -61,9 +61,9 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<OrganizationUserUserDetailsResponseModel>> Get(string orgId)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageAssignedCollections(orgGuidId) &&
|
||||
!_currentContext.ManageGroups(orgGuidId) &&
|
||||
!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageAssignedCollections(orgGuidId) &&
|
||||
!await _currentContext.ManageGroups(orgGuidId) &&
|
||||
!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -79,8 +79,8 @@ namespace Bit.Api.Controllers
|
||||
public async Task<IEnumerable<string>> GetGroups(string orgId, string id)
|
||||
{
|
||||
var organizationUser = await _organizationUserRepository.GetByIdAsync(new Guid(id));
|
||||
if (organizationUser == null || (!_currentContext.ManageGroups(organizationUser.OrganizationId) &&
|
||||
!_currentContext.ManageUsers(organizationUser.OrganizationId)))
|
||||
if (organizationUser == null || (!await _currentContext.ManageGroups(organizationUser.OrganizationId) &&
|
||||
!await _currentContext.ManageUsers(organizationUser.OrganizationId)))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -95,7 +95,7 @@ namespace Bit.Api.Controllers
|
||||
{
|
||||
// Make sure the calling user can reset passwords for this org
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageResetPassword(orgGuidId))
|
||||
if (!await _currentContext.ManageResetPassword(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -128,7 +128,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Invite(string orgId, [FromBody]OrganizationUserInviteRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -141,7 +141,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkReinvite(string orgId, [FromBody]OrganizationUserBulkRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -156,7 +156,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Reinvite(string orgId, string id)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -181,7 +181,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Confirm(string orgId, string id, [FromBody]OrganizationUserConfirmRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -196,7 +196,7 @@ namespace Bit.Api.Controllers
|
||||
[FromBody]OrganizationUserBulkConfirmRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -213,7 +213,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<OrganizationUserPublicKeyResponseModel>> UserPublicKeys(string orgId, [FromBody]OrganizationUserBulkRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -228,7 +228,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Put(string orgId, string id, [FromBody]OrganizationUserUpdateRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -249,7 +249,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PutGroups(string orgId, string id, [FromBody]OrganizationUserUpdateGroupsRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -278,7 +278,7 @@ namespace Bit.Api.Controllers
|
||||
var orgGuidId = new Guid(orgId);
|
||||
|
||||
// Calling user must have Manage Reset Password permission
|
||||
if (!_currentContext.ManageResetPassword(orgGuidId))
|
||||
if (!await _currentContext.ManageResetPassword(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -310,7 +310,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Delete(string orgId, string id)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -324,7 +324,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkDelete(string orgId, [FromBody]OrganizationUserBulkRequestModel model)
|
||||
{
|
||||
var orgGuidId = new Guid(orgId);
|
||||
if (!_currentContext.ManageUsers(orgGuidId))
|
||||
if (!await _currentContext.ManageUsers(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<OrganizationResponseModel> Get(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -70,7 +70,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<BillingResponseModel> GetBilling(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -89,7 +89,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<OrganizationSubscriptionResponseModel> GetSubscription(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -120,7 +120,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<OrganizationLicense> GetLicense(string id, [FromQuery]Guid installationId)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -154,12 +154,6 @@ namespace Bit.Api.Controllers
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var plan = StaticStore.Plans.FirstOrDefault(plan => plan.Type == model.PlanType);
|
||||
if (plan == null || plan.LegacyYear != null)
|
||||
{
|
||||
throw new Exception("Invalid plan selected.");
|
||||
}
|
||||
|
||||
var organizationSignup = model.ToOrganizationSignup(user);
|
||||
var result = await _organizationService.SignUpAsync(organizationSignup);
|
||||
return new OrganizationResponseModel(result.Item1);
|
||||
@ -191,7 +185,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<OrganizationResponseModel> Put(string id, [FromBody]OrganizationUpdateRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -214,7 +208,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PostPayment(string id, [FromBody]PaymentRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -237,7 +231,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<PaymentResponseModel> PostUpgrade(string id, [FromBody]OrganizationUpgradeRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -255,7 +249,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<PaymentResponseModel> PostSeat(string id, [FromBody]OrganizationSeatRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -273,7 +267,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<PaymentResponseModel> PostStorage(string id, [FromBody]StorageRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -291,7 +285,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PostVerifyBank(string id, [FromBody]OrganizationVerifyBankRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -304,7 +298,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PostCancel(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -317,7 +311,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PostReinstate(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -329,7 +323,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Leave(string id)
|
||||
{
|
||||
var orgGuidId = new Guid(id);
|
||||
if (!_currentContext.OrganizationUser(orgGuidId))
|
||||
if (!await _currentContext.OrganizationUser(orgGuidId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -343,7 +337,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task Delete(string id, [FromBody]OrganizationDeleteRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -376,7 +370,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PostLicense(string id, LicenseRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -400,7 +394,7 @@ namespace Bit.Api.Controllers
|
||||
}
|
||||
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationAdmin(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationAdmin(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -419,7 +413,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ApiKeyResponseModel> ApiKey(string id, [FromBody]ApiKeyRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -452,7 +446,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ApiKeyResponseModel> RotateApiKey(string id, [FromBody]ApiKeyRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -487,7 +481,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<TaxInfoResponseModel> GetTaxInfo(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -507,7 +501,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task PutTaxInfo(string id, [FromBody]OrganizationTaxInfoUpdateRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationOwner(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<PolicyResponseModel> Get(string orgId, int type)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!_currentContext.ManagePolicies(orgIdGuid))
|
||||
if (!await _currentContext.ManagePolicies(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -70,7 +70,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<PolicyResponseModel>> Get(string orgId)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!_currentContext.ManagePolicies(orgIdGuid))
|
||||
if (!await _currentContext.ManagePolicies(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -109,7 +109,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<PolicyResponseModel> Put(string orgId, int type, [FromBody]PolicyRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(orgId);
|
||||
if (!_currentContext.ManagePolicies(orgIdGuid))
|
||||
if (!await _currentContext.ManagePolicies(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@ -58,5 +59,25 @@ namespace Bit.Api.Controllers
|
||||
|
||||
await _providerService.AddOrganization(providerId, model.OrganizationId, userId, model.Key);
|
||||
}
|
||||
|
||||
[HttpPost("")]
|
||||
[SelfHosted(NotSelfHostedOnly = true)]
|
||||
public async Task<ProviderOrganizationResponseModel> Post(Guid providerId, [FromBody]OrganizationCreateRequestModel model)
|
||||
{
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
if (!_currentContext.ManageProviderOrganizations(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var organizationSignup = model.ToOrganizationSignup(user);
|
||||
var result = await _providerService.CreateOrganizationAsync(providerId, organizationSignup, user);
|
||||
return new ProviderOrganizationResponseModel(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,11 +100,6 @@ namespace Bit.Api.Controllers
|
||||
[HttpPost("{id:guid}/accept")]
|
||||
public async Task Accept(Guid providerId, Guid id, [FromBody]ProviderUserAcceptRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
|
@ -68,6 +68,9 @@ namespace Bit.Api.Controllers
|
||||
OrganizationUserStatusType.Confirmed);
|
||||
var providerUserDetails = await _providerUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||
ProviderUserStatusType.Confirmed);
|
||||
var providerUserOrganizationDetails =
|
||||
await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id,
|
||||
ProviderUserStatusType.Confirmed);
|
||||
var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled);
|
||||
var folders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, hasEnabledOrgs);
|
||||
@ -86,8 +89,8 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, organizationUserDetails,
|
||||
providerUserDetails, folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains,
|
||||
policies, sends);
|
||||
providerUserDetails, providerUserOrganizationDetails, folders, collections, ciphers,
|
||||
collectionCiphersGroupDict, excludeDomains, policies, sends);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace Bit.Api.Controllers
|
||||
public async Task<ListResponseModel<TwoFactorProviderResponseModel>> GetOrganization(string id)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.OrganizationAdmin(orgIdGuid))
|
||||
if (!await _currentContext.OrganizationAdmin(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -169,7 +169,7 @@ namespace Bit.Api.Controllers
|
||||
var user = await CheckAsync(model.MasterPasswordHash, false);
|
||||
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.ManagePolicies(orgIdGuid))
|
||||
if (!await _currentContext.ManagePolicies(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -192,7 +192,7 @@ namespace Bit.Api.Controllers
|
||||
var user = await CheckAsync(model.MasterPasswordHash, false);
|
||||
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.ManagePolicies(orgIdGuid))
|
||||
if (!await _currentContext.ManagePolicies(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@ -332,7 +332,7 @@ namespace Bit.Api.Controllers
|
||||
var user = await CheckAsync(model.MasterPasswordHash, false);
|
||||
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!_currentContext.ManagePolicies(orgIdGuid))
|
||||
if (!await _currentContext.ManagePolicies(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -10,14 +10,17 @@ using System.Security.Claims;
|
||||
using Bit.Core.Enums.Provider;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.Context
|
||||
{
|
||||
public class CurrentContext : ICurrentContext
|
||||
{
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
private bool _builtHttpContext;
|
||||
private bool _builtClaimsPrincipal;
|
||||
private ICollection<ProviderOrganization> _providerOrganizations;
|
||||
|
||||
public virtual HttpContext HttpContext { get; set; }
|
||||
public virtual Guid? UserId { get; set; }
|
||||
@ -34,6 +37,11 @@ namespace Bit.Core.Context
|
||||
public virtual bool MaybeBot { get; set; }
|
||||
public virtual int? BotScore { get; set; }
|
||||
|
||||
public CurrentContext(IProviderOrganizationRepository providerOrganizationRepository)
|
||||
{
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
}
|
||||
|
||||
public async virtual Task BuildAsync(HttpContext httpContext, GlobalSettings globalSettings)
|
||||
{
|
||||
if (_builtHttpContext)
|
||||
@ -197,7 +205,7 @@ namespace Bit.Core.Context
|
||||
Permissions = SetOrganizationPermissionsFromClaims(c.Value, claimsDict)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
return organizations;
|
||||
}
|
||||
|
||||
@ -227,97 +235,106 @@ namespace Bit.Core.Context
|
||||
return providers;
|
||||
}
|
||||
|
||||
public bool OrganizationUser(Guid orgId)
|
||||
public async Task<bool> OrganizationUser(Guid orgId)
|
||||
{
|
||||
return Organizations?.Any(o => o.Id == orgId) ?? false;
|
||||
return (Organizations?.Any(o => o.Id == orgId) ?? false) || await OrganizationOwner(orgId);
|
||||
}
|
||||
|
||||
public bool OrganizationManager(Guid orgId)
|
||||
public async Task<bool> OrganizationManager(Guid orgId)
|
||||
{
|
||||
return Organizations?.Any(o => o.Id == orgId &&
|
||||
(o.Type == OrganizationUserType.Owner || o.Type == OrganizationUserType.Admin ||
|
||||
o.Type == OrganizationUserType.Manager)) ?? false;
|
||||
return await OrganizationAdmin(orgId) ||
|
||||
(Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Manager) ?? false);
|
||||
}
|
||||
|
||||
public bool OrganizationAdmin(Guid orgId)
|
||||
public async Task<bool> OrganizationAdmin(Guid orgId)
|
||||
{
|
||||
return Organizations?.Any(o => o.Id == orgId &&
|
||||
(o.Type == OrganizationUserType.Owner || o.Type == OrganizationUserType.Admin)) ?? false;
|
||||
return await OrganizationOwner(orgId) ||
|
||||
(Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Admin) ?? false);
|
||||
}
|
||||
|
||||
public bool OrganizationOwner(Guid orgId)
|
||||
public async Task<bool> OrganizationOwner(Guid orgId)
|
||||
{
|
||||
return Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Owner) ?? false;
|
||||
if (Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Owner) ?? false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Providers.Any())
|
||||
{
|
||||
return (await GetProviderOrganizations()).Any(po => po.OrganizationId == orgId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OrganizationCustom(Guid orgId)
|
||||
public Task<bool> OrganizationCustom(Guid orgId)
|
||||
{
|
||||
return Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Custom) ?? false;
|
||||
return Task.FromResult(Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Custom) ?? false);
|
||||
}
|
||||
|
||||
public bool AccessBusinessPortal(Guid orgId)
|
||||
public async Task<bool> AccessBusinessPortal(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.AccessBusinessPortal ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool AccessEventLogs(Guid orgId)
|
||||
public async Task<bool> AccessEventLogs(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.AccessEventLogs ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool AccessImportExport(Guid orgId)
|
||||
public async Task<bool> AccessImportExport(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.AccessImportExport ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool AccessReports(Guid orgId)
|
||||
public async Task<bool> AccessReports(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.AccessReports ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManageAllCollections(Guid orgId)
|
||||
public async Task<bool> ManageAllCollections(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManageAllCollections ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManageAssignedCollections(Guid orgId)
|
||||
public async Task<bool> ManageAssignedCollections(Guid orgId)
|
||||
{
|
||||
return OrganizationManager(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationManager(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManageAssignedCollections ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManageGroups(Guid orgId)
|
||||
public async Task<bool> ManageGroups(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManageGroups ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManagePolicies(Guid orgId)
|
||||
public async Task<bool> ManagePolicies(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManagePolicies ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManageSso(Guid orgId)
|
||||
public async Task<bool> ManageSso(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManageSso ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManageUsers(Guid orgId)
|
||||
public async Task<bool> ManageUsers(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManageUsers ?? false)) ?? false);
|
||||
}
|
||||
|
||||
public bool ManageResetPassword(Guid orgId)
|
||||
public async Task<bool> ManageResetPassword(Guid orgId)
|
||||
{
|
||||
return OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
|
||||
&& (o.Permissions?.ManageResetPassword ?? false)) ?? false);
|
||||
}
|
||||
|
||||
@ -403,5 +420,15 @@ namespace Bit.Core.Context
|
||||
ManageResetPassword = hasClaim("manageresetpassword")
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<ICollection<ProviderOrganization>> GetProviderOrganizations()
|
||||
{
|
||||
if (_providerOrganizations == null)
|
||||
{
|
||||
_providerOrganizations = await _providerOrganizationRepository.GetManyByUserIdAsync(UserId.Value);
|
||||
}
|
||||
|
||||
return _providerOrganizations;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,22 +31,22 @@ namespace Bit.Core.Context
|
||||
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);
|
||||
bool ManageResetPassword(Guid orgId);
|
||||
Task<bool> OrganizationUser(Guid orgId);
|
||||
Task<bool> OrganizationManager(Guid orgId);
|
||||
Task<bool> OrganizationAdmin(Guid orgId);
|
||||
Task<bool> OrganizationOwner(Guid orgId);
|
||||
Task<bool> OrganizationCustom(Guid orgId);
|
||||
Task<bool> AccessBusinessPortal(Guid orgId);
|
||||
Task<bool> AccessEventLogs(Guid orgId);
|
||||
Task<bool> AccessImportExport(Guid orgId);
|
||||
Task<bool> AccessReports(Guid orgId);
|
||||
Task<bool> ManageAllCollections(Guid orgId);
|
||||
Task<bool> ManageAssignedCollections(Guid orgId);
|
||||
Task<bool> ManageGroups(Guid orgId);
|
||||
Task<bool> ManagePolicies(Guid orgId);
|
||||
Task<bool> ManageSso(Guid orgId);
|
||||
Task<bool> ManageUsers(Guid orgId);
|
||||
Task<bool> ManageResetPassword(Guid orgId);
|
||||
bool ProviderProviderAdmin(Guid providerId);
|
||||
bool ProviderUser(Guid providerId);
|
||||
bool ManageProviderUsers(Guid providerId);
|
||||
|
@ -26,6 +26,7 @@ namespace Bit.Core.IdentityServer
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
|
||||
public ClientStore(
|
||||
IInstallationRepository installationRepository,
|
||||
@ -36,7 +37,8 @@ namespace Bit.Core.IdentityServer
|
||||
ILicensingService licensingService,
|
||||
ICurrentContext currentContext,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IProviderUserRepository providerUserRepository)
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IProviderOrganizationRepository providerOrganizationRepository)
|
||||
{
|
||||
_installationRepository = installationRepository;
|
||||
_organizationRepository = organizationRepository;
|
||||
@ -47,6 +49,7 @@ namespace Bit.Core.IdentityServer
|
||||
_currentContext = currentContext;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
}
|
||||
|
||||
public async Task<Client> FindClientByIdAsync(string clientId)
|
||||
|
@ -19,6 +19,7 @@ namespace Bit.Core.IdentityServer
|
||||
private readonly IUserService _userService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
private readonly ILicensingService _licensingService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
@ -26,12 +27,14 @@ namespace Bit.Core.IdentityServer
|
||||
IUserService userService,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IProviderOrganizationRepository providerOrganizationRepository,
|
||||
ILicensingService licensingService,
|
||||
ICurrentContext currentContext)
|
||||
{
|
||||
_userService = userService;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
_licensingService = licensingService;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Models.Api
|
||||
{
|
||||
public class ProfileProviderOrganizationResponseModel : ResponseModel
|
||||
{
|
||||
public ProfileProviderOrganizationResponseModel(ProviderUserOrganizationDetails organization)
|
||||
: base("profileProviderOrganization")
|
||||
{
|
||||
Id = organization.OrganizationId.ToString();
|
||||
Name = organization.Name;
|
||||
UsePolicies = organization.UsePolicies;
|
||||
UseSso = organization.UseSso;
|
||||
UseGroups = organization.UseGroups;
|
||||
UseDirectory = organization.UseDirectory;
|
||||
UseEvents = organization.UseEvents;
|
||||
UseTotp = organization.UseTotp;
|
||||
Use2fa = organization.Use2fa;
|
||||
UseApi = organization.UseApi;
|
||||
UseResetPassword = organization.UseResetPassword;
|
||||
UsersGetPremium = organization.UsersGetPremium;
|
||||
SelfHost = organization.SelfHost;
|
||||
Seats = organization.Seats;
|
||||
MaxCollections = organization.MaxCollections;
|
||||
MaxStorageGb = organization.MaxStorageGb;
|
||||
Key = organization.Key;
|
||||
HasPublicAndPrivateKeys = organization.PublicKey != null && organization.PrivateKey != null;
|
||||
Status = organization.Status;
|
||||
Type = organization.Type;
|
||||
Enabled = organization.Enabled;
|
||||
SsoBound = !string.IsNullOrWhiteSpace(organization.SsoExternalId);
|
||||
Identifier = organization.Identifier;
|
||||
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(organization.Permissions);
|
||||
ResetPasswordEnrolled = organization.ResetPasswordKey != null;
|
||||
UserId = organization.UserId?.ToString();
|
||||
ProviderId = organization.ProviderId?.ToString();
|
||||
ProviderName = organization.ProviderName;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool UsePolicies { get; set; }
|
||||
public bool UseSso { get; set; }
|
||||
public bool UseGroups { get; set; }
|
||||
public bool UseDirectory { get; set; }
|
||||
public bool UseEvents { get; set; }
|
||||
public bool UseTotp { get; set; }
|
||||
public bool Use2fa { get; set; }
|
||||
public bool UseApi { get; set; }
|
||||
public bool UseResetPassword { get; set; }
|
||||
public bool UseBusinessPortal => UsePolicies || UseSso; // TODO add events if needed
|
||||
public bool UsersGetPremium { get; set; }
|
||||
public bool SelfHost { get; set; }
|
||||
public int Seats { get; set; }
|
||||
public int MaxCollections { get; set; }
|
||||
public short? MaxStorageGb { get; set; }
|
||||
public string Key { get; set; }
|
||||
public OrganizationUserStatusType Status { get; set; }
|
||||
public OrganizationUserType Type { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public bool SsoBound { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
public Permissions Permissions { get; set; }
|
||||
public bool ResetPasswordEnrolled { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public bool HasPublicAndPrivateKeys { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
public string ProviderName { get; set; }
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ using Bit.Core.Models.Table;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Core.Models.Api
|
||||
{
|
||||
@ -11,7 +10,9 @@ namespace Bit.Core.Models.Api
|
||||
{
|
||||
public ProfileResponseModel(User user,
|
||||
IEnumerable<OrganizationUserOrganizationDetails> organizationsUserDetails,
|
||||
IEnumerable<ProviderUserProviderDetails> providerUserDetails, bool twoFactorEnabled) : base("profile")
|
||||
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
||||
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
|
||||
bool twoFactorEnabled) : base("profile")
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
@ -30,7 +31,9 @@ namespace Bit.Core.Models.Api
|
||||
PrivateKey = user.PrivateKey;
|
||||
SecurityStamp = user.SecurityStamp;
|
||||
Organizations = organizationsUserDetails?.Select(o => new ProfileOrganizationResponseModel(o));
|
||||
Providers = providerUserDetails?.Select(p => new ProfileProviderResponseModel(p));
|
||||
Providers = providerUserDetails?.Where(p => p.Enabled).Select(p => new ProfileProviderResponseModel(p));
|
||||
ProviderOrganizations =
|
||||
providerUserOrganizationDetails?.Select(po => new ProfileProviderOrganizationResponseModel(po));
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
@ -46,5 +49,6 @@ namespace Bit.Core.Models.Api
|
||||
public string SecurityStamp { get; set; }
|
||||
public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; }
|
||||
public IEnumerable<ProfileProviderResponseModel> Providers { get; set; }
|
||||
public IEnumerable<ProfileProviderOrganizationResponseModel> ProviderOrganizations { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace Bit.Core.Models.Api
|
||||
Enabled = provider.Enabled;
|
||||
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(provider.Permissions);
|
||||
UserId = provider.UserId?.ToString();
|
||||
UseEvents = provider.UseEvents;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
@ -27,5 +28,6 @@ namespace Bit.Core.Models.Api
|
||||
public bool Enabled { get; set; }
|
||||
public Permissions Permissions { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public bool UseEvents { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,39 @@
|
||||
using System;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
|
||||
namespace Bit.Core.Models.Api
|
||||
{
|
||||
public class ProviderOrganizationOrganizationDetailsResponseModel : ResponseModel
|
||||
public class ProviderOrganizationResponseModel : ResponseModel
|
||||
{
|
||||
public ProviderOrganizationOrganizationDetailsResponseModel(ProviderOrganizationOrganizationDetails providerOrganization,
|
||||
public ProviderOrganizationResponseModel(ProviderOrganization providerOrganization,
|
||||
string obj = "providerOrganization") : base(obj)
|
||||
{
|
||||
if (providerOrganization == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(providerOrganization));
|
||||
}
|
||||
|
||||
|
||||
Id = providerOrganization.Id;
|
||||
ProviderId = providerOrganization.ProviderId;
|
||||
OrganizationId = providerOrganization.OrganizationId;
|
||||
Key = providerOrganization.Key;
|
||||
Settings = providerOrganization.Settings;
|
||||
CreationDate = providerOrganization.CreationDate;
|
||||
RevisionDate = providerOrganization.RevisionDate;
|
||||
}
|
||||
|
||||
public ProviderOrganizationResponseModel(ProviderOrganizationOrganizationDetails providerOrganization,
|
||||
string obj = "providerOrganization") : base(obj)
|
||||
{
|
||||
if (providerOrganization == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(providerOrganization));
|
||||
}
|
||||
|
||||
Id = providerOrganization.Id;
|
||||
ProviderId = providerOrganization.ProviderId;
|
||||
OrganizationId = providerOrganization.OrganizationId;
|
||||
OrganizationName = providerOrganization.OrganizationName;
|
||||
Key = providerOrganization.Key;
|
||||
Settings = providerOrganization.Settings;
|
||||
CreationDate = providerOrganization.CreationDate;
|
||||
@ -26,10 +43,25 @@ namespace Bit.Core.Models.Api
|
||||
public Guid Id { get; set; }
|
||||
public Guid ProviderId { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public string OrganizationName { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string Settings { get; set; }
|
||||
public DateTime CreationDate { get; set; }
|
||||
public DateTime RevisionDate { get; set; }
|
||||
}
|
||||
|
||||
public class ProviderOrganizationOrganizationDetailsResponseModel : ProviderOrganizationResponseModel
|
||||
{
|
||||
public ProviderOrganizationOrganizationDetailsResponseModel(ProviderOrganizationOrganizationDetails providerOrganization,
|
||||
string obj = "providerOrganizationOrganizationDetail") : base(providerOrganization, obj)
|
||||
{
|
||||
if (providerOrganization == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(providerOrganization));
|
||||
}
|
||||
|
||||
OrganizationName = providerOrganization.OrganizationName;
|
||||
}
|
||||
|
||||
public string OrganizationName { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ namespace Bit.Core.Models.Api
|
||||
bool userTwoFactorEnabled,
|
||||
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails,
|
||||
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
||||
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
|
||||
IEnumerable<Folder> folders,
|
||||
IEnumerable<CollectionDetails> collections,
|
||||
IEnumerable<CipherDetails> ciphers,
|
||||
@ -25,7 +26,8 @@ namespace Bit.Core.Models.Api
|
||||
IEnumerable<Send> sends)
|
||||
: base("sync")
|
||||
{
|
||||
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails, userTwoFactorEnabled);
|
||||
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
||||
providerUserOrganizationDetails, userTwoFactorEnabled);
|
||||
Folders = folders.Select(f => new FolderResponseModel(f));
|
||||
Ciphers = ciphers.Select(c => new CipherDetailsResponseModel(c, globalSettings, collectionCiphersDict));
|
||||
Collections = collections?.Select(
|
||||
|
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class ProviderUserOrganizationDetails
|
||||
{
|
||||
public Guid OrganizationId { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool UsePolicies { get; set; }
|
||||
public bool UseSso { get; set; }
|
||||
public bool UseGroups { get; set; }
|
||||
public bool UseDirectory { get; set; }
|
||||
public bool UseEvents { get; set; }
|
||||
public bool UseTotp { get; set; }
|
||||
public bool Use2fa { get; set; }
|
||||
public bool UseApi{ get; set; }
|
||||
public bool UseResetPassword { get; set; }
|
||||
public bool UseBusinessPortal => UsePolicies || UseSso;
|
||||
public bool SelfHost { get; set; }
|
||||
public bool UsersGetPremium { get; set; }
|
||||
public int Seats { get; set; }
|
||||
public int MaxCollections { get; set; }
|
||||
public short? MaxStorageGb { get; set; }
|
||||
public string Key { get; set; }
|
||||
public Enums.OrganizationUserStatusType Status { get; set; }
|
||||
public Enums.OrganizationUserType Type { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string SsoExternalId { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
public string Permissions { get; set; }
|
||||
public string ResetPasswordKey { get; set; }
|
||||
public string PublicKey { get; set; }
|
||||
public string PrivateKey { get; set; }
|
||||
public Guid? ProviderId { get; set; }
|
||||
public string ProviderName { get; set; }
|
||||
}
|
||||
}
|
@ -13,5 +13,6 @@ namespace Bit.Core.Models.Data
|
||||
public ProviderUserType Type { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string Permissions { get; set; }
|
||||
public bool UseEvents { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -9,5 +9,6 @@ namespace Bit.Core.Repositories
|
||||
public interface IProviderOrganizationRepository : IRepository<ProviderOrganization, Guid>
|
||||
{
|
||||
Task<ICollection<ProviderOrganizationOrganizationDetails>> GetManyDetailsByProviderAsync(Guid providerId);
|
||||
Task<ICollection<ProviderOrganization>> GetManyByUserIdAsync(Guid userId);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace Bit.Core.Repositories
|
||||
Task<ICollection<ProviderUserUserDetails>> GetManyDetailsByProviderAsync(Guid providerId);
|
||||
Task<ICollection<ProviderUserProviderDetails>> GetManyDetailsByUserAsync(Guid userId,
|
||||
ProviderUserStatusType? status = null);
|
||||
Task<IEnumerable<ProviderUserOrganizationDetails>> GetManyOrganizationDetailsByUserAsync(Guid userId, ProviderUserStatusType? status = null);
|
||||
Task DeleteManyAsync(IEnumerable<Guid> userIds);
|
||||
Task<IEnumerable<ProviderUserPublicKey>> GetManyPublicKeysByProviderUserAsync(Guid providerId, IEnumerable<Guid> Ids);
|
||||
}
|
||||
|
@ -33,5 +33,18 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
return results.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<ProviderOrganization>> GetManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.QueryAsync<ProviderOrganization>(
|
||||
"[dbo].[ProviderOrganization_ReadByUserId]",
|
||||
new { UserId = userId },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
return results.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +115,20 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProviderUserOrganizationDetails>> GetManyOrganizationDetailsByUserAsync(Guid userId,
|
||||
ProviderUserStatusType? status = null)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.QueryAsync<ProviderUserOrganizationDetails>(
|
||||
"[dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]",
|
||||
new { UserId = userId, Status = status },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
return results.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteManyAsync(IEnumerable<Guid> providerUserIds)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Table;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
@ -11,6 +12,7 @@ namespace Bit.Core.Services
|
||||
Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync();
|
||||
Task<IDictionary<Guid, ProviderAbility>> GetProviderAbilitiesAsync();
|
||||
Task UpsertOrganizationAbilityAsync(Organization organization);
|
||||
Task UpsertProviderAbilityAsync(Provider provider);
|
||||
Task DeleteOrganizationAbilityAsync(Guid organizationId);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace Bit.Core.Services
|
||||
Task<string> AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb);
|
||||
Task<string> AdjustSeatsAsync(Guid organizationId, int seatAdjustment);
|
||||
Task VerifyBankAsync(Guid organizationId, int amount1, int amount2);
|
||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup);
|
||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup, bool provider = false);
|
||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationLicense license, User owner,
|
||||
string ownerKey, string collectionName, string publicKey, string privateKey);
|
||||
Task UpdateLicenseAsync(Guid organizationId, OrganizationLicense license);
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Bit.Core.Models.Table;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Business.Provider;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
|
||||
@ -24,8 +25,7 @@ namespace Bit.Core.Services
|
||||
Guid deletingUserId);
|
||||
|
||||
Task AddOrganization(Guid providerId, Guid organizationId, Guid addingUserId, string key);
|
||||
Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup, User user);
|
||||
Task RemoveOrganization(Guid providerOrganizationId, Guid removingUserId);
|
||||
|
||||
// TODO: Figure out how ProviderOrganizationProviderUsers should be managed
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ namespace Bit.Core.Services
|
||||
grantor.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>());
|
||||
await _userRepository.ReplaceAsync(grantor);
|
||||
|
||||
// Remove grantor from all organisations unless Owner
|
||||
// Remove grantor from all organizations unless Owner
|
||||
var orgUser = await _organizationUserRepository.GetManyByUserAsync(grantor.Id);
|
||||
foreach (var o in orgUser)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Table;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
@ -36,6 +37,21 @@ namespace Bit.Core.Services
|
||||
await InitProviderAbilitiesAsync();
|
||||
return _providerAbilities;
|
||||
}
|
||||
|
||||
public virtual async Task UpsertProviderAbilityAsync(Provider provider)
|
||||
{
|
||||
await InitProviderAbilitiesAsync();
|
||||
var newAbility = new ProviderAbility(provider);
|
||||
|
||||
if (_providerAbilities.ContainsKey(provider.Id))
|
||||
{
|
||||
_providerAbilities[provider.Id] = newAbility;
|
||||
}
|
||||
else
|
||||
{
|
||||
_providerAbilities.Add(provider.Id, newAbility);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task UpsertOrganizationAbilityAsync(Organization organization)
|
||||
{
|
||||
|
@ -552,15 +552,25 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup signup)
|
||||
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup signup,
|
||||
bool provider = false)
|
||||
{
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == signup.Plan && !p.Disabled);
|
||||
if (plan == null)
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == signup.Plan);
|
||||
if (!(plan is {LegacyYear: null}))
|
||||
{
|
||||
throw new BadRequestException("Invalid plan selected.");
|
||||
}
|
||||
|
||||
if (plan.Disabled)
|
||||
{
|
||||
throw new BadRequestException("Plan not found.");
|
||||
}
|
||||
|
||||
await ValidateSignUpPoliciesAsync(signup.Owner.Id);
|
||||
if (!provider)
|
||||
{
|
||||
await ValidateSignUpPoliciesAsync(signup.Owner.Id);
|
||||
}
|
||||
|
||||
ValidateOrganizationUpgradeParameters(plan, signup);
|
||||
|
||||
var organization = new Organization
|
||||
@ -598,7 +608,7 @@ namespace Bit.Core.Services
|
||||
RevisionDate = DateTime.UtcNow,
|
||||
};
|
||||
|
||||
if (plan.Type == PlanType.Free)
|
||||
if (plan.Type == PlanType.Free && !provider)
|
||||
{
|
||||
var adminCount =
|
||||
await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(signup.Owner.Id);
|
||||
@ -607,14 +617,15 @@ namespace Bit.Core.Services
|
||||
throw new BadRequestException("You can only be an admin of one free organization.");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (plan.Type != PlanType.Free)
|
||||
{
|
||||
await _paymentService.PurchaseOrganizationAsync(organization, signup.PaymentMethodType.Value,
|
||||
signup.PaymentToken, plan, signup.AdditionalStorageGb, signup.AdditionalSeats,
|
||||
signup.PremiumAccessAddon, signup.TaxInfo);
|
||||
}
|
||||
|
||||
var returnValue = await SignUpAsync(organization, signup.Owner.Id, signup.OwnerKey, signup.CollectionName, true);
|
||||
var ownerId = provider ? default : signup.Owner.Id;
|
||||
var returnValue = await SignUpAsync(organization, ownerId, signup.OwnerKey, signup.CollectionName, true);
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.Signup, organization)
|
||||
{
|
||||
@ -725,20 +736,6 @@ namespace Bit.Core.Services
|
||||
await _organizationRepository.CreateAsync(organization);
|
||||
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||
|
||||
var orgUser = new OrganizationUser
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
UserId = ownerId,
|
||||
Key = ownerKey,
|
||||
Type = OrganizationUserType.Owner,
|
||||
Status = OrganizationUserStatusType.Confirmed,
|
||||
AccessAll = true,
|
||||
CreationDate = organization.CreationDate,
|
||||
RevisionDate = organization.CreationDate
|
||||
};
|
||||
|
||||
await _organizationUserRepository.CreateAsync(orgUser);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(collectionName))
|
||||
{
|
||||
var defaultCollection = new Collection
|
||||
@ -751,11 +748,28 @@ namespace Bit.Core.Services
|
||||
await _collectionRepository.CreateAsync(defaultCollection);
|
||||
}
|
||||
|
||||
// push
|
||||
var deviceIds = await GetUserDeviceIdsAsync(orgUser.UserId.Value);
|
||||
await _pushRegistrationService.AddUserRegistrationOrganizationAsync(deviceIds,
|
||||
organization.Id.ToString());
|
||||
await _pushNotificationService.PushSyncOrgKeysAsync(ownerId);
|
||||
OrganizationUser orgUser = null;
|
||||
if (ownerId != default)
|
||||
{
|
||||
orgUser = new OrganizationUser
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
UserId = ownerId,
|
||||
Key = ownerKey,
|
||||
Type = OrganizationUserType.Owner,
|
||||
Status = OrganizationUserStatusType.Confirmed,
|
||||
AccessAll = true,
|
||||
CreationDate = organization.CreationDate,
|
||||
RevisionDate = organization.CreationDate
|
||||
};
|
||||
|
||||
await _organizationUserRepository.CreateAsync(orgUser);
|
||||
|
||||
var deviceIds = await GetUserDeviceIdsAsync(orgUser.UserId.Value);
|
||||
await _pushRegistrationService.AddUserRegistrationOrganizationAsync(deviceIds,
|
||||
organization.Id.ToString());
|
||||
await _pushNotificationService.PushSyncOrgKeysAsync(ownerId);
|
||||
}
|
||||
|
||||
return new Tuple<Organization, OrganizationUser>(organization, orgUser);
|
||||
}
|
||||
@ -1051,7 +1065,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
foreach (var type in inviteTypes)
|
||||
{
|
||||
ValidateOrganizationUserUpdatePermissions(organizationId, type, null);
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationId, type, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1158,7 +1172,7 @@ namespace Bit.Core.Services
|
||||
|
||||
if (invitingUserId.HasValue && invite.Type.HasValue)
|
||||
{
|
||||
ValidateOrganizationUserUpdatePermissions(organizationId, invite.Type.Value, null);
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationId, invite.Type.Value, null);
|
||||
}
|
||||
|
||||
if (organization.Seats.HasValue)
|
||||
@ -1172,6 +1186,12 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
var invitedIsOwner = invite.Type is OrganizationUserType.Owner;
|
||||
if (!invitedIsOwner && !await HasConfirmedOwnersExceptAsync(organizationId, new Guid[] {}))
|
||||
{
|
||||
throw new BadRequestException("Organization must have at least one confirmed owner.");
|
||||
}
|
||||
|
||||
var orgUsers = new List<OrganizationUser>();
|
||||
var orgUserInvitedCount = 0;
|
||||
foreach (var email in invite.Emails)
|
||||
@ -1532,7 +1552,7 @@ namespace Bit.Core.Services
|
||||
|
||||
if (savingUserId.HasValue)
|
||||
{
|
||||
ValidateOrganizationUserUpdatePermissions(user.OrganizationId, user.Type, originalUser.Type);
|
||||
await ValidateOrganizationUserUpdatePermissions(user.OrganizationId, user.Type, originalUser.Type);
|
||||
}
|
||||
|
||||
if (user.Type != OrganizationUserType.Owner &&
|
||||
@ -1564,7 +1584,7 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
if (orgUser.Type == OrganizationUserType.Owner && deletingUserId.HasValue &&
|
||||
!_currentContext.OrganizationOwner(organizationId))
|
||||
!await _currentContext.OrganizationOwner(organizationId))
|
||||
{
|
||||
throw new BadRequestException("Only owners can delete other owners.");
|
||||
}
|
||||
@ -1626,7 +1646,7 @@ namespace Bit.Core.Services
|
||||
var deletingUserIsOwner = false;
|
||||
if (deletingUserId.HasValue)
|
||||
{
|
||||
deletingUserIsOwner = _currentContext.OrganizationOwner(organizationId);
|
||||
deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId);
|
||||
}
|
||||
|
||||
var result = new List<Tuple<OrganizationUser, string>>();
|
||||
@ -1676,7 +1696,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
if (loggedInUserId.HasValue)
|
||||
{
|
||||
ValidateOrganizationUserUpdatePermissions(organizationUser.OrganizationId, organizationUser.Type, null);
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationUser.OrganizationId, organizationUser.Type, null);
|
||||
}
|
||||
await _organizationUserRepository.UpdateGroupsAsync(organizationUser.Id, groupIds);
|
||||
await _eventService.LogOrganizationUserEventAsync(organizationUser,
|
||||
@ -1961,7 +1981,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task<Organization> UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey)
|
||||
{
|
||||
if (!_currentContext.ManageResetPassword(orgId))
|
||||
if (!await _currentContext.ManageResetPassword(orgId))
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
@ -1972,7 +1992,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
throw new BadRequestException("Organization Keys already exist");
|
||||
}
|
||||
|
||||
|
||||
// Update org with generated public/private key
|
||||
org.PublicKey = publicKey;
|
||||
org.PrivateKey = privateKey;
|
||||
@ -2072,10 +2092,10 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateOrganizationUserUpdatePermissions(Guid organizationId, OrganizationUserType newType,
|
||||
private async Task ValidateOrganizationUserUpdatePermissions(Guid organizationId, OrganizationUserType newType,
|
||||
OrganizationUserType? oldType)
|
||||
{
|
||||
if (_currentContext.OrganizationOwner(organizationId))
|
||||
if (await _currentContext.OrganizationOwner(organizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -2085,7 +2105,7 @@ namespace Bit.Core.Services
|
||||
throw new BadRequestException("Only an Owner can configure another Owner's account.");
|
||||
}
|
||||
|
||||
if (_currentContext.OrganizationAdmin(organizationId))
|
||||
if (await _currentContext.OrganizationAdmin(organizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -2095,7 +2115,7 @@ namespace Bit.Core.Services
|
||||
throw new BadRequestException("Only Owners and Admins can configure Custom accounts.");
|
||||
}
|
||||
|
||||
if (!_currentContext.ManageUsers(organizationId))
|
||||
if (!await _currentContext.ManageUsers(organizationId))
|
||||
{
|
||||
throw new BadRequestException("Your account does not have permission to manage users.");
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ namespace Bit.Core.Services
|
||||
|
||||
foreach (var policy in policies.Where(p => p.Enabled && p.Type == PolicyType.DisableSend))
|
||||
{
|
||||
if (!_currentContext.ManagePolicies(policy.OrganizationId))
|
||||
if (!await _currentContext.ManagePolicies(policy.OrganizationId))
|
||||
{
|
||||
throw new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.");
|
||||
}
|
||||
@ -292,8 +292,13 @@ namespace Bit.Core.Services
|
||||
|
||||
if (send.HideEmail.GetValueOrDefault())
|
||||
{
|
||||
foreach (var policy in policies.Where(p => p.Enabled && p.Type == PolicyType.SendOptions && !_currentContext.ManagePolicies(p.OrganizationId)))
|
||||
foreach (var policy in policies.Where(p => p.Enabled && p.Type == PolicyType.SendOptions))
|
||||
{
|
||||
if (await _currentContext.ManagePolicies(policy.OrganizationId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SendOptionsPolicyData data = null;
|
||||
if (policy.Data != null)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Business.Provider;
|
||||
using Bit.Core.Models.Table;
|
||||
using Bit.Core.Models.Table.Provider;
|
||||
@ -28,6 +29,7 @@ namespace Bit.Core.Services
|
||||
public Task<List<Tuple<ProviderUser, string>>> DeleteUsersAsync(Guid providerId, IEnumerable<Guid> providerUserIds, Guid deletingUserId) => throw new NotImplementedException();
|
||||
|
||||
public Task AddOrganization(Guid providerId, Guid organizationId, Guid addingUserId, string key) => throw new NotImplementedException();
|
||||
public Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup, User user) => throw new NotImplementedException();
|
||||
|
||||
public Task RemoveOrganization(Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@ -9,18 +10,21 @@ namespace Bit.Notifications
|
||||
[Authorize("Application")]
|
||||
public class NotificationsHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
{
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
private readonly ConnectionCounter _connectionCounter;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public NotificationsHub(ConnectionCounter connectionCounter, GlobalSettings globalSettings)
|
||||
public NotificationsHub(IProviderOrganizationRepository providerOrganizationRepository,
|
||||
ConnectionCounter connectionCounter, GlobalSettings globalSettings)
|
||||
{
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
_connectionCounter = connectionCounter;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
var currentContext = new CurrentContext();
|
||||
var currentContext = new CurrentContext(_providerOrganizationRepository);
|
||||
await currentContext.BuildAsync(Context.User, _globalSettings);
|
||||
if (currentContext.Organizations != null)
|
||||
{
|
||||
@ -35,7 +39,7 @@ namespace Bit.Notifications
|
||||
|
||||
public override async Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
var currentContext = new CurrentContext();
|
||||
var currentContext = new CurrentContext(_providerOrganizationRepository);
|
||||
await currentContext.BuildAsync(Context.User, _globalSettings);
|
||||
if (currentContext.Organizations != null)
|
||||
{
|
||||
|
@ -70,6 +70,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Build Include="dbo\Stored Procedures\EmergencyAccessDetails_ReadByIdGrantorId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_ReadByUserId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\ProviderUserProviderOrganizationDetails_ReadByUserIdStatus.sql" />
|
||||
<Build Include="dbo\Stored Procedures\SsoConfig_Create.sql" />
|
||||
<Build Include="dbo\Stored Procedures\SsoConfig_ReadByIdentifier.sql" />
|
||||
<Build Include="dbo\Stored Procedures\SsoConfig_ReadByOrganizationId.sql" />
|
||||
@ -93,6 +95,7 @@
|
||||
<Build Include="dbo\Views\GrantView.sql" />
|
||||
<Build Include="dbo\Views\ProviderOrganizationOrganizationDetailsView.sql" />
|
||||
<Build Include="dbo\Views\ProviderUserProviderDetailsView.sql" />
|
||||
<Build Include="dbo\Views\ProviderUserProviderOrganizationDetailsView.sql" />
|
||||
<Build Include="dbo\Views\SsoConfigView.sql" />
|
||||
<Build Include="dbo\Views\UserView.sql" />
|
||||
<Build Include="dbo\Views\U2fView.sql" />
|
||||
|
@ -0,0 +1,17 @@
|
||||
CREATE PROCEDURE [dbo].[ProviderOrganization_ReadByUserId]
|
||||
@UserId UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
PO.*
|
||||
FROM
|
||||
[dbo].[ProviderOrganizationView] PO
|
||||
INNER JOIN
|
||||
[dbo].[Provider] P ON PO.[ProviderId] = P.[Id]
|
||||
INNER JOIN
|
||||
[dbo].[ProviderUser] PU ON P.[Id] = PU.[ProviderId]
|
||||
WHERE
|
||||
PU.[UserId] = @UserId
|
||||
END
|
@ -0,0 +1,15 @@
|
||||
CREATE PROCEDURE [dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@Status TINYINT
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
[dbo].[ProviderUserProviderOrganizationDetailsView]
|
||||
WHERE
|
||||
[UserId] = @UserId
|
||||
AND (@Status IS NULL OR [Status] = @Status)
|
||||
END
|
@ -8,7 +8,8 @@ SELECT
|
||||
PU.[Status],
|
||||
PU.[Type],
|
||||
P.[Enabled],
|
||||
PU.[Permissions]
|
||||
PU.[Permissions],
|
||||
P.[UseEvents]
|
||||
FROM
|
||||
[dbo].[ProviderUser] PU
|
||||
LEFT JOIN
|
||||
|
@ -0,0 +1,37 @@
|
||||
CREATE VIEW [dbo].[ProviderUserProviderOrganizationDetailsView]
|
||||
AS
|
||||
SELECT
|
||||
PU.[UserId],
|
||||
PO.[OrganizationId],
|
||||
O.[Name],
|
||||
O.[Enabled],
|
||||
O.[UsePolicies],
|
||||
O.[UseSso],
|
||||
O.[UseGroups],
|
||||
O.[UseDirectory],
|
||||
O.[UseEvents],
|
||||
O.[UseTotp],
|
||||
O.[Use2fa],
|
||||
O.[UseApi],
|
||||
O.[UseResetPassword],
|
||||
O.[SelfHost],
|
||||
O.[UsersGetPremium],
|
||||
O.[Seats],
|
||||
O.[MaxCollections],
|
||||
O.[MaxStorageGb],
|
||||
O.[Identifier],
|
||||
PO.[Key],
|
||||
O.[PublicKey],
|
||||
O.[PrivateKey],
|
||||
PU.[Status],
|
||||
PU.[Type],
|
||||
PO.[ProviderId],
|
||||
P.[Name] ProviderName
|
||||
FROM
|
||||
[dbo].[ProviderUser] PU
|
||||
INNER JOIN
|
||||
[dbo].[ProviderOrganization] PO ON PO.[ProviderId] = PU.[ProviderId]
|
||||
INNER JOIN
|
||||
[dbo].[Organization] O ON O.[Id] = PO.[OrganizationId]
|
||||
INNER JOIN
|
||||
[dbo].[Provider] P ON P.[Id] = PU.[ProviderId]
|
@ -23,7 +23,7 @@ namespace Bit.Core.Test.Services
|
||||
_eventWriteService = Substitute.For<IEventWriteService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_applicationCacheService = Substitute.For<IApplicationCacheService>();
|
||||
_currentContext = new CurrentContext();
|
||||
_currentContext = new CurrentContext(null);
|
||||
_globalSettings = new GlobalSettings();
|
||||
|
||||
_sut = new EventService(
|
||||
|
@ -188,6 +188,21 @@ namespace Bit.Core.Test.Services
|
||||
await Assert.ThrowsAsync<NotFoundException>(
|
||||
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationInviteAutoData(
|
||||
inviteeUserType: (int)OrganizationUserType.Admin,
|
||||
invitorUserType: (int)OrganizationUserType.Owner
|
||||
)]
|
||||
public async Task InviteUser_NoOwner_Throws(Organization organization, OrganizationUser invitor,
|
||||
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(organization.Id).Returns(true);
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
||||
Assert.Contains("Organization must have at least one confirmed owner.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationInviteAutoData(
|
||||
@ -288,10 +303,14 @@ namespace Bit.Core.Test.Services
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
invite.Permissions = null;
|
||||
invitor.Status = OrganizationUserStatusType.Confirmed;
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
var currentContext = sutProvider.GetDependency<ICurrentContext>();
|
||||
|
||||
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
||||
organizationUserRepository.GetManyByOrganizationAsync(organization.Id, OrganizationUserType.Owner)
|
||||
.Returns(new [] {invitor});
|
||||
currentContext.OrganizationOwner(organization.Id).Returns(true);
|
||||
|
||||
await sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite);
|
||||
@ -303,7 +322,9 @@ namespace Bit.Core.Test.Services
|
||||
invitorUserType: (int)OrganizationUserType.Custom
|
||||
)]
|
||||
public async Task InviteUser_Passes(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
OrganizationUser invitor,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)]OrganizationUser owner,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = true },
|
||||
new JsonSerializerOptions
|
||||
@ -312,9 +333,12 @@ namespace Bit.Core.Test.Services
|
||||
});
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
var currentContext = sutProvider.GetDependency<ICurrentContext>();
|
||||
|
||||
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
||||
organizationUserRepository.GetManyByOrganizationAsync(organization.Id, OrganizationUserType.Owner)
|
||||
.Returns(new [] {owner});
|
||||
currentContext.ManageUsers(organization.Id).Returns(true);
|
||||
|
||||
await sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite);
|
||||
|
@ -72,7 +72,7 @@ namespace Bit.Core.Test.Services
|
||||
_policyRepository = Substitute.For<IPolicyRepository>();
|
||||
_referenceEventService = Substitute.For<IReferenceEventService>();
|
||||
_fido2 = Substitute.For<IFido2>();
|
||||
_currentContext = new CurrentContext();
|
||||
_currentContext = new CurrentContext(null);
|
||||
_globalSettings = new GlobalSettings();
|
||||
_organizationService = Substitute.For<IOrganizationService>();
|
||||
_sendRepository = Substitute.For<ISendRepository>();
|
||||
|
@ -1097,7 +1097,8 @@ SELECT
|
||||
PU.[Status],
|
||||
PU.[Type],
|
||||
P.[Enabled],
|
||||
PU.[Permissions]
|
||||
PU.[Permissions],
|
||||
P.[UseEvents]
|
||||
FROM
|
||||
[dbo].[ProviderUser] PU
|
||||
LEFT JOIN
|
||||
@ -1122,8 +1123,8 @@ BEGIN
|
||||
FROM
|
||||
[dbo].[ProviderUserProviderDetailsView]
|
||||
WHERE
|
||||
[UserId] = @UserId
|
||||
AND (@Status IS NULL OR [Status] = @Status)
|
||||
[UserId] = @UserId
|
||||
AND (@Status IS NULL OR [Status] = @Status)
|
||||
END
|
||||
GO
|
||||
|
||||
@ -1266,3 +1267,96 @@ LEFT JOIN
|
||||
[dbo].[ProviderOrganization] PO ON PO.[OrganizationId] = O.[Id]
|
||||
LEFT JOIN
|
||||
[dbo].[Provider] P ON P.[Id] = PO.[ProviderId]
|
||||
GO
|
||||
|
||||
IF OBJECT_ID('[dbo].[ProviderOrganization_ReadByUserId]') IS NOT NULL
|
||||
BEGIN
|
||||
DROP PROCEDURE [dbo].[ProviderOrganization_ReadByUserId]
|
||||
END
|
||||
GO
|
||||
|
||||
CREATE PROCEDURE [dbo].[ProviderOrganization_ReadByUserId]
|
||||
@UserId UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
PO.*
|
||||
FROM
|
||||
[dbo].[ProviderOrganizationView] PO
|
||||
INNER JOIN
|
||||
[dbo].[Provider] P ON PO.[ProviderId] = P.[Id]
|
||||
INNER JOIN
|
||||
[dbo].[ProviderUser] PU ON P.[Id] = PU.[ProviderId]
|
||||
WHERE
|
||||
PU.[UserId] = @UserId
|
||||
END
|
||||
GO
|
||||
|
||||
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'ProviderUserProviderOrganizationDetailsView')
|
||||
BEGIN
|
||||
DROP VIEW [dbo].[ProviderUserProviderOrganizationDetailsView];
|
||||
END
|
||||
GO
|
||||
|
||||
CREATE VIEW [dbo].[ProviderUserProviderOrganizationDetailsView]
|
||||
AS
|
||||
SELECT
|
||||
PU.[UserId],
|
||||
PO.[OrganizationId],
|
||||
O.[Name],
|
||||
O.[Enabled],
|
||||
O.[UsePolicies],
|
||||
O.[UseSso],
|
||||
O.[UseGroups],
|
||||
O.[UseDirectory],
|
||||
O.[UseEvents],
|
||||
O.[UseTotp],
|
||||
O.[Use2fa],
|
||||
O.[UseApi],
|
||||
O.[UseResetPassword],
|
||||
O.[SelfHost],
|
||||
O.[UsersGetPremium],
|
||||
O.[Seats],
|
||||
O.[MaxCollections],
|
||||
O.[MaxStorageGb],
|
||||
O.[Identifier],
|
||||
PO.[Key],
|
||||
O.[PublicKey],
|
||||
O.[PrivateKey],
|
||||
PU.[Status],
|
||||
PU.[Type],
|
||||
PO.[ProviderId],
|
||||
P.[Name] ProviderName
|
||||
FROM
|
||||
[dbo].[ProviderUser] PU
|
||||
INNER JOIN
|
||||
[dbo].[ProviderOrganization] PO ON PO.[ProviderId] = PU.[ProviderId]
|
||||
INNER JOIN
|
||||
[dbo].[Organization] O ON O.[Id] = PO.[OrganizationId]
|
||||
INNER JOIN
|
||||
[dbo].[Provider] P ON P.[Id] = PU.[ProviderId]
|
||||
GO
|
||||
|
||||
IF OBJECT_ID('[dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]') IS NOT NULL
|
||||
BEGIN
|
||||
DROP PROCEDURE [dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]
|
||||
END
|
||||
GO
|
||||
|
||||
CREATE PROCEDURE [dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@Status TINYINT
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
[dbo].[ProviderUserProviderOrganizationDetailsView]
|
||||
WHERE
|
||||
[UserId] = @UserId
|
||||
AND (@Status IS NULL OR [Status] = @Status)
|
||||
END
|
Loading…
Reference in New Issue
Block a user