1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-23 17:07:42 +01:00

Invite Client owner at time of client org creation (#1488)

This commit is contained in:
Matt Gibson 2021-07-30 08:10:58 -05:00 committed by GitHub
parent fdaf6b14d4
commit 2298c96e30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 8 deletions

View File

@ -7,6 +7,7 @@ using Bit.Core.Enums.Provider;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.Business.Provider; using Bit.Core.Models.Business.Provider;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table; using Bit.Core.Models.Table;
using Bit.Core.Models.Table.Provider; using Bit.Core.Models.Table.Provider;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@ -374,7 +375,8 @@ namespace Bit.CommCore.Services
await _eventService.LogProviderOrganizationEventAsync(providerOrganization, EventType.ProviderOrganization_Added); await _eventService.LogProviderOrganizationEventAsync(providerOrganization, EventType.ProviderOrganization_Added);
} }
public async Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup, User user) public async Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId,
OrganizationSignup organizationSignup, string clientOwnerEmail, User user)
{ {
var (organization, _) = await _organizationService.SignUpAsync(organizationSignup, true); var (organization, _) = await _organizationService.SignUpAsync(organizationSignup, true);
@ -388,6 +390,15 @@ namespace Bit.CommCore.Services
await _providerOrganizationRepository.CreateAsync(providerOrganization); await _providerOrganizationRepository.CreateAsync(providerOrganization);
await _eventService.LogProviderOrganizationEventAsync(providerOrganization, EventType.ProviderOrganization_Created); await _eventService.LogProviderOrganizationEventAsync(providerOrganization, EventType.ProviderOrganization_Created);
await _organizationService.InviteUserAsync(organization.Id, user.Id, null, new OrganizationUserInvite
{
Emails = new[] { clientOwnerEmail },
AccessAll = true,
Type = OrganizationUserType.Owner,
Permissions = null,
Collections = Array.Empty<SelectionReadOnly>(),
});
return providerOrganization; return providerOrganization;
} }

View File

@ -433,7 +433,7 @@ namespace Bit.CommCore.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))] [Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task CreateOrganizationAsync_Success(Provider provider, OrganizationSignup organizationSignup, public async Task CreateOrganizationAsync_Success(Provider provider, OrganizationSignup organizationSignup,
Organization organization, User user, SutProvider<ProviderService> sutProvider) Organization organization, string clientOwnerEmail, User user, SutProvider<ProviderService> sutProvider)
{ {
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider); sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>(); var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
@ -441,12 +441,19 @@ namespace Bit.CommCore.Test.Services
.Returns(Tuple.Create(organization, null as OrganizationUser)); .Returns(Tuple.Create(organization, null as OrganizationUser));
var providerOrganization = var providerOrganization =
await sutProvider.Sut.CreateOrganizationAsync(provider.Id, organizationSignup, user); await sutProvider.Sut.CreateOrganizationAsync(provider.Id, organizationSignup, clientOwnerEmail, user);
await providerOrganizationRepository.ReceivedWithAnyArgs().CreateAsync(default); await providerOrganizationRepository.ReceivedWithAnyArgs().CreateAsync(default);
await sutProvider.GetDependency<IEventService>() await sutProvider.GetDependency<IEventService>()
.Received().LogProviderOrganizationEventAsync(providerOrganization, .Received().LogProviderOrganizationEventAsync(providerOrganization,
EventType.ProviderOrganization_Created); EventType.ProviderOrganization_Created);
await sutProvider.GetDependency<IOrganizationService>()
.Received().InviteUserAsync(organization.Id, user.Id, null,
Arg.Is<OrganizationUserInvite>(
i => i.Emails.Count() == 1 &&
i.Emails.First() == clientOwnerEmail &&
i.Type == OrganizationUserType.Owner &&
i.AccessAll));
} }
[Theory, CustomAutoData(typeof(SutProviderCustomization))] [Theory, CustomAutoData(typeof(SutProviderCustomization))]

View File

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.Api.Request;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Utilities; using Bit.Core.Utilities;
@ -62,7 +63,7 @@ namespace Bit.Api.Controllers
[HttpPost("")] [HttpPost("")]
[SelfHosted(NotSelfHostedOnly = true)] [SelfHosted(NotSelfHostedOnly = true)]
public async Task<ProviderOrganizationResponseModel> Post(Guid providerId, [FromBody]OrganizationCreateRequestModel model) public async Task<ProviderOrganizationResponseModel> Post(Guid providerId, [FromBody] ProviderOrganizationCreateRequestModel model)
{ {
var user = await _userService.GetUserByPrincipalAsync(User); var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null) if (user == null)
@ -75,8 +76,8 @@ namespace Bit.Api.Controllers
throw new NotFoundException(); throw new NotFoundException();
} }
var organizationSignup = model.ToOrganizationSignup(user); var organizationSignup = model.OrganizationCreateRequest.ToOrganizationSignup(user);
var result = await _providerService.CreateOrganizationAsync(providerId, organizationSignup, user); var result = await _providerService.CreateOrganizationAsync(providerId, organizationSignup, model.ClientOwnerEmail, user);
return new ProviderOrganizationResponseModel(result); return new ProviderOrganizationResponseModel(result);
} }

View File

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api.Request
{
public class ProviderOrganizationCreateRequestModel
{
[Required]
[StrictEmailAddress]
public string ClientOwnerEmail { get; set; }
[Required]
public OrganizationCreateRequestModel OrganizationCreateRequest { get; set; }
}
}

View File

@ -25,7 +25,8 @@ namespace Bit.Core.Services
Guid deletingUserId); Guid deletingUserId);
Task AddOrganization(Guid providerId, Guid organizationId, Guid addingUserId, string key); Task AddOrganization(Guid providerId, Guid organizationId, Guid addingUserId, string key);
Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup, User user); Task<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup,
string clientOwnerEmail, User user);
Task RemoveOrganization(Guid providerId, Guid providerOrganizationId, Guid removingUserId); Task RemoveOrganization(Guid providerId, Guid providerOrganizationId, Guid removingUserId);
} }
} }

View File

@ -29,7 +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<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 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<ProviderOrganization> CreateOrganizationAsync(Guid providerId, OrganizationSignup organizationSignup, string clientOwnerEmail, User user) => throw new NotImplementedException();
public Task RemoveOrganization(Guid providerId, Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException(); public Task RemoveOrganization(Guid providerId, Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException();
} }