mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 08:02:49 -05:00
[Provider] Setup provider (#1378)
This commit is contained in:
@ -19,6 +19,14 @@
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Choose>
|
||||
<When Condition="!$(DefineConstants.Contains('OSS'))">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\bitwarden_license\src\CommCore\CommCore.csproj" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.6" />
|
||||
<PackageReference Include="NewRelic.Agent" Version="8.30.0" />
|
||||
|
@ -18,6 +18,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Enums.Provider;
|
||||
|
||||
namespace Bit.Api.Controllers
|
||||
{
|
||||
@ -30,6 +31,7 @@ namespace Bit.Api.Controllers
|
||||
private readonly IFolderRepository _folderRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IUserService _userService;
|
||||
@ -40,6 +42,7 @@ namespace Bit.Api.Controllers
|
||||
IFolderRepository folderRepository,
|
||||
IOrganizationService organizationService,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IPaymentService paymentService,
|
||||
ISsoUserRepository ssoUserRepository,
|
||||
IUserRepository userRepository,
|
||||
@ -50,6 +53,7 @@ namespace Bit.Api.Controllers
|
||||
_globalSettings = globalSettings;
|
||||
_organizationService = organizationService;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_paymentService = paymentService;
|
||||
_userRepository = userRepository;
|
||||
_userService = userService;
|
||||
@ -358,7 +362,9 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||
OrganizationUserStatusType.Confirmed);
|
||||
var response = new ProfileResponseModel(user, organizationUserDetails,
|
||||
var providerUserDetails = await _providerUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||
ProviderUserStatusType.Confirmed);
|
||||
var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
||||
await _userService.TwoFactorIsEnabledAsync(user));
|
||||
return response;
|
||||
}
|
||||
@ -384,7 +390,7 @@ namespace Bit.Api.Controllers
|
||||
}
|
||||
|
||||
await _userService.SaveUserAsync(model.ToUser(user));
|
||||
var response = new ProfileResponseModel(user, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
var response = new ProfileResponseModel(user, null, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -535,7 +541,7 @@ namespace Bit.Api.Controllers
|
||||
BillingAddressCountry = model.Country,
|
||||
BillingAddressPostalCode = model.PostalCode,
|
||||
});
|
||||
var profile = new ProfileResponseModel(user, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
var profile = new ProfileResponseModel(user, null, null, await _userService.TwoFactorIsEnabledAsync(user));
|
||||
return new PaymentResponseModel
|
||||
{
|
||||
UserProfile = profile,
|
||||
|
62
src/Api/Controllers/ProviderOrganizationsController.cs
Normal file
62
src/Api/Controllers/ProviderOrganizationsController.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Controllers
|
||||
{
|
||||
[Route("providers/{providerId:guid}/organizations")]
|
||||
[Authorize("Application")]
|
||||
public class ProviderOrganizationsController : Controller
|
||||
{
|
||||
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
private readonly IProviderService _providerService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public ProviderOrganizationsController(
|
||||
IProviderOrganizationRepository providerOrganizationRepository,
|
||||
IProviderService providerService,
|
||||
IUserService userService,
|
||||
ICurrentContext currentContext)
|
||||
{
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
_providerService = providerService;
|
||||
_userService = userService;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
public async Task<ListResponseModel<ProviderOrganizationOrganizationDetailsResponseModel>> Get(Guid providerId)
|
||||
{
|
||||
if (!_currentContext.AccessProviderOrganizations(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var providerOrganizations = await _providerOrganizationRepository.GetManyDetailsByProviderAsync(providerId);
|
||||
var responses = providerOrganizations.Select(o => new ProviderOrganizationOrganizationDetailsResponseModel(o));
|
||||
return new ListResponseModel<ProviderOrganizationOrganizationDetailsResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpPost("add")]
|
||||
public async Task Add(Guid providerId, [FromBody]ProviderOrganizationAddRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderOrganizations(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
|
||||
await _providerService.AddOrganization(providerId, model.OrganizationId, userId, model.Key);
|
||||
}
|
||||
}
|
||||
}
|
205
src/Api/Controllers/ProviderUsersController.cs
Normal file
205
src/Api/Controllers/ProviderUsersController.cs
Normal file
@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Bit.Core.Repositories;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Models.Business.Provider;
|
||||
|
||||
namespace Bit.Api.Controllers
|
||||
{
|
||||
[Route("providers/{providerId:guid}/users")]
|
||||
[Authorize("Application")]
|
||||
public class ProviderUsersController : Controller
|
||||
{
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IProviderService _providerService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public ProviderUsersController(
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IProviderService providerService,
|
||||
IUserService userService,
|
||||
ICurrentContext currentContext)
|
||||
{
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_providerService = providerService;
|
||||
_userService = userService;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<ProviderUserResponseModel> Get(Guid providerId, Guid id)
|
||||
{
|
||||
var providerUser = await _providerUserRepository.GetByIdAsync(id);
|
||||
if (providerUser == null || !_currentContext.ManageProviderUsers(providerUser.ProviderId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return new ProviderUserResponseModel(providerUser);
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
public async Task<ListResponseModel<ProviderUserUserDetailsResponseModel>> Get(Guid providerId)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var providerUsers = await _providerUserRepository.GetManyDetailsByProviderAsync(providerId);
|
||||
var responses = providerUsers.Select(o => new ProviderUserUserDetailsResponseModel(o));
|
||||
return new ListResponseModel<ProviderUserUserDetailsResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpPost("invite")]
|
||||
public async Task Invite(Guid providerId, [FromBody]ProviderUserInviteRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
await _providerService.InviteUserAsync(providerId, userId.Value, new ProviderUserInvite(model));
|
||||
}
|
||||
|
||||
[HttpPost("reinvite")]
|
||||
public async Task<ListResponseModel<ProviderUserBulkResponseModel>> BulkReinvite(Guid providerId, [FromBody]ProviderUserBulkRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
var result = await _providerService.ResendInvitesAsync(providerId, userId.Value, model.Ids);
|
||||
return new ListResponseModel<ProviderUserBulkResponseModel>(
|
||||
result.Select(t => new ProviderUserBulkResponseModel(t.Item1.Id, t.Item2)));
|
||||
}
|
||||
|
||||
[HttpPost("{id:guid}/reinvite")]
|
||||
public async Task Reinvite(Guid providerId, Guid id)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
await _providerService.ResendInvitesAsync(providerId, userId.Value, new [] { id });
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
await _providerService.AcceptUserAsync(id, user, model.Token);
|
||||
}
|
||||
|
||||
[HttpPost("{id:guid}/confirm")]
|
||||
public async Task Confirm(Guid providerId, Guid id, [FromBody]ProviderUserConfirmRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
await _providerService.ConfirmUsersAsync(providerId, new Dictionary<Guid, string> { [id] = model.Key }, userId.Value);
|
||||
}
|
||||
|
||||
[HttpPost("confirm")]
|
||||
public async Task<ListResponseModel<ProviderUserBulkResponseModel>> BulkConfirm(Guid providerId,
|
||||
[FromBody]ProviderUserBulkConfirmRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
var results = await _providerService.ConfirmUsersAsync(providerId, model.ToDictionary(), userId.Value);
|
||||
|
||||
return new ListResponseModel<ProviderUserBulkResponseModel>(results.Select(r =>
|
||||
new ProviderUserBulkResponseModel(r.Item1.Id, r.Item2)));
|
||||
}
|
||||
|
||||
[HttpPost("public-keys")]
|
||||
public async Task<ListResponseModel<ProviderUserPublicKeyResponseModel>> UserPublicKeys(Guid providerId, [FromBody]ProviderUserBulkRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var result = await _providerUserRepository.GetManyPublicKeysByProviderUserAsync(providerId, model.Ids);
|
||||
var responses = result.Select(r => new ProviderUserPublicKeyResponseModel(r.Id, r.PublicKey)).ToList();
|
||||
return new ListResponseModel<ProviderUserPublicKeyResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
[HttpPost("{id:guid}")]
|
||||
public async Task Put(Guid providerId, Guid id, [FromBody]ProviderUserUpdateRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var providerUser = await _providerUserRepository.GetByIdAsync(id);
|
||||
if (providerUser == null || providerUser.ProviderId != providerId)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
await _providerService.SaveUserAsync(model.ToProviderUser(providerUser), userId.Value);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
[HttpPost("{id:guid}/delete")]
|
||||
public async Task Delete(Guid providerId, Guid id)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
await _providerService.DeleteUsersAsync(providerId, new [] { id }, userId.Value);
|
||||
}
|
||||
|
||||
[HttpDelete("")]
|
||||
[HttpPost("delete")]
|
||||
public async Task<ListResponseModel<ProviderUserBulkResponseModel>> BulkDelete(Guid providerId, [FromBody]ProviderUserBulkRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ManageProviderUsers(providerId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User);
|
||||
var result = await _providerService.DeleteUsersAsync(providerId, model.Ids, userId.Value);
|
||||
return new ListResponseModel<ProviderUserBulkResponseModel>(result.Select(r =>
|
||||
new ProviderUserBulkResponseModel(r.Item1.Id, r.Item2)));
|
||||
}
|
||||
}
|
||||
}
|
70
src/Api/Controllers/ProvidersController.cs
Normal file
70
src/Api/Controllers/ProvidersController.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Controllers
|
||||
{
|
||||
[Route("providers")]
|
||||
[Authorize("Application")]
|
||||
public class ProvidersController : Controller
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IProviderService _providerService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public ProvidersController(IUserService userService, IProviderRepository providerRepository,
|
||||
IProviderService providerService, ICurrentContext currentContext)
|
||||
{
|
||||
_userService = userService;
|
||||
_providerRepository = providerRepository;
|
||||
_providerService = providerService;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<ProviderResponseModel> Get(Guid id)
|
||||
{
|
||||
if (!_currentContext.ProviderUser(id))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var provider = await _providerRepository.GetByIdAsync(id);
|
||||
if (provider == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return new ProviderResponseModel(provider);
|
||||
}
|
||||
|
||||
[HttpPost("{id:guid}/setup")]
|
||||
public async Task<ProviderResponseModel> Setup(Guid id, [FromBody]ProviderSetupRequestModel model)
|
||||
{
|
||||
if (!_currentContext.ProviderProviderAdmin(id))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var provider = await _providerRepository.GetByIdAsync(id);
|
||||
if (provider == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
|
||||
var response =
|
||||
await _providerService.CompleteSetupAsync(model.ToProvider(provider), userId, model.Token, model.Key);
|
||||
|
||||
return new ProviderResponseModel(response);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ using Bit.Core.Exceptions;
|
||||
using System.Linq;
|
||||
using Bit.Core.Models.Table;
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core.Enums.Provider;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
@ -25,6 +26,7 @@ namespace Bit.Api.Controllers
|
||||
private readonly ICollectionRepository _collectionRepository;
|
||||
private readonly ICollectionCipherRepository _collectionCipherRepository;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
@ -36,6 +38,7 @@ namespace Bit.Api.Controllers
|
||||
ICollectionRepository collectionRepository,
|
||||
ICollectionCipherRepository collectionCipherRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IPolicyRepository policyRepository,
|
||||
ISendRepository sendRepository,
|
||||
GlobalSettings globalSettings)
|
||||
@ -46,6 +49,7 @@ namespace Bit.Api.Controllers
|
||||
_collectionRepository = collectionRepository;
|
||||
_collectionCipherRepository = collectionCipherRepository;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_policyRepository = policyRepository;
|
||||
_sendRepository = sendRepository;
|
||||
_globalSettings = globalSettings;
|
||||
@ -62,6 +66,8 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||
OrganizationUserStatusType.Confirmed);
|
||||
var providerUserDetails = await _providerUserRepository.GetManyDetailsByUserAsync(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);
|
||||
@ -80,7 +86,8 @@ namespace Bit.Api.Controllers
|
||||
|
||||
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, organizationUserDetails,
|
||||
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends);
|
||||
providerUserDetails, folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains,
|
||||
policies, sends);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ using Microsoft.OpenApi.Models;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
#if !OSS
|
||||
using Bit.CommCore.Utilities;
|
||||
#endif
|
||||
|
||||
namespace Bit.Api
|
||||
{
|
||||
public class Startup
|
||||
@ -119,6 +123,12 @@ namespace Bit.Api
|
||||
services.AddDefaultServices(globalSettings);
|
||||
services.AddCoreLocalizationServices();
|
||||
|
||||
#if OSS
|
||||
services.AddOosServices();
|
||||
#else
|
||||
services.AddCommCoreServices();
|
||||
#endif
|
||||
|
||||
// MVC
|
||||
services.AddMvc(config =>
|
||||
{
|
||||
|
Reference in New Issue
Block a user