mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01:00
[Provider] Setup provider (#1378)
This commit is contained in:
parent
08f508f536
commit
43f7271147
2
SETUP.md
2
SETUP.md
@ -13,6 +13,8 @@ Each service is built and run separately. The Bitwarden clients can use differen
|
|||||||
|
|
||||||
This means that you don't need to run all services locally for a development environment. You can run only those services that you intend to modify, and use Bitwarden.com or a self-hosted instance for all other services required.
|
This means that you don't need to run all services locally for a development environment. You can run only those services that you intend to modify, and use Bitwarden.com or a self-hosted instance for all other services required.
|
||||||
|
|
||||||
|
By default some of the services depends on the Bitwarden licensed `CommCore`, however it can easily be disabled by including the `/p:DefineConstants="OSS"` as an argument to `dotnet`.
|
||||||
|
|
||||||
# Local Development Environment Setup
|
# Local Development Environment Setup
|
||||||
|
|
||||||
This guide will show you how to set up the Api, Identity and SQL projects for development. These are the minimum projects for any development work. You may need to set up additional projects depending on the changes you want to make.
|
This guide will show you how to set up the Api, Identity and SQL projects for development. These are the minimum projects for any development work. You may need to set up additional projects depending on the changes you want to make.
|
||||||
|
@ -61,7 +61,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Portal", "bitwarden_license
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sso", "bitwarden_license\src\Sso\Sso.csproj", "{4866AF64-6640-4C65-A662-A31E02FF9064}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sso", "bitwarden_license\src\Sso\Sso.csproj", "{4866AF64-6640-4C65-A662-A31E02FF9064}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Icons.Test", "test\Icons.Test\Icons.Test.csproj", "{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Icons.Test", "test\Icons.Test\Icons.Test.csproj", "{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommCore", "bitwarden_license\src\CommCore\CommCore.csproj", "{EDC0D688-D58C-4CE1-AA07-3606AC6874B8}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{3973D21B-A692-4B60-9B70-3631C057423A} = {3973D21B-A692-4B60-9B70-3631C057423A}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommCore.Test", "bitwarden_license\test\CmmCore.Test\CommCore.Test.csproj", "{0E99A21B-684B-4C59-9831-90F775CAB6F7}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test - Bitwarden License", "test - Bitwarden License", "{287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -143,6 +152,14 @@ Global
|
|||||||
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EDC0D688-D58C-4CE1-AA07-3606AC6874B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EDC0D688-D58C-4CE1-AA07-3606AC6874B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EDC0D688-D58C-4CE1-AA07-3606AC6874B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EDC0D688-D58C-4CE1-AA07-3606AC6874B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0E99A21B-684B-4C59-9831-90F775CAB6F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0E99A21B-684B-4C59-9831-90F775CAB6F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0E99A21B-684B-4C59-9831-90F775CAB6F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0E99A21B-684B-4C59-9831-90F775CAB6F7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -166,6 +183,8 @@ Global
|
|||||||
{BA852F18-852F-4154-973B-77D577B8CA04} = {4FDB6543-F68B-4202-9EA6-7FEA984D2D0A}
|
{BA852F18-852F-4154-973B-77D577B8CA04} = {4FDB6543-F68B-4202-9EA6-7FEA984D2D0A}
|
||||||
{4866AF64-6640-4C65-A662-A31E02FF9064} = {4FDB6543-F68B-4202-9EA6-7FEA984D2D0A}
|
{4866AF64-6640-4C65-A662-A31E02FF9064} = {4FDB6543-F68B-4202-9EA6-7FEA984D2D0A}
|
||||||
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F}
|
{C7BA2255-C1B1-4789-8BB9-C27540DA6FB8} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F}
|
||||||
|
{EDC0D688-D58C-4CE1-AA07-3606AC6874B8} = {4FDB6543-F68B-4202-9EA6-7FEA984D2D0A}
|
||||||
|
{0E99A21B-684B-4C59-9831-90F775CAB6F7} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {E01CBF68-2E20-425F-9EDB-E0A6510CA92F}
|
SolutionGuid = {E01CBF68-2E20-425F-9EDB-E0A6510CA92F}
|
||||||
|
11
bitwarden_license/src/CommCore/CommCore.csproj
Normal file
11
bitwarden_license/src/CommCore/CommCore.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\src\Core\Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
@ -10,11 +9,12 @@ using Bit.Core.Models.Business.Provider;
|
|||||||
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;
|
||||||
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.CommCore.Services
|
||||||
{
|
{
|
||||||
public class ProviderService : IProviderService
|
public class ProviderService : IProviderService
|
||||||
{
|
{
|
||||||
@ -24,15 +24,18 @@ namespace Bit.Core.Services
|
|||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IProviderRepository _providerRepository;
|
private readonly IProviderRepository _providerRepository;
|
||||||
private readonly IProviderUserRepository _providerUserRepository;
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
|
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
public ProviderService(IProviderRepository providerRepository, IProviderUserRepository providerUserRepository,
|
public ProviderService(IProviderRepository providerRepository, IProviderUserRepository providerUserRepository,
|
||||||
IUserRepository userRepository, IUserService userService, IMailService mailService,
|
IProviderOrganizationRepository providerOrganizationRepository, IUserRepository userRepository,
|
||||||
IDataProtectionProvider dataProtectionProvider, IEventService eventService, GlobalSettings globalSettings)
|
IUserService userService, IMailService mailService, IDataProtectionProvider dataProtectionProvider,
|
||||||
|
IEventService eventService, GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
_providerRepository = providerRepository;
|
_providerRepository = providerRepository;
|
||||||
_providerUserRepository = providerUserRepository;
|
_providerUserRepository = providerUserRepository;
|
||||||
|
_providerOrganizationRepository = providerOrganizationRepository;
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_mailService = mailService;
|
_mailService = mailService;
|
||||||
@ -56,11 +59,20 @@ namespace Bit.Core.Services
|
|||||||
};
|
};
|
||||||
await _providerRepository.CreateAsync(provider);
|
await _providerRepository.CreateAsync(provider);
|
||||||
|
|
||||||
|
var providerUser = new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = owner.Id,
|
||||||
|
Type = ProviderUserType.ProviderAdmin,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
};
|
||||||
|
await _providerUserRepository.CreateAsync(providerUser);
|
||||||
|
|
||||||
var token = _dataProtector.Protect($"ProviderSetupInvite {provider.Id} {owner.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");
|
var token = _dataProtector.Protect($"ProviderSetupInvite {provider.Id} {owner.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");
|
||||||
await _mailService.SendProviderSetupInviteEmailAsync(provider, token, owner.Email);
|
await _mailService.SendProviderSetupInviteEmailAsync(provider, token, owner.Email);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key)
|
public async Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key)
|
||||||
{
|
{
|
||||||
var owner = await _userService.GetUserByIdAsync(ownerUserId);
|
var owner = await _userService.GetUserByIdAsync(ownerUserId);
|
||||||
if (owner == null)
|
if (owner == null)
|
||||||
@ -68,23 +80,29 @@ namespace Bit.Core.Services
|
|||||||
throw new BadRequestException("Invalid owner.");
|
throw new BadRequestException("Invalid owner.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (provider.Status != ProviderStatusType.Pending)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Provider is already setup.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!CoreHelpers.TokenIsValid("ProviderSetupInvite", _dataProtector, token, owner.Email, provider.Id, _globalSettings))
|
if (!CoreHelpers.TokenIsValid("ProviderSetupInvite", _dataProtector, token, owner.Email, provider.Id, _globalSettings))
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Invalid token.");
|
throw new BadRequestException("Invalid token.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var providerUser = await _providerUserRepository.GetByProviderUserAsync(provider.Id, ownerUserId);
|
||||||
|
if (!(providerUser is {Type: ProviderUserType.ProviderAdmin}))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid owner.");
|
||||||
|
}
|
||||||
|
|
||||||
|
provider.Status = ProviderStatusType.Created;
|
||||||
await _providerRepository.UpsertAsync(provider);
|
await _providerRepository.UpsertAsync(provider);
|
||||||
|
|
||||||
var providerUser = new ProviderUser
|
providerUser.Key = key;
|
||||||
{
|
await _providerUserRepository.ReplaceAsync(providerUser);
|
||||||
ProviderId = provider.Id,
|
|
||||||
UserId = owner.Id,
|
|
||||||
Key = key,
|
|
||||||
Status = ProviderUserStatusType.Confirmed,
|
|
||||||
Type = ProviderUserType.ProviderAdmin,
|
|
||||||
};
|
|
||||||
|
|
||||||
await _providerUserRepository.CreateAsync(providerUser);
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateAsync(Provider provider, bool updateBilling = false)
|
public async Task UpdateAsync(Provider provider, bool updateBilling = false)
|
||||||
@ -129,14 +147,6 @@ namespace Bit.Core.Services
|
|||||||
RevisionDate = DateTime.UtcNow,
|
RevisionDate = DateTime.UtcNow,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (invite.Permissions != null)
|
|
||||||
{
|
|
||||||
providerUser.Permissions = JsonSerializer.Serialize(invite.Permissions, new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await _providerUserRepository.CreateAsync(providerUser);
|
await _providerUserRepository.CreateAsync(providerUser);
|
||||||
|
|
||||||
await SendInviteAsync(providerUser, provider);
|
await SendInviteAsync(providerUser, provider);
|
||||||
@ -322,8 +332,17 @@ namespace Bit.Core.Services
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement this
|
public async Task AddOrganization(Guid providerId, Guid organizationId, Guid addingUserId, string key)
|
||||||
public Task AddOrganization(Guid providerId, Guid organizationId, Guid addingUserId, string key) => throw new NotImplementedException();
|
{
|
||||||
|
var providerOrganization = new ProviderOrganization
|
||||||
|
{
|
||||||
|
ProviderId = providerId,
|
||||||
|
OrganizationId = organizationId,
|
||||||
|
Key = key,
|
||||||
|
};
|
||||||
|
|
||||||
|
await _providerOrganizationRepository.CreateAsync(providerOrganization);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Implement this
|
// TODO: Implement this
|
||||||
public Task RemoveOrganization(Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException();
|
public Task RemoveOrganization(Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException();
|
@ -0,0 +1,14 @@
|
|||||||
|
using Bit.CommCore.Services;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Bit.CommCore.Utilities
|
||||||
|
{
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
public static void AddCommCoreServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IProviderService, ProviderService>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ using AutoFixture;
|
|||||||
using AutoFixture.Xunit2;
|
using AutoFixture.Xunit2;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
|
|
||||||
namespace Bit.Core.Test.AutoFixture.ProviderUserFixtures
|
namespace Bit.CommCore.Test.AutoFixture.ProviderUserFixtures
|
||||||
{
|
{
|
||||||
internal class ProviderUser : ICustomization
|
internal class ProviderUser : ICustomization
|
||||||
{
|
{
|
27
bitwarden_license/test/CmmCore.Test/CommCore.Test.csproj
Normal file
27
bitwarden_license/test/CmmCore.Test/CommCore.Test.csproj
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\CommCore\CommCore.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\test\Core.Test\Core.Test.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -2,6 +2,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.CommCore.Test.AutoFixture.ProviderUserFixtures;
|
||||||
|
using Bit.CommCore.Services;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
@ -12,14 +14,13 @@ using Bit.Core.Repositories;
|
|||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Test.AutoFixture;
|
using Bit.Core.Test.AutoFixture;
|
||||||
using Bit.Core.Test.AutoFixture.Attributes;
|
using Bit.Core.Test.AutoFixture.Attributes;
|
||||||
using Bit.Core.Test.AutoFixture.ProviderUserFixtures;
|
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using ProviderUser = Bit.Core.Models.Table.Provider.ProviderUser;
|
using ProviderUser = Bit.Core.Models.Table.Provider.ProviderUser;
|
||||||
|
|
||||||
namespace Bit.Core.Test.Services
|
namespace Bit.CommCore.Test.Services
|
||||||
{
|
{
|
||||||
public class ProviderServiceTests
|
public class ProviderServiceTests
|
||||||
{
|
{
|
||||||
@ -64,12 +65,18 @@ namespace Bit.Core.Test.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||||
public async Task CompleteSetupAsync_Success(User user, Provider provider,
|
public async Task CompleteSetupAsync_Success(User user, Provider provider, string key,
|
||||||
|
[ProviderUser(ProviderUserStatusType.Confirmed, ProviderUserType.ProviderAdmin)]ProviderUser providerUser,
|
||||||
SutProvider<ProviderService> sutProvider)
|
SutProvider<ProviderService> sutProvider)
|
||||||
{
|
{
|
||||||
|
providerUser.ProviderId = provider.Id;
|
||||||
|
providerUser.UserId = user.Id;
|
||||||
var userService = sutProvider.GetDependency<IUserService>();
|
var userService = sutProvider.GetDependency<IUserService>();
|
||||||
userService.GetUserByIdAsync(user.Id).Returns(user);
|
userService.GetUserByIdAsync(user.Id).Returns(user);
|
||||||
|
|
||||||
|
var providerUserRepository = sutProvider.GetDependency<IProviderUserRepository>();
|
||||||
|
providerUserRepository.GetByProviderUserAsync(provider.Id, user.Id).Returns(providerUser);
|
||||||
|
|
||||||
var dataProtectionProvider = DataProtectionProvider.Create("ApplicationName");
|
var dataProtectionProvider = DataProtectionProvider.Create("ApplicationName");
|
||||||
var protector = dataProtectionProvider.CreateProtector("ProviderServiceDataProtector");
|
var protector = dataProtectionProvider.CreateProtector("ProviderServiceDataProtector");
|
||||||
sutProvider.GetDependency<IDataProtectionProvider>().CreateProtector("ProviderServiceDataProtector")
|
sutProvider.GetDependency<IDataProtectionProvider>().CreateProtector("ProviderServiceDataProtector")
|
||||||
@ -78,11 +85,11 @@ namespace Bit.Core.Test.Services
|
|||||||
|
|
||||||
var token = protector.Protect($"ProviderSetupInvite {provider.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");
|
var token = protector.Protect($"ProviderSetupInvite {provider.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");
|
||||||
|
|
||||||
await sutProvider.Sut.CompleteSetupAsync(provider, user.Id, token, default);
|
await sutProvider.Sut.CompleteSetupAsync(provider, user.Id, token, key);
|
||||||
|
|
||||||
await sutProvider.GetDependency<IProviderRepository>().Received().UpsertAsync(provider);
|
await sutProvider.GetDependency<IProviderRepository>().Received().UpsertAsync(provider);
|
||||||
await sutProvider.GetDependency<IProviderUserRepository>().Received()
|
await sutProvider.GetDependency<IProviderUserRepository>().Received()
|
||||||
.CreateAsync(Arg.Is<ProviderUser>(pu => pu.UserId == user.Id && pu.ProviderId == provider.Id));
|
.ReplaceAsync(Arg.Is<ProviderUser>(pu => pu.UserId == user.Id && pu.ProviderId == provider.Id && pu.Key == key));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
@ -9,6 +9,14 @@
|
|||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Choose>
|
||||||
|
<When Condition="!$(DefineConstants.Contains('OSS'))">
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\bitwarden_license\src\CommCore\CommCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.3" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -85,7 +85,7 @@ namespace Bit.Admin.Controllers
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
var users = await _providerUserRepository.GetManyByProviderAsync(id);
|
var users = await _providerUserRepository.GetManyDetailsByProviderAsync(id);
|
||||||
return View(new ProviderViewModel(provider, users));
|
return View(new ProviderViewModel(provider, users));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ namespace Bit.Admin.Controllers
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
var users = await _providerUserRepository.GetManyByProviderAsync(id);
|
var users = await _providerUserRepository.GetManyDetailsByProviderAsync(id);
|
||||||
return View(new ProviderEditModel(provider, users));
|
return View(new ProviderEditModel(provider, users));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
namespace Bit.Admin.Models
|
namespace Bit.Admin.Models
|
||||||
{
|
{
|
||||||
public class ProviderEditModel : ProviderViewModel
|
public class ProviderEditModel : ProviderViewModel
|
||||||
{
|
{
|
||||||
public ProviderEditModel(Provider provider, IEnumerable<ProviderUser> providerUsers)
|
public ProviderEditModel(Provider provider, IEnumerable<ProviderUserUserDetails> providerUsers)
|
||||||
: base(provider, providerUsers)
|
: base(provider, providerUsers)
|
||||||
{
|
{
|
||||||
Name = provider.Name;
|
Name = provider.Name;
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
namespace Bit.Admin.Models
|
namespace Bit.Admin.Models
|
||||||
{
|
{
|
||||||
public class ProviderViewModel
|
public class ProviderViewModel
|
||||||
{
|
{
|
||||||
public ProviderViewModel(Provider provider, IEnumerable<ProviderUser> providerUsers)
|
public ProviderViewModel(Provider provider, IEnumerable<ProviderUserUserDetails> providerUsers)
|
||||||
{
|
{
|
||||||
Provider = provider;
|
Provider = provider;
|
||||||
UserCount = providerUsers.Count();
|
UserCount = providerUsers.Count();
|
||||||
|
@ -13,6 +13,10 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
|
|
||||||
|
#if !OSS
|
||||||
|
using Bit.CommCore.Utilities;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Bit.Admin
|
namespace Bit.Admin
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
@ -66,6 +70,12 @@ namespace Bit.Admin
|
|||||||
services.AddBaseServices();
|
services.AddBaseServices();
|
||||||
services.AddDefaultServices(globalSettings);
|
services.AddDefaultServices(globalSettings);
|
||||||
|
|
||||||
|
#if OSS
|
||||||
|
services.AddOosServices();
|
||||||
|
#else
|
||||||
|
services.AddCommCoreServices();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Mvc
|
// Mvc
|
||||||
services.AddMvc(config =>
|
services.AddMvc(config =>
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,14 @@
|
|||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Choose>
|
||||||
|
<When Condition="!$(DefineConstants.Contains('OSS'))">
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\bitwarden_license\src\CommCore\CommCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.6" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.6" />
|
||||||
<PackageReference Include="NewRelic.Agent" Version="8.30.0" />
|
<PackageReference Include="NewRelic.Agent" Version="8.30.0" />
|
||||||
|
@ -18,6 +18,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers
|
namespace Bit.Api.Controllers
|
||||||
{
|
{
|
||||||
@ -30,6 +31,7 @@ namespace Bit.Api.Controllers
|
|||||||
private readonly IFolderRepository _folderRepository;
|
private readonly IFolderRepository _folderRepository;
|
||||||
private readonly IOrganizationService _organizationService;
|
private readonly IOrganizationService _organizationService;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
private readonly IPaymentService _paymentService;
|
private readonly IPaymentService _paymentService;
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
@ -40,6 +42,7 @@ namespace Bit.Api.Controllers
|
|||||||
IFolderRepository folderRepository,
|
IFolderRepository folderRepository,
|
||||||
IOrganizationService organizationService,
|
IOrganizationService organizationService,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IProviderUserRepository providerUserRepository,
|
||||||
IPaymentService paymentService,
|
IPaymentService paymentService,
|
||||||
ISsoUserRepository ssoUserRepository,
|
ISsoUserRepository ssoUserRepository,
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
@ -50,6 +53,7 @@ namespace Bit.Api.Controllers
|
|||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_organizationService = organizationService;
|
_organizationService = organizationService;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_providerUserRepository = providerUserRepository;
|
||||||
_paymentService = paymentService;
|
_paymentService = paymentService;
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
@ -358,7 +362,9 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id,
|
var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||||
OrganizationUserStatusType.Confirmed);
|
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));
|
await _userService.TwoFactorIsEnabledAsync(user));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -384,7 +390,7 @@ namespace Bit.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _userService.SaveUserAsync(model.ToUser(user));
|
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;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,7 +541,7 @@ namespace Bit.Api.Controllers
|
|||||||
BillingAddressCountry = model.Country,
|
BillingAddressCountry = model.Country,
|
||||||
BillingAddressPostalCode = model.PostalCode,
|
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
|
return new PaymentResponseModel
|
||||||
{
|
{
|
||||||
UserProfile = profile,
|
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 System.Linq;
|
||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ namespace Bit.Api.Controllers
|
|||||||
private readonly ICollectionRepository _collectionRepository;
|
private readonly ICollectionRepository _collectionRepository;
|
||||||
private readonly ICollectionCipherRepository _collectionCipherRepository;
|
private readonly ICollectionCipherRepository _collectionCipherRepository;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly ISendRepository _sendRepository;
|
private readonly ISendRepository _sendRepository;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
@ -36,6 +38,7 @@ namespace Bit.Api.Controllers
|
|||||||
ICollectionRepository collectionRepository,
|
ICollectionRepository collectionRepository,
|
||||||
ICollectionCipherRepository collectionCipherRepository,
|
ICollectionCipherRepository collectionCipherRepository,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IProviderUserRepository providerUserRepository,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
ISendRepository sendRepository,
|
ISendRepository sendRepository,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
@ -46,6 +49,7 @@ namespace Bit.Api.Controllers
|
|||||||
_collectionRepository = collectionRepository;
|
_collectionRepository = collectionRepository;
|
||||||
_collectionCipherRepository = collectionCipherRepository;
|
_collectionCipherRepository = collectionCipherRepository;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_providerUserRepository = providerUserRepository;
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_sendRepository = sendRepository;
|
_sendRepository = sendRepository;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
@ -62,6 +66,8 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id,
|
var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||||
OrganizationUserStatusType.Confirmed);
|
OrganizationUserStatusType.Confirmed);
|
||||||
|
var providerUserDetails = await _providerUserRepository.GetManyDetailsByUserAsync(user.Id,
|
||||||
|
ProviderUserStatusType.Confirmed);
|
||||||
var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled);
|
var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled);
|
||||||
var folders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
var folders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
||||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, hasEnabledOrgs);
|
var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, hasEnabledOrgs);
|
||||||
@ -80,7 +86,8 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||||
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, organizationUserDetails,
|
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;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ using Microsoft.OpenApi.Models;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
#if !OSS
|
||||||
|
using Bit.CommCore.Utilities;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Bit.Api
|
namespace Bit.Api
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
@ -119,6 +123,12 @@ namespace Bit.Api
|
|||||||
services.AddDefaultServices(globalSettings);
|
services.AddDefaultServices(globalSettings);
|
||||||
services.AddCoreLocalizationServices();
|
services.AddCoreLocalizationServices();
|
||||||
|
|
||||||
|
#if OSS
|
||||||
|
services.AddOosServices();
|
||||||
|
#else
|
||||||
|
services.AddCommCoreServices();
|
||||||
|
#endif
|
||||||
|
|
||||||
// MVC
|
// MVC
|
||||||
services.AddMvc(config =>
|
services.AddMvc(config =>
|
||||||
{
|
{
|
||||||
|
26
src/Core/Context/CurrentContentProvider.cs
Normal file
26
src/Core/Context/CurrentContentProvider.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.Context
|
||||||
|
{
|
||||||
|
public class CurrentContentProvider
|
||||||
|
{
|
||||||
|
public CurrentContentProvider() { }
|
||||||
|
|
||||||
|
public CurrentContentProvider(ProviderUser providerUser)
|
||||||
|
{
|
||||||
|
Id = providerUser.ProviderId;
|
||||||
|
Type = providerUser.Type;
|
||||||
|
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(providerUser.Permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public ProviderUserType Type { get; set; }
|
||||||
|
public Permissions Permissions { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
@ -25,6 +26,7 @@ namespace Bit.Core.Context
|
|||||||
public virtual DeviceType? DeviceType { get; set; }
|
public virtual DeviceType? DeviceType { get; set; }
|
||||||
public virtual string IpAddress { get; set; }
|
public virtual string IpAddress { get; set; }
|
||||||
public virtual List<CurrentContentOrganization> Organizations { get; set; }
|
public virtual List<CurrentContentOrganization> Organizations { get; set; }
|
||||||
|
public virtual List<CurrentContentProvider> Providers { get; set; }
|
||||||
public virtual Guid? InstallationId { get; set; }
|
public virtual Guid? InstallationId { get; set; }
|
||||||
public virtual Guid? OrganizationId { get; set; }
|
public virtual Guid? OrganizationId { get; set; }
|
||||||
public virtual bool CloudflareWorkerProxied { get; set; }
|
public virtual bool CloudflareWorkerProxied { get; set; }
|
||||||
@ -127,10 +129,19 @@ namespace Bit.Core.Context
|
|||||||
|
|
||||||
DeviceIdentifier = GetClaimValue(claimsDict, "device");
|
DeviceIdentifier = GetClaimValue(claimsDict, "device");
|
||||||
|
|
||||||
Organizations = new List<CurrentContentOrganization>();
|
Organizations = GetOrganizations(claimsDict, orgApi);
|
||||||
|
|
||||||
|
Providers = GetProviders(claimsDict);
|
||||||
|
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CurrentContentOrganization> GetOrganizations(Dictionary<string, IEnumerable<Claim>> claimsDict, bool orgApi)
|
||||||
|
{
|
||||||
|
var organizations = new List<CurrentContentOrganization>();
|
||||||
if (claimsDict.ContainsKey("orgowner"))
|
if (claimsDict.ContainsKey("orgowner"))
|
||||||
{
|
{
|
||||||
Organizations.AddRange(claimsDict["orgowner"].Select(c =>
|
organizations.AddRange(claimsDict["orgowner"].Select(c =>
|
||||||
new CurrentContentOrganization
|
new CurrentContentOrganization
|
||||||
{
|
{
|
||||||
Id = new Guid(c.Value),
|
Id = new Guid(c.Value),
|
||||||
@ -139,7 +150,7 @@ namespace Bit.Core.Context
|
|||||||
}
|
}
|
||||||
else if (orgApi && OrganizationId.HasValue)
|
else if (orgApi && OrganizationId.HasValue)
|
||||||
{
|
{
|
||||||
Organizations.Add(new CurrentContentOrganization
|
organizations.Add(new CurrentContentOrganization
|
||||||
{
|
{
|
||||||
Id = OrganizationId.Value,
|
Id = OrganizationId.Value,
|
||||||
Type = OrganizationUserType.Owner
|
Type = OrganizationUserType.Owner
|
||||||
@ -148,7 +159,7 @@ namespace Bit.Core.Context
|
|||||||
|
|
||||||
if (claimsDict.ContainsKey("orgadmin"))
|
if (claimsDict.ContainsKey("orgadmin"))
|
||||||
{
|
{
|
||||||
Organizations.AddRange(claimsDict["orgadmin"].Select(c =>
|
organizations.AddRange(claimsDict["orgadmin"].Select(c =>
|
||||||
new CurrentContentOrganization
|
new CurrentContentOrganization
|
||||||
{
|
{
|
||||||
Id = new Guid(c.Value),
|
Id = new Guid(c.Value),
|
||||||
@ -158,7 +169,7 @@ namespace Bit.Core.Context
|
|||||||
|
|
||||||
if (claimsDict.ContainsKey("orguser"))
|
if (claimsDict.ContainsKey("orguser"))
|
||||||
{
|
{
|
||||||
Organizations.AddRange(claimsDict["orguser"].Select(c =>
|
organizations.AddRange(claimsDict["orguser"].Select(c =>
|
||||||
new CurrentContentOrganization
|
new CurrentContentOrganization
|
||||||
{
|
{
|
||||||
Id = new Guid(c.Value),
|
Id = new Guid(c.Value),
|
||||||
@ -168,7 +179,7 @@ namespace Bit.Core.Context
|
|||||||
|
|
||||||
if (claimsDict.ContainsKey("orgmanager"))
|
if (claimsDict.ContainsKey("orgmanager"))
|
||||||
{
|
{
|
||||||
Organizations.AddRange(claimsDict["orgmanager"].Select(c =>
|
organizations.AddRange(claimsDict["orgmanager"].Select(c =>
|
||||||
new CurrentContentOrganization
|
new CurrentContentOrganization
|
||||||
{
|
{
|
||||||
Id = new Guid(c.Value),
|
Id = new Guid(c.Value),
|
||||||
@ -178,7 +189,7 @@ namespace Bit.Core.Context
|
|||||||
|
|
||||||
if (claimsDict.ContainsKey("orgcustom"))
|
if (claimsDict.ContainsKey("orgcustom"))
|
||||||
{
|
{
|
||||||
Organizations.AddRange(claimsDict["orgcustom"].Select(c =>
|
organizations.AddRange(claimsDict["orgcustom"].Select(c =>
|
||||||
new CurrentContentOrganization
|
new CurrentContentOrganization
|
||||||
{
|
{
|
||||||
Id = new Guid(c.Value),
|
Id = new Guid(c.Value),
|
||||||
@ -187,7 +198,33 @@ namespace Bit.Core.Context
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(0);
|
return organizations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CurrentContentProvider> GetProviders(Dictionary<string, IEnumerable<Claim>> claimsDict)
|
||||||
|
{
|
||||||
|
var providers = new List<CurrentContentProvider>();
|
||||||
|
if (claimsDict.ContainsKey("providerprovideradmin"))
|
||||||
|
{
|
||||||
|
providers.AddRange(claimsDict["providerprovideradmin"].Select(c =>
|
||||||
|
new CurrentContentProvider
|
||||||
|
{
|
||||||
|
Id = new Guid(c.Value),
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (claimsDict.ContainsKey("providerserviceuser"))
|
||||||
|
{
|
||||||
|
providers.AddRange(claimsDict["providerserviceuser"].Select(c =>
|
||||||
|
new CurrentContentProvider
|
||||||
|
{
|
||||||
|
Id = new Guid(c.Value),
|
||||||
|
Type = ProviderUserType.ServiceUser
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OrganizationUser(Guid orgId)
|
public bool OrganizationUser(Guid orgId)
|
||||||
@ -284,6 +321,31 @@ namespace Bit.Core.Context
|
|||||||
&& (o.Permissions?.ManageResetPassword ?? false)) ?? false);
|
&& (o.Permissions?.ManageResetPassword ?? false)) ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ProviderProviderAdmin(Guid providerId)
|
||||||
|
{
|
||||||
|
return Providers?.Any(o => o.Id == providerId && o.Type == ProviderUserType.ProviderAdmin) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ManageProviderUsers(Guid providerId)
|
||||||
|
{
|
||||||
|
return ProviderProviderAdmin(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AccessProviderOrganizations(Guid providerId)
|
||||||
|
{
|
||||||
|
return ProviderUser(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ManageProviderOrganizations(Guid providerId)
|
||||||
|
{
|
||||||
|
return ProviderProviderAdmin(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ProviderUser(Guid providerId)
|
||||||
|
{
|
||||||
|
return Providers?.Any(o => o.Id == providerId) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ICollection<CurrentContentOrganization>> OrganizationMembershipAsync(
|
public async Task<ICollection<CurrentContentOrganization>> OrganizationMembershipAsync(
|
||||||
IOrganizationUserRepository organizationUserRepository, Guid userId)
|
IOrganizationUserRepository organizationUserRepository, Guid userId)
|
||||||
{
|
{
|
||||||
@ -296,6 +358,18 @@ namespace Bit.Core.Context
|
|||||||
return Organizations;
|
return Organizations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<CurrentContentProvider>> ProviderMembershipAsync(
|
||||||
|
IProviderUserRepository providerUserRepository, Guid userId)
|
||||||
|
{
|
||||||
|
if (Providers == null)
|
||||||
|
{
|
||||||
|
var userProviders = await providerUserRepository.GetManyByUserAsync(userId);
|
||||||
|
Providers = userProviders.Where(ou => ou.Status == ProviderUserStatusType.Confirmed)
|
||||||
|
.Select(ou => new CurrentContentProvider(ou)).ToList();
|
||||||
|
}
|
||||||
|
return Providers;
|
||||||
|
}
|
||||||
|
|
||||||
private string GetClaimValue(Dictionary<string, IEnumerable<Claim>> claims, string type)
|
private string GetClaimValue(Dictionary<string, IEnumerable<Claim>> claims, string type)
|
||||||
{
|
{
|
||||||
if (!claims.ContainsKey(type))
|
if (!claims.ContainsKey(type))
|
||||||
|
@ -47,8 +47,16 @@ namespace Bit.Core.Context
|
|||||||
bool ManageSso(Guid orgId);
|
bool ManageSso(Guid orgId);
|
||||||
bool ManageUsers(Guid orgId);
|
bool ManageUsers(Guid orgId);
|
||||||
bool ManageResetPassword(Guid orgId);
|
bool ManageResetPassword(Guid orgId);
|
||||||
|
bool ProviderProviderAdmin(Guid providerId);
|
||||||
|
bool ProviderUser(Guid providerId);
|
||||||
|
bool ManageProviderUsers(Guid providerId);
|
||||||
|
bool AccessProviderOrganizations(Guid providerId);
|
||||||
|
bool ManageProviderOrganizations(Guid providerId);
|
||||||
|
|
||||||
Task<ICollection<CurrentContentOrganization>> OrganizationMembershipAsync(
|
Task<ICollection<CurrentContentOrganization>> OrganizationMembershipAsync(
|
||||||
IOrganizationUserRepository organizationUserRepository, Guid userId);
|
IOrganizationUserRepository organizationUserRepository, Guid userId);
|
||||||
|
|
||||||
|
Task<ICollection<CurrentContentProvider>> ProviderMembershipAsync(
|
||||||
|
IProviderUserRepository providerUserRepository, Guid userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,14 @@ namespace Bit.Core.IdentityServer
|
|||||||
"orgmanager",
|
"orgmanager",
|
||||||
"orguser",
|
"orguser",
|
||||||
"orgcustom",
|
"orgcustom",
|
||||||
|
"providerprovideradmin",
|
||||||
|
"providerserviceuser",
|
||||||
}),
|
}),
|
||||||
new ApiResource("internal", new string[] { JwtClaimTypes.Subject }),
|
new ApiResource("internal", new string[] { JwtClaimTypes.Subject }),
|
||||||
new ApiResource("api.push", new string[] { JwtClaimTypes.Subject }),
|
new ApiResource("api.push", new string[] { JwtClaimTypes.Subject }),
|
||||||
new ApiResource("api.licensing", new string[] { JwtClaimTypes.Subject }),
|
new ApiResource("api.licensing", new string[] { JwtClaimTypes.Subject }),
|
||||||
new ApiResource("api.organization", new string[] { JwtClaimTypes.Subject })
|
new ApiResource("api.organization", new string[] { JwtClaimTypes.Subject }),
|
||||||
|
new ApiResource("api.provider", new string[] { JwtClaimTypes.Subject }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ namespace Bit.Core.IdentityServer
|
|||||||
private readonly ILicensingService _licensingService;
|
private readonly ILicensingService _licensingService;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
|
|
||||||
public ClientStore(
|
public ClientStore(
|
||||||
IInstallationRepository installationRepository,
|
IInstallationRepository installationRepository,
|
||||||
@ -34,7 +35,8 @@ namespace Bit.Core.IdentityServer
|
|||||||
StaticClientStore staticClientStore,
|
StaticClientStore staticClientStore,
|
||||||
ILicensingService licensingService,
|
ILicensingService licensingService,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
IOrganizationUserRepository organizationUserRepository)
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
{
|
{
|
||||||
_installationRepository = installationRepository;
|
_installationRepository = installationRepository;
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
@ -44,6 +46,7 @@ namespace Bit.Core.IdentityServer
|
|||||||
_licensingService = licensingService;
|
_licensingService = licensingService;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_providerUserRepository = providerUserRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Client> FindClientByIdAsync(string clientId)
|
public async Task<Client> FindClientByIdAsync(string clientId)
|
||||||
@ -138,8 +141,9 @@ namespace Bit.Core.IdentityServer
|
|||||||
new ClientClaim(JwtClaimTypes.AuthenticationMethod, "Application", "external")
|
new ClientClaim(JwtClaimTypes.AuthenticationMethod, "Application", "external")
|
||||||
};
|
};
|
||||||
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id);
|
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id);
|
||||||
|
var providers = await _currentContext.ProviderMembershipAsync(_providerUserRepository, user.Id);
|
||||||
var isPremium = await _licensingService.ValidateUserPremiumAsync(user);
|
var isPremium = await _licensingService.ValidateUserPremiumAsync(user);
|
||||||
foreach (var claim in CoreHelpers.BuildIdentityClaims(user, orgs, isPremium))
|
foreach (var claim in CoreHelpers.BuildIdentityClaims(user, orgs, providers, isPremium))
|
||||||
{
|
{
|
||||||
var upperValue = claim.Value.ToUpperInvariant();
|
var upperValue = claim.Value.ToUpperInvariant();
|
||||||
var isBool = upperValue == "TRUE" || upperValue == "FALSE";
|
var isBool = upperValue == "TRUE" || upperValue == "FALSE";
|
||||||
|
@ -18,17 +18,20 @@ namespace Bit.Core.IdentityServer
|
|||||||
{
|
{
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
private readonly ILicensingService _licensingService;
|
private readonly ILicensingService _licensingService;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
|
|
||||||
public ProfileService(
|
public ProfileService(
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IProviderUserRepository providerUserRepository,
|
||||||
ILicensingService licensingService,
|
ILicensingService licensingService,
|
||||||
ICurrentContext currentContext)
|
ICurrentContext currentContext)
|
||||||
{
|
{
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_providerUserRepository = providerUserRepository;
|
||||||
_licensingService = licensingService;
|
_licensingService = licensingService;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
}
|
}
|
||||||
@ -43,7 +46,8 @@ namespace Bit.Core.IdentityServer
|
|||||||
{
|
{
|
||||||
var isPremium = await _licensingService.ValidateUserPremiumAsync(user);
|
var isPremium = await _licensingService.ValidateUserPremiumAsync(user);
|
||||||
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id);
|
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id);
|
||||||
foreach (var claim in CoreHelpers.BuildIdentityClaims(user, orgs, isPremium))
|
var providers = await _currentContext.ProviderMembershipAsync(_providerUserRepository, user.Id);
|
||||||
|
foreach (var claim in CoreHelpers.BuildIdentityClaims(user, orgs, providers, isPremium))
|
||||||
{
|
{
|
||||||
var upperValue = claim.Value.ToUpperInvariant();
|
var upperValue = claim.Value.ToUpperInvariant();
|
||||||
var isBool = upperValue == "TRUE" || upperValue == "FALSE";
|
var isBool = upperValue == "TRUE" || upperValue == "FALSE";
|
||||||
|
@ -5,47 +5,20 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Api
|
namespace Bit.Core.Models.Api
|
||||||
{
|
{
|
||||||
public class OrganizationUserInviteRequestModel : IValidatableObject
|
public class OrganizationUserInviteRequestModel
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
|
[EmailAddressList]
|
||||||
public IEnumerable<string> Emails { get; set; }
|
public IEnumerable<string> Emails { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public Enums.OrganizationUserType? Type { get; set; }
|
public Enums.OrganizationUserType? Type { get; set; }
|
||||||
public bool AccessAll { get; set; }
|
public bool AccessAll { get; set; }
|
||||||
public Permissions Permissions { get; set; }
|
public Permissions Permissions { get; set; }
|
||||||
public IEnumerable<SelectionReadOnlyRequestModel> Collections { get; set; }
|
public IEnumerable<SelectionReadOnlyRequestModel> Collections { get; set; }
|
||||||
|
|
||||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
|
||||||
{
|
|
||||||
if (!Emails.Any())
|
|
||||||
{
|
|
||||||
yield return new ValidationResult("An email is required.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Emails.Count() > 20)
|
|
||||||
{
|
|
||||||
yield return new ValidationResult("You can only invite up to 20 users at a time.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var attr = new EmailAddressAttribute();
|
|
||||||
for (var i = 0; i < Emails.Count(); i++)
|
|
||||||
{
|
|
||||||
var email = Emails.ElementAt(i);
|
|
||||||
if (!attr.IsValid(email) || email.Contains(" ") || email.Contains("<"))
|
|
||||||
{
|
|
||||||
yield return new ValidationResult($"Email #{i + 1} is not valid.",
|
|
||||||
new string[] { nameof(Emails) });
|
|
||||||
}
|
|
||||||
else if (email.Length > 256)
|
|
||||||
{
|
|
||||||
yield return new ValidationResult($"Email #{i + 1} is longer than 256 characters.",
|
|
||||||
new string[] { nameof(Emails) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OrganizationUserAcceptRequestModel
|
public class OrganizationUserAcceptRequestModel
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProviderOrganizationAddRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public Guid OrganizationId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Key { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProviderSetupRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[StringLength(50)]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[StringLength(50)]
|
||||||
|
public string BusinessName { get; set; }
|
||||||
|
[Required]
|
||||||
|
[StringLength(256)]
|
||||||
|
[EmailAddress]
|
||||||
|
public string BillingEmail { get; set; }
|
||||||
|
[Required]
|
||||||
|
public string Token { get; set; }
|
||||||
|
[Required]
|
||||||
|
public string Key { get; set; }
|
||||||
|
|
||||||
|
public virtual Provider ToProvider(Provider provider)
|
||||||
|
{
|
||||||
|
provider.Name = Name;
|
||||||
|
provider.BusinessName = BusinessName;
|
||||||
|
provider.BillingEmail = BillingEmail;
|
||||||
|
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProviderUserInviteRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddressList]
|
||||||
|
public IEnumerable<string> Emails { get; set; }
|
||||||
|
[Required]
|
||||||
|
public ProviderUserType? Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserAcceptRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Token { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserConfirmRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Key { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserBulkConfirmRequestModelEntry
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
[Required]
|
||||||
|
public string Key { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserBulkConfirmRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public IEnumerable<ProviderUserBulkConfirmRequestModelEntry> Keys { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<Guid, string> ToDictionary()
|
||||||
|
{
|
||||||
|
return Keys.ToDictionary(e => e.Id, e => e.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserUpdateRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public ProviderUserType? Type { get; set; }
|
||||||
|
|
||||||
|
public ProviderUser ToProviderUser(ProviderUser existingUser)
|
||||||
|
{
|
||||||
|
existingUser.Type = Type.Value;
|
||||||
|
return existingUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserBulkRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public IEnumerable<Guid> Ids { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,8 @@ namespace Bit.Core.Models.Api
|
|||||||
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(organization.Permissions);
|
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(organization.Permissions);
|
||||||
ResetPasswordEnrolled = organization.ResetPasswordKey != null;
|
ResetPasswordEnrolled = organization.ResetPasswordKey != null;
|
||||||
UserId = organization.UserId?.ToString();
|
UserId = organization.UserId?.ToString();
|
||||||
|
ProviderId = organization.ProviderId?.ToString();
|
||||||
|
ProviderName = organization.ProviderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
@ -63,5 +65,7 @@ namespace Bit.Core.Models.Api
|
|||||||
public bool ResetPasswordEnrolled { get; set; }
|
public bool ResetPasswordEnrolled { get; set; }
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
public bool HasPublicAndPrivateKeys { get; set; }
|
public bool HasPublicAndPrivateKeys { get; set; }
|
||||||
|
public string ProviderId { get; set; }
|
||||||
|
public string ProviderName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ namespace Bit.Core.Models.Api
|
|||||||
public class ProfileResponseModel : ResponseModel
|
public class ProfileResponseModel : ResponseModel
|
||||||
{
|
{
|
||||||
public ProfileResponseModel(User user,
|
public ProfileResponseModel(User user,
|
||||||
IEnumerable<OrganizationUserOrganizationDetails> organizationsUserDetails, bool twoFactorEnabled)
|
IEnumerable<OrganizationUserOrganizationDetails> organizationsUserDetails,
|
||||||
: base("profile")
|
IEnumerable<ProviderUserProviderDetails> providerUserDetails, bool twoFactorEnabled) : base("profile")
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -30,6 +30,7 @@ namespace Bit.Core.Models.Api
|
|||||||
PrivateKey = user.PrivateKey;
|
PrivateKey = user.PrivateKey;
|
||||||
SecurityStamp = user.SecurityStamp;
|
SecurityStamp = user.SecurityStamp;
|
||||||
Organizations = organizationsUserDetails?.Select(o => new ProfileOrganizationResponseModel(o));
|
Organizations = organizationsUserDetails?.Select(o => new ProfileOrganizationResponseModel(o));
|
||||||
|
Providers = providerUserDetails?.Select(p => new ProfileProviderResponseModel(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
@ -44,5 +45,6 @@ namespace Bit.Core.Models.Api
|
|||||||
public string PrivateKey { get; set; }
|
public string PrivateKey { get; set; }
|
||||||
public string SecurityStamp { get; set; }
|
public string SecurityStamp { get; set; }
|
||||||
public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; }
|
public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; }
|
||||||
|
public IEnumerable<ProfileProviderResponseModel> Providers { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProfileProviderResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public ProfileProviderResponseModel(ProviderUserProviderDetails provider)
|
||||||
|
: base("profileProvider")
|
||||||
|
{
|
||||||
|
Id = provider.ProviderId.ToString();
|
||||||
|
Name = provider.Name;
|
||||||
|
Key = provider.Key;
|
||||||
|
Status = provider.Status;
|
||||||
|
Type = provider.Type;
|
||||||
|
Enabled = provider.Enabled;
|
||||||
|
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(provider.Permissions);
|
||||||
|
UserId = provider.UserId?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Key { get; set; }
|
||||||
|
public ProviderUserStatusType Status { get; set; }
|
||||||
|
public ProviderUserType Type { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public Permissions Permissions { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProviderOrganizationOrganizationDetailsResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public ProviderOrganizationOrganizationDetailsResponseModel(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;
|
||||||
|
RevisionDate = providerOrganization.RevisionDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProviderResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public ProviderResponseModel(Provider provider, string obj = "provider") : base(obj)
|
||||||
|
{
|
||||||
|
if (provider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(provider));
|
||||||
|
}
|
||||||
|
|
||||||
|
Id = provider.Id;
|
||||||
|
Name = provider.Name;
|
||||||
|
BusinessName = provider.BusinessName;
|
||||||
|
BusinessAddress1 = provider.BusinessAddress1;
|
||||||
|
BusinessAddress2 = provider.BusinessAddress2;
|
||||||
|
BusinessAddress3 = provider.BusinessAddress3;
|
||||||
|
BusinessCountry = provider.BusinessCountry;
|
||||||
|
BusinessTaxNumber = provider.BusinessTaxNumber;
|
||||||
|
BillingEmail = provider.BillingEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string BusinessName { get; set; }
|
||||||
|
public string BusinessAddress1 { get; set; }
|
||||||
|
public string BusinessAddress2 { get; set; }
|
||||||
|
public string BusinessAddress3 { get; set; }
|
||||||
|
public string BusinessCountry { get; set; }
|
||||||
|
public string BusinessTaxNumber { get; set; }
|
||||||
|
public string BillingEmail { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class ProviderUserResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public ProviderUserResponseModel(ProviderUser providerUser, string obj = "providerUser")
|
||||||
|
: base(obj)
|
||||||
|
{
|
||||||
|
if (providerUser == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(providerUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
Id = providerUser.Id.ToString();
|
||||||
|
UserId = providerUser.UserId?.ToString();
|
||||||
|
Type = providerUser.Type;
|
||||||
|
Status = providerUser.Status;
|
||||||
|
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(providerUser.Permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProviderUserResponseModel(ProviderUserUserDetails providerUser, string obj = "providerUser")
|
||||||
|
: base(obj)
|
||||||
|
{
|
||||||
|
if (providerUser == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(providerUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
Id = providerUser.Id.ToString();
|
||||||
|
UserId = providerUser.UserId?.ToString();
|
||||||
|
Type = providerUser.Type;
|
||||||
|
Status = providerUser.Status;
|
||||||
|
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(providerUser.Permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
public ProviderUserType Type { get; set; }
|
||||||
|
public ProviderUserStatusType Status { get; set; }
|
||||||
|
public Permissions Permissions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserUserDetailsResponseModel : ProviderUserResponseModel
|
||||||
|
{
|
||||||
|
public ProviderUserUserDetailsResponseModel(ProviderUserUserDetails providerUser,
|
||||||
|
string obj = "providerUserUserDetails") : base(providerUser, obj)
|
||||||
|
{
|
||||||
|
if (providerUser == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(providerUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
Name = providerUser.Name;
|
||||||
|
Email = providerUser.Email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserPublicKeyResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public ProviderUserPublicKeyResponseModel(Guid id, string key,
|
||||||
|
string obj = "providerUserPublicKeyResponseModel") : base(obj)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Key { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderUserBulkResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public ProviderUserBulkResponseModel(Guid id, string error,
|
||||||
|
string obj = "providerBulkConfirmResponseModel") : base(obj)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Error { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ namespace Bit.Core.Models.Api
|
|||||||
User user,
|
User user,
|
||||||
bool userTwoFactorEnabled,
|
bool userTwoFactorEnabled,
|
||||||
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails,
|
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails,
|
||||||
|
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
||||||
IEnumerable<Folder> folders,
|
IEnumerable<Folder> folders,
|
||||||
IEnumerable<CollectionDetails> collections,
|
IEnumerable<CollectionDetails> collections,
|
||||||
IEnumerable<CipherDetails> ciphers,
|
IEnumerable<CipherDetails> ciphers,
|
||||||
@ -24,7 +25,7 @@ namespace Bit.Core.Models.Api
|
|||||||
IEnumerable<Send> sends)
|
IEnumerable<Send> sends)
|
||||||
: base("sync")
|
: base("sync")
|
||||||
{
|
{
|
||||||
Profile = new ProfileResponseModel(user, organizationUserDetails, userTwoFactorEnabled);
|
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails, userTwoFactorEnabled);
|
||||||
Folders = folders.Select(f => new FolderResponseModel(f));
|
Folders = folders.Select(f => new FolderResponseModel(f));
|
||||||
Ciphers = ciphers.Select(c => new CipherDetailsResponseModel(c, globalSettings, collectionCiphersDict));
|
Ciphers = ciphers.Select(c => new CipherDetailsResponseModel(c, globalSettings, collectionCiphersDict));
|
||||||
Collections = collections?.Select(
|
Collections = collections?.Select(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Business.Provider
|
namespace Bit.Core.Models.Business.Provider
|
||||||
@ -8,8 +9,11 @@ namespace Bit.Core.Models.Business.Provider
|
|||||||
{
|
{
|
||||||
public IEnumerable<string> Emails { get; set; }
|
public IEnumerable<string> Emails { get; set; }
|
||||||
public ProviderUserType Type { get; set; }
|
public ProviderUserType Type { get; set; }
|
||||||
public Permissions Permissions { get; set; }
|
|
||||||
|
|
||||||
public ProviderUserInvite() {}
|
public ProviderUserInvite(ProviderUserInviteRequestModel requestModel)
|
||||||
|
{
|
||||||
|
Emails = requestModel.Emails;
|
||||||
|
Type = requestModel.Type.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,13 @@ namespace Bit.Core.Models.Data
|
|||||||
public EventType Type { get; set; }
|
public EventType Type { get; set; }
|
||||||
public Guid? UserId { get; set; }
|
public Guid? UserId { get; set; }
|
||||||
public Guid? OrganizationId { get; set; }
|
public Guid? OrganizationId { get; set; }
|
||||||
|
public Guid? ProviderId { get; set; }
|
||||||
public Guid? CipherId { get; set; }
|
public Guid? CipherId { get; set; }
|
||||||
public Guid? CollectionId { get; set; }
|
public Guid? CollectionId { get; set; }
|
||||||
public Guid? GroupId { get; set; }
|
public Guid? GroupId { get; set; }
|
||||||
public Guid? PolicyId { get; set; }
|
public Guid? PolicyId { get; set; }
|
||||||
public Guid? OrganizationUserId { get; set; }
|
public Guid? OrganizationUserId { get; set; }
|
||||||
|
public Guid? ProviderUserId { get; set; }
|
||||||
public Guid? ActingUserId { get; set; }
|
public Guid? ActingUserId { get; set; }
|
||||||
public DeviceType? DeviceType { get; set; }
|
public DeviceType? DeviceType { get; set; }
|
||||||
public string IpAddress { get; set; }
|
public string IpAddress { get; set; }
|
||||||
|
@ -32,5 +32,7 @@ namespace Bit.Core.Models.Data
|
|||||||
public string ResetPasswordKey { get; set; }
|
public string ResetPasswordKey { get; set; }
|
||||||
public string PublicKey { get; set; }
|
public string PublicKey { get; set; }
|
||||||
public string PrivateKey { get; set; }
|
public string PrivateKey { get; set; }
|
||||||
|
public Guid? ProviderId { get; set; }
|
||||||
|
public string ProviderName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
src/Core/Models/Data/Provider/ProviderAbility.cs
Normal file
22
src/Core/Models/Data/Provider/ProviderAbility.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Data
|
||||||
|
{
|
||||||
|
public class ProviderAbility
|
||||||
|
{
|
||||||
|
public ProviderAbility() { }
|
||||||
|
|
||||||
|
public ProviderAbility(Provider provider)
|
||||||
|
{
|
||||||
|
Id = provider.Id;
|
||||||
|
UseEvents = provider.UseEvents;
|
||||||
|
Enabled = provider.Enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public bool UseEvents { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Data
|
||||||
|
{
|
||||||
|
public class ProviderOrganizationOrganizationDetails
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
17
src/Core/Models/Data/Provider/ProviderUserProviderDetails.cs
Normal file
17
src/Core/Models/Data/Provider/ProviderUserProviderDetails.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Data
|
||||||
|
{
|
||||||
|
public class ProviderUserProviderDetails
|
||||||
|
{
|
||||||
|
public Guid ProviderId { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Key { get; set; }
|
||||||
|
public ProviderUserStatusType Status { get; set; }
|
||||||
|
public ProviderUserType Type { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string Permissions { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
src/Core/Models/Data/Provider/ProviderUserPublicKey.cs
Normal file
10
src/Core/Models/Data/Provider/ProviderUserPublicKey.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Data
|
||||||
|
{
|
||||||
|
public class ProviderUserPublicKey
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string PublicKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
17
src/Core/Models/Data/Provider/ProviderUserUserDetails.cs
Normal file
17
src/Core/Models/Data/Provider/ProviderUserUserDetails.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Data
|
||||||
|
{
|
||||||
|
public class ProviderUserUserDetails
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid ProviderId { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public ProviderUserStatusType Status { get; set; }
|
||||||
|
public ProviderUserType Type { get; set; }
|
||||||
|
public string Permissions { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
public string ProviderId { get; set; }
|
public string ProviderId { get; set; }
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
public string Url => string.Format("{0}/setup-provider?providerId={1}&email={2}&token={3}",
|
public string Url => string.Format("{0}/providers/setup-provider?providerId={1}&email={2}&token={3}",
|
||||||
WebVaultUrl,
|
WebVaultUrl,
|
||||||
ProviderId,
|
ProviderId,
|
||||||
Email,
|
Email,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string ProviderNameUrlEncoded { get; set; }
|
public string ProviderNameUrlEncoded { get; set; }
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
public string Url => string.Format("{0}/accept-provider?providerId={1}&" +
|
public string Url => string.Format("{0}/providers/accept-provider?providerId={1}&" +
|
||||||
"providerUserId={2}&email={3}&providerName={4}&token={5}",
|
"providerUserId={2}&email={3}&providerName={4}&token={5}",
|
||||||
WebVaultUrl,
|
WebVaultUrl,
|
||||||
ProviderId,
|
ProviderId,
|
||||||
|
@ -16,6 +16,7 @@ namespace Bit.Core.Models.Table.Provider
|
|||||||
public string BusinessTaxNumber { get; set; }
|
public string BusinessTaxNumber { get; set; }
|
||||||
public string BillingEmail { get; set; }
|
public string BillingEmail { get; set; }
|
||||||
public ProviderStatusType Status { get; set; }
|
public ProviderStatusType Status { get; set; }
|
||||||
|
public bool UseEvents { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
||||||
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
||||||
|
@ -14,8 +14,8 @@ namespace Bit.Core.Models.Table.Provider
|
|||||||
public ProviderUserStatusType Status { get; set; }
|
public ProviderUserStatusType Status { get; set; }
|
||||||
public ProviderUserType Type { get; set; }
|
public ProviderUserType Type { get; set; }
|
||||||
public string Permissions { get; set; }
|
public string Permissions { get; set; }
|
||||||
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
public void SetNewId()
|
public void SetNewId()
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories
|
namespace Bit.Core.Repositories
|
||||||
{
|
{
|
||||||
public interface IProviderOrganizationRepository : IRepository<Provider, Guid>
|
public interface IProviderOrganizationRepository : IRepository<ProviderOrganization, Guid>
|
||||||
{
|
{
|
||||||
|
Task<ICollection<ProviderOrganizationOrganizationDetails>> GetManyDetailsByProviderAsync(Guid providerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories
|
namespace Bit.Core.Repositories
|
||||||
@ -8,5 +9,6 @@ namespace Bit.Core.Repositories
|
|||||||
public interface IProviderRepository : IRepository<Provider, Guid>
|
public interface IProviderRepository : IRepository<Provider, Guid>
|
||||||
{
|
{
|
||||||
Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take);
|
Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take);
|
||||||
|
Task<ICollection<ProviderAbility>> GetManyAbilitiesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories
|
namespace Bit.Core.Repositories
|
||||||
@ -10,7 +11,13 @@ namespace Bit.Core.Repositories
|
|||||||
{
|
{
|
||||||
Task<int> GetCountByProviderAsync(Guid providerId, string email, bool onlyRegisteredUsers);
|
Task<int> GetCountByProviderAsync(Guid providerId, string email, bool onlyRegisteredUsers);
|
||||||
Task<ICollection<ProviderUser>> GetManyAsync(IEnumerable<Guid> ids);
|
Task<ICollection<ProviderUser>> GetManyAsync(IEnumerable<Guid> ids);
|
||||||
|
Task<ICollection<ProviderUser>> GetManyByUserAsync(Guid userId);
|
||||||
|
Task<ProviderUser> GetByProviderUserAsync(Guid providerId, Guid userId);
|
||||||
Task<ICollection<ProviderUser>> GetManyByProviderAsync(Guid providerId, ProviderUserType? type = null);
|
Task<ICollection<ProviderUser>> GetManyByProviderAsync(Guid providerId, ProviderUserType? type = null);
|
||||||
|
Task<ICollection<ProviderUserUserDetails>> GetManyDetailsByProviderAsync(Guid providerId);
|
||||||
|
Task<ICollection<ProviderUserProviderDetails>> GetManyDetailsByUserAsync(Guid userId,
|
||||||
|
ProviderUserStatusType? status = null);
|
||||||
Task DeleteManyAsync(IEnumerable<Guid> userIds);
|
Task DeleteManyAsync(IEnumerable<Guid> userIds);
|
||||||
|
Task<IEnumerable<ProviderUserPublicKey>> GetManyPublicKeysByProviderUserAsync(Guid providerId, IEnumerable<Guid> Ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
|
using Dapper;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories.SqlServer
|
namespace Bit.Core.Repositories.SqlServer
|
||||||
{
|
{
|
||||||
public class ProviderOrganizationRepository : Repository<Provider, Guid>, IProviderOrganizationRepository
|
public class ProviderOrganizationRepository : Repository<ProviderOrganization, Guid>, IProviderOrganizationRepository
|
||||||
{
|
{
|
||||||
public ProviderOrganizationRepository(GlobalSettings globalSettings)
|
public ProviderOrganizationRepository(GlobalSettings globalSettings)
|
||||||
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
|
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
|
||||||
@ -13,5 +20,18 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
public ProviderOrganizationRepository(string connectionString, string readOnlyConnectionString)
|
public ProviderOrganizationRepository(string connectionString, string readOnlyConnectionString)
|
||||||
: base(connectionString, readOnlyConnectionString)
|
: base(connectionString, readOnlyConnectionString)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderOrganizationOrganizationDetails>> GetManyDetailsByProviderAsync(Guid providerId)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderOrganizationOrganizationDetails>(
|
||||||
|
"[dbo].[ProviderOrganizationOrganizationDetails_ReadByProviderId]",
|
||||||
|
new { ProviderId = providerId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Data;
|
|||||||
using Dapper;
|
using Dapper;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
|
|
||||||
@ -34,5 +35,17 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
return results.ToList();
|
return results.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderAbility>> GetManyAbilitiesAsync()
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderAbility>(
|
||||||
|
"[dbo].[Provider_ReadAbilities]",
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using System.Data;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table.Provider;
|
using Bit.Core.Models.Table.Provider;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
@ -48,6 +49,32 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderUser>> GetManyByUserAsync(Guid userId)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderUser>(
|
||||||
|
"[dbo].[ProviderUser_ReadByUserId]",
|
||||||
|
new { UserId = userId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ProviderUser> GetByProviderUserAsync(Guid providerId, Guid userId)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderUser>(
|
||||||
|
"[dbo].[ProviderUser_ReadByProviderIdUserId]",
|
||||||
|
new { ProviderId = providerId, UserId = userId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.SingleOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ICollection<ProviderUser>> GetManyByProviderAsync(Guid providerId, ProviderUserType? type)
|
public async Task<ICollection<ProviderUser>> GetManyByProviderAsync(Guid providerId, ProviderUserType? type)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
@ -61,6 +88,33 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderUserUserDetails>> GetManyDetailsByProviderAsync(Guid providerId)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderUserUserDetails>(
|
||||||
|
"[dbo].[ProviderUserUserDetails_ReadByProviderId]",
|
||||||
|
new { ProviderId = providerId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderUserProviderDetails>> GetManyDetailsByUserAsync(Guid userId,
|
||||||
|
ProviderUserStatusType? status = null)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderUserProviderDetails>(
|
||||||
|
"[dbo].[ProviderUserProviderDetails_ReadByUserIdStatus]",
|
||||||
|
new { UserId = userId, Status = status },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteManyAsync(IEnumerable<Guid> providerUserIds)
|
public async Task DeleteManyAsync(IEnumerable<Guid> providerUserIds)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
@ -69,5 +123,19 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
new { Ids = providerUserIds.ToGuidIdArrayTVP() }, commandType: CommandType.StoredProcedure);
|
new { Ids = providerUserIds.ToGuidIdArrayTVP() }, commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<ProviderUserPublicKey>> GetManyPublicKeysByProviderUserAsync(
|
||||||
|
Guid providerId, IEnumerable<Guid> Ids)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<ProviderUserPublicKey>(
|
||||||
|
"[dbo].[User_ReadPublicKeysByProviderUserIds]",
|
||||||
|
new { ProviderId = providerId, ProviderUserIds = Ids.ToGuidIdArrayTVP() },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ namespace Bit.Core.Services
|
|||||||
public interface IApplicationCacheService
|
public interface IApplicationCacheService
|
||||||
{
|
{
|
||||||
Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync();
|
Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync();
|
||||||
|
Task<IDictionary<Guid, ProviderAbility>> GetProviderAbilitiesAsync();
|
||||||
Task UpsertOrganizationAbilityAsync(Organization organization);
|
Task UpsertOrganizationAbilityAsync(Organization organization);
|
||||||
Task DeleteOrganizationAbilityAsync(Guid organizationId);
|
Task DeleteOrganizationAbilityAsync(Guid organizationId);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace Bit.Core.Services
|
|||||||
public interface IProviderService
|
public interface IProviderService
|
||||||
{
|
{
|
||||||
Task CreateAsync(string ownerEmail);
|
Task CreateAsync(string ownerEmail);
|
||||||
Task CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key);
|
Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key);
|
||||||
Task UpdateAsync(Provider provider, bool updateBilling = false);
|
Task UpdateAsync(Provider provider, bool updateBilling = false);
|
||||||
|
|
||||||
Task<List<ProviderUser>> InviteUserAsync(Guid providerId, Guid invitingUserId, ProviderUserInvite providerUserInvite);
|
Task<List<ProviderUser>> InviteUserAsync(Guid providerId, Guid invitingUserId, ProviderUserInvite providerUserInvite);
|
||||||
|
@ -223,16 +223,45 @@ namespace Bit.Core.Services
|
|||||||
await _eventWriteService.CreateAsync(e);
|
await _eventWriteService.CreateAsync(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement this
|
public async Task LogProviderUserEventAsync(ProviderUser providerUser, EventType type, DateTime? date = null)
|
||||||
public Task LogProviderUserEventAsync(ProviderUser providerUser, EventType type, DateTime? date = null) => throw new NotImplementedException();
|
{
|
||||||
|
await LogProviderUsersEventAsync(new[] { (providerUser, type, date) });
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Implement this
|
public async Task LogProviderUsersEventAsync(IEnumerable<(ProviderUser, EventType, DateTime?)> events)
|
||||||
public Task LogProviderUsersEventAsync(IEnumerable<(ProviderUser, EventType, DateTime?)> events) => throw new NotImplementedException();
|
{
|
||||||
|
var providerAbilities = await _applicationCacheService.GetProviderAbilitiesAsync();
|
||||||
|
var eventMessages = new List<IEvent>();
|
||||||
|
foreach (var (providerUser, type, date) in events)
|
||||||
|
{
|
||||||
|
if (!CanUseProviderEvents(providerAbilities, providerUser.ProviderId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
eventMessages.Add(new EventMessage
|
||||||
|
{
|
||||||
|
ProviderId = providerUser.ProviderId,
|
||||||
|
UserId = providerUser.UserId,
|
||||||
|
ProviderUserId = providerUser.Id,
|
||||||
|
Type = type,
|
||||||
|
ActingUserId = _currentContext?.UserId,
|
||||||
|
Date = date.GetValueOrDefault(DateTime.UtcNow)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _eventWriteService.CreateManyAsync(eventMessages);
|
||||||
|
}
|
||||||
|
|
||||||
private bool CanUseEvents(IDictionary<Guid, OrganizationAbility> orgAbilities, Guid orgId)
|
private bool CanUseEvents(IDictionary<Guid, OrganizationAbility> orgAbilities, Guid orgId)
|
||||||
{
|
{
|
||||||
return orgAbilities != null && orgAbilities.ContainsKey(orgId) &&
|
return orgAbilities != null && orgAbilities.ContainsKey(orgId) &&
|
||||||
orgAbilities[orgId].Enabled && orgAbilities[orgId].UseEvents;
|
orgAbilities[orgId].Enabled && orgAbilities[orgId].UseEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanUseProviderEvents(IDictionary<Guid, ProviderAbility> providerAbilities, Guid providerId)
|
||||||
|
{
|
||||||
|
return providerAbilities != null && providerAbilities.ContainsKey(providerId) &&
|
||||||
|
providerAbilities[providerId].Enabled && providerAbilities[providerId].UseEvents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -675,6 +675,7 @@ namespace Bit.Core.Services
|
|||||||
ProviderId = providerUser.ProviderId.ToString(),
|
ProviderId = providerUser.ProviderId.ToString(),
|
||||||
ProviderUserId = providerUser.Id.ToString(),
|
ProviderUserId = providerUser.Id.ToString(),
|
||||||
ProviderNameUrlEncoded = WebUtility.UrlEncode(providerName),
|
ProviderNameUrlEncoded = WebUtility.UrlEncode(providerName),
|
||||||
|
Token = token,
|
||||||
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
|
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
|
||||||
SiteName = _globalSettings.SiteName,
|
SiteName = _globalSettings.SiteName,
|
||||||
};
|
};
|
||||||
|
@ -11,14 +11,18 @@ namespace Bit.Core.Services
|
|||||||
public class InMemoryApplicationCacheService : IApplicationCacheService
|
public class InMemoryApplicationCacheService : IApplicationCacheService
|
||||||
{
|
{
|
||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
|
private readonly IProviderRepository _providerRepository;
|
||||||
private DateTime _lastOrgAbilityRefresh = DateTime.MinValue;
|
private DateTime _lastOrgAbilityRefresh = DateTime.MinValue;
|
||||||
private IDictionary<Guid, OrganizationAbility> _orgAbilities;
|
private IDictionary<Guid, OrganizationAbility> _orgAbilities;
|
||||||
private TimeSpan _orgAbilitiesRefreshInterval = TimeSpan.FromMinutes(10);
|
private TimeSpan _orgAbilitiesRefreshInterval = TimeSpan.FromMinutes(10);
|
||||||
|
|
||||||
|
private IDictionary<Guid, ProviderAbility> _providerAbilities;
|
||||||
|
|
||||||
public InMemoryApplicationCacheService(
|
public InMemoryApplicationCacheService(
|
||||||
IOrganizationRepository organizationRepository)
|
IOrganizationRepository organizationRepository, IProviderRepository providerRepository)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
|
_providerRepository = providerRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync()
|
public virtual async Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync()
|
||||||
@ -27,6 +31,12 @@ namespace Bit.Core.Services
|
|||||||
return _orgAbilities;
|
return _orgAbilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IDictionary<Guid, ProviderAbility>> GetProviderAbilitiesAsync()
|
||||||
|
{
|
||||||
|
await InitProviderAbilitiesAsync();
|
||||||
|
return _providerAbilities;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task UpsertOrganizationAbilityAsync(Organization organization)
|
public virtual async Task UpsertOrganizationAbilityAsync(Organization organization)
|
||||||
{
|
{
|
||||||
await InitOrganizationAbilitiesAsync();
|
await InitOrganizationAbilitiesAsync();
|
||||||
@ -62,5 +72,16 @@ namespace Bit.Core.Services
|
|||||||
_lastOrgAbilityRefresh = now;
|
_lastOrgAbilityRefresh = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task InitProviderAbilitiesAsync()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
if (_providerAbilities == null || (now - _lastOrgAbilityRefresh) > _orgAbilitiesRefreshInterval)
|
||||||
|
{
|
||||||
|
var abilities = await _providerRepository.GetManyAbilitiesAsync();
|
||||||
|
_providerAbilities = abilities.ToDictionary(a => a.Id);
|
||||||
|
_lastOrgAbilityRefresh = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,9 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public InMemoryServiceBusApplicationCacheService(
|
public InMemoryServiceBusApplicationCacheService(
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
: base(organizationRepository)
|
: base(organizationRepository, providerRepository)
|
||||||
{
|
{
|
||||||
_subName = CoreHelpers.GetApplicationCacheServiceBusSubcriptionName(globalSettings);
|
_subName = CoreHelpers.GetApplicationCacheServiceBusSubcriptionName(globalSettings);
|
||||||
_topicClient = new TopicClient(globalSettings.ServiceBus.ConnectionString,
|
_topicClient = new TopicClient(globalSettings.ServiceBus.ConnectionString,
|
||||||
|
34
src/Core/Services/NoopImplementations/NoopProviderService.cs
Normal file
34
src/Core/Services/NoopImplementations/NoopProviderService.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Business.Provider;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using Bit.Core.Models.Table.Provider;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class NoopProviderService : IProviderService
|
||||||
|
{
|
||||||
|
public Task CreateAsync(string ownerEmail) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task UpdateAsync(Provider provider, bool updateBilling = false) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<List<ProviderUser>> InviteUserAsync(Guid providerId, Guid invitingUserId, ProviderUserInvite providerUserInvite) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<List<Tuple<ProviderUser, string>>> ResendInvitesAsync(Guid providerId, Guid invitingUserId, IEnumerable<Guid> providerUsersId) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<ProviderUser> AcceptUserAsync(Guid providerUserId, User user, string token) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<List<Tuple<ProviderUser, string>>> ConfirmUsersAsync(Guid providerId, Dictionary<Guid, string> keys, Guid confirmingUserId) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task SaveUserAsync(ProviderUser user, Guid savingUserId) => 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 RemoveOrganization(Guid providerOrganizationId, Guid removingUserId) => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ using Microsoft.Azure.Storage.Blob;
|
|||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using IdentityModel;
|
using IdentityModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Bit.Core.Enums.Provider;
|
||||||
|
|
||||||
namespace Bit.Core.Utilities
|
namespace Bit.Core.Utilities
|
||||||
{
|
{
|
||||||
@ -737,7 +738,8 @@ namespace Bit.Core.Utilities
|
|||||||
return configDict;
|
return configDict;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<KeyValuePair<string, string>> BuildIdentityClaims(User user, ICollection<CurrentContentOrganization> orgs, bool isPremium)
|
public static List<KeyValuePair<string, string>> BuildIdentityClaims(User user, ICollection<CurrentContentOrganization> orgs,
|
||||||
|
ICollection<CurrentContentProvider> providers, bool isPremium)
|
||||||
{
|
{
|
||||||
var claims = new List<KeyValuePair<string, string>>()
|
var claims = new List<KeyValuePair<string, string>>()
|
||||||
{
|
{
|
||||||
@ -849,6 +851,29 @@ namespace Bit.Core.Utilities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (providers.Any())
|
||||||
|
{
|
||||||
|
foreach (var group in providers.GroupBy(o => o.Type))
|
||||||
|
{
|
||||||
|
switch (group.Key)
|
||||||
|
{
|
||||||
|
case ProviderUserType.ProviderAdmin:
|
||||||
|
foreach (var provider in group)
|
||||||
|
{
|
||||||
|
claims.Add(new KeyValuePair<string, string>("providerprovideradmin", provider.Id.ToString()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProviderUserType.ServiceUser:
|
||||||
|
foreach (var provider in group)
|
||||||
|
{
|
||||||
|
claims.Add(new KeyValuePair<string, string>("providerserviceuser", provider.Id.ToString()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return claims;
|
return claims;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
src/Core/Utilities/EmailAddressListAttribute.cs
Normal file
41
src/Core/Utilities/EmailAddressListAttribute.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Bit.Core.Utilities
|
||||||
|
{
|
||||||
|
public class EmailAddressListAttribute : ValidationAttribute
|
||||||
|
{
|
||||||
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
var emailAttribute = new EmailAddressAttribute();
|
||||||
|
var emails = value as IList<string>;
|
||||||
|
|
||||||
|
if (!emails?.Any() ?? true)
|
||||||
|
{
|
||||||
|
return new ValidationResult("An email is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emails.Count() > 20)
|
||||||
|
{
|
||||||
|
return new ValidationResult("You can only submit up to 20 emails at a time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < emails.Count(); i++)
|
||||||
|
{
|
||||||
|
var email = emails.ElementAt(i);
|
||||||
|
if (!emailAttribute.IsValid(email) || email.Contains(" ") || email.Contains("<"))
|
||||||
|
{
|
||||||
|
return new ValidationResult($"Email #{i + 1} is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (email.Length > 256)
|
||||||
|
{
|
||||||
|
return new ValidationResult($"Email #{i + 1} is longer than 256 characters.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -126,7 +126,6 @@ namespace Bit.Core.Utilities
|
|||||||
services.AddSingleton<IAppleIapService, AppleIapService>();
|
services.AddSingleton<IAppleIapService, AppleIapService>();
|
||||||
services.AddSingleton<ISsoConfigService, SsoConfigService>();
|
services.AddSingleton<ISsoConfigService, SsoConfigService>();
|
||||||
services.AddScoped<ISendService, SendService>();
|
services.AddScoped<ISendService, SendService>();
|
||||||
services.AddScoped<IProviderService, ProviderService>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings)
|
public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings)
|
||||||
@ -265,6 +264,11 @@ namespace Bit.Core.Utilities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddOosServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IProviderService, NoopProviderService>();
|
||||||
|
}
|
||||||
|
|
||||||
public static void AddNoopServices(this IServiceCollection services)
|
public static void AddNoopServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IMailService, NoopMailService>();
|
services.AddSingleton<IMailService, NoopMailService>();
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
<Build Include="dbo\Stored Procedures\SsoConfig_ReadByIdentifier.sql" />
|
<Build Include="dbo\Stored Procedures\SsoConfig_ReadByIdentifier.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\SsoConfig_ReadByOrganizationId.sql" />
|
<Build Include="dbo\Stored Procedures\SsoConfig_ReadByOrganizationId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\SsoConfig_Update.sql" />
|
<Build Include="dbo\Stored Procedures\SsoConfig_Update.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\User_ReadPublicKeysByProviderUserIds.sql" />
|
||||||
<Build Include="dbo\Tables\Grant.sql" />
|
<Build Include="dbo\Tables\Grant.sql" />
|
||||||
<Build Include="dbo\Tables\SsoConfig.sql" />
|
<Build Include="dbo\Tables\SsoConfig.sql" />
|
||||||
<Build Include="dbo\Tables\User.sql" />
|
<Build Include="dbo\Tables\User.sql" />
|
||||||
@ -90,6 +91,8 @@
|
|||||||
<Build Include="dbo\Tables\OrganizationUser.sql" />
|
<Build Include="dbo\Tables\OrganizationUser.sql" />
|
||||||
<Build Include="dbo\Tables\Organization.sql" />
|
<Build Include="dbo\Tables\Organization.sql" />
|
||||||
<Build Include="dbo\Views\GrantView.sql" />
|
<Build Include="dbo\Views\GrantView.sql" />
|
||||||
|
<Build Include="dbo\Views\ProviderOrganizationOrganizationDetailsView.sql" />
|
||||||
|
<Build Include="dbo\Views\ProviderUserProviderDetailsView.sql" />
|
||||||
<Build Include="dbo\Views\SsoConfigView.sql" />
|
<Build Include="dbo\Views\SsoConfigView.sql" />
|
||||||
<Build Include="dbo\Views\UserView.sql" />
|
<Build Include="dbo\Views\UserView.sql" />
|
||||||
<Build Include="dbo\Views\U2fView.sql" />
|
<Build Include="dbo\Views\U2fView.sql" />
|
||||||
@ -332,6 +335,7 @@
|
|||||||
<Build Include="dbo\Stored Procedures\Provider_DeleteById.sql" />
|
<Build Include="dbo\Stored Procedures\Provider_DeleteById.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Provider_ReadById.sql" />
|
<Build Include="dbo\Stored Procedures\Provider_ReadById.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Provider_Search.sql" />
|
<Build Include="dbo\Stored Procedures\Provider_Search.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\Provider_ReadAbilities.sql" />
|
||||||
<Build Include="dbo\Tables\ProviderUser.sql" />
|
<Build Include="dbo\Tables\ProviderUser.sql" />
|
||||||
<Build Include="dbo\Views\ProviderUserView.sql" />
|
<Build Include="dbo\Views\ProviderUserView.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderUser_Create.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderUser_Create.sql" />
|
||||||
@ -343,12 +347,17 @@
|
|||||||
<Build Include="dbo\Stored Procedures\ProviderUser_ReadByProviderId.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderUser_ReadByProviderId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderUser_ReadByUserId.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderUser_ReadByUserId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderUser_ReadCountByProviderIdEmail.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderUser_ReadCountByProviderIdEmail.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\ProviderUser_ReadByProviderIdUserId.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\ProviderUserProviderDetails_ReadByUserIdStatus.sql" />
|
||||||
|
<Build Include="dbo\Views\ProviderUserUserDetailsView.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\ProviderUserUserDetails_ReadByProviderId.sql" />
|
||||||
<Build Include="dbo\Tables\ProviderOrganization.sql" />
|
<Build Include="dbo\Tables\ProviderOrganization.sql" />
|
||||||
<Build Include="dbo\Views\ProviderOrganizationView.sql" />
|
<Build Include="dbo\Views\ProviderOrganizationView.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_Create.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderOrganization_Create.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_Update.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderOrganization_Update.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_DeleteById.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderOrganization_DeleteById.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_ReadById.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderOrganization_ReadById.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\ProviderOrganizationOrganizationDetails_ReadByProviderId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\User_BumpAccountRevisionDateByProviderId.sql" />
|
<Build Include="dbo\Stored Procedures\User_BumpAccountRevisionDateByProviderId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\User_BumpAccountRevisionDateByProviderUserId.sql" />
|
<Build Include="dbo\Stored Procedures\User_BumpAccountRevisionDateByProviderUserId.sql" />
|
||||||
<Build Include="dbo\Tables\ProviderOrganizationProviderUser.sql" />
|
<Build Include="dbo\Tables\ProviderOrganizationProviderUser.sql" />
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[ProviderOrganizationOrganizationDetails_ReadByProviderId]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderOrganizationOrganizationDetailsView]
|
||||||
|
WHERE
|
||||||
|
[ProviderId] = @ProviderId
|
||||||
|
END
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[ProviderUserProviderDetails_ReadByUserIdStatus]
|
||||||
|
@UserId UNIQUEIDENTIFIER,
|
||||||
|
@Status TINYINT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserProviderDetailsView]
|
||||||
|
WHERE
|
||||||
|
[UserId] = @UserId
|
||||||
|
AND (@Status IS NULL OR [Status] = @Status)
|
||||||
|
END
|
@ -0,0 +1,13 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[ProviderUserUserDetails_ReadByProviderId]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserUserDetailsView]
|
||||||
|
WHERE
|
||||||
|
[ProviderId] = @ProviderId
|
||||||
|
END
|
@ -28,7 +28,7 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
BEGIN TRANSACTION ProviderUser_DeleteMany_PUs
|
BEGIN TRANSACTION ProviderUser_DeleteMany_PUs
|
||||||
|
|
||||||
DELETE TOP(@BatchSize) OU
|
DELETE TOP(@BatchSize) PU
|
||||||
FROM
|
FROM
|
||||||
[dbo].[ProviderUser] PU
|
[dbo].[ProviderUser] PU
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[ProviderUser_ReadByProviderIdUserId]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER,
|
||||||
|
@UserId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserView]
|
||||||
|
WHERE
|
||||||
|
[ProviderId] = @ProviderId
|
||||||
|
AND [UserId] = @UserId
|
||||||
|
END
|
@ -9,6 +9,7 @@
|
|||||||
@BusinessTaxNumber NVARCHAR(30),
|
@BusinessTaxNumber NVARCHAR(30),
|
||||||
@BillingEmail NVARCHAR(256),
|
@BillingEmail NVARCHAR(256),
|
||||||
@Status TINYINT,
|
@Status TINYINT,
|
||||||
|
@UseEvents BIT,
|
||||||
@Enabled BIT,
|
@Enabled BIT,
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
@ -28,6 +29,7 @@ BEGIN
|
|||||||
[BusinessTaxNumber],
|
[BusinessTaxNumber],
|
||||||
[BillingEmail],
|
[BillingEmail],
|
||||||
[Status],
|
[Status],
|
||||||
|
[UseEvents],
|
||||||
[Enabled],
|
[Enabled],
|
||||||
[CreationDate],
|
[CreationDate],
|
||||||
[RevisionDate]
|
[RevisionDate]
|
||||||
@ -44,6 +46,7 @@ BEGIN
|
|||||||
@BusinessTaxNumber,
|
@BusinessTaxNumber,
|
||||||
@BillingEmail,
|
@BillingEmail,
|
||||||
@Status,
|
@Status,
|
||||||
|
@UseEvents,
|
||||||
@Enabled,
|
@Enabled,
|
||||||
@CreationDate,
|
@CreationDate,
|
||||||
@RevisionDate
|
@RevisionDate
|
||||||
|
12
src/Sql/dbo/Stored Procedures/Provider_ReadAbilities.sql
Normal file
12
src/Sql/dbo/Stored Procedures/Provider_ReadAbilities.sql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Provider_ReadAbilities]
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[Id],
|
||||||
|
[UseEvents],
|
||||||
|
[Enabled]
|
||||||
|
FROM
|
||||||
|
[dbo].[Provider]
|
||||||
|
END
|
@ -9,6 +9,7 @@
|
|||||||
@BusinessTaxNumber NVARCHAR(30),
|
@BusinessTaxNumber NVARCHAR(30),
|
||||||
@BillingEmail NVARCHAR(256),
|
@BillingEmail NVARCHAR(256),
|
||||||
@Status TINYINT,
|
@Status TINYINT,
|
||||||
|
@UseEvents BIT,
|
||||||
@Enabled BIT,
|
@Enabled BIT,
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
@ -28,6 +29,7 @@ BEGIN
|
|||||||
[BusinessTaxNumber] = @BusinessTaxNumber,
|
[BusinessTaxNumber] = @BusinessTaxNumber,
|
||||||
[BillingEmail] = @BillingEmail,
|
[BillingEmail] = @BillingEmail,
|
||||||
[Status] = @Status,
|
[Status] = @Status,
|
||||||
|
[UseEvents] = @UseEvents,
|
||||||
[Enabled] = @Enabled,
|
[Enabled] = @Enabled,
|
||||||
[CreationDate] = @CreationDate,
|
[CreationDate] = @CreationDate,
|
||||||
[RevisionDate] = @RevisionDate
|
[RevisionDate] = @RevisionDate
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[User_ReadPublicKeysByProviderUserIds]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER,
|
||||||
|
@ProviderUserIds [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
PU.[Id],
|
||||||
|
U.[PublicKey]
|
||||||
|
FROM
|
||||||
|
@ProviderUserIds PUIDs
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[ProviderUser] PU ON PUIDs.Id = PU.Id AND PU.[Status] = 1 -- Accepted
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[User] U ON PU.UserId = U.Id
|
||||||
|
WHERE
|
||||||
|
PU.ProviderId = @ProviderId
|
||||||
|
END
|
@ -9,6 +9,7 @@
|
|||||||
[BusinessTaxNumber] NVARCHAR (30) NULL,
|
[BusinessTaxNumber] NVARCHAR (30) NULL,
|
||||||
[BillingEmail] NVARCHAR (256) NULL,
|
[BillingEmail] NVARCHAR (256) NULL,
|
||||||
[Status] TINYINT NOT NULL,
|
[Status] TINYINT NOT NULL,
|
||||||
|
[UseEvents] BIT NOT NULL,
|
||||||
[Enabled] BIT NOT NULL,
|
[Enabled] BIT NOT NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
|
@ -27,10 +27,16 @@ SELECT
|
|||||||
OU.[Status],
|
OU.[Status],
|
||||||
OU.[Type],
|
OU.[Type],
|
||||||
SU.[ExternalId] SsoExternalId,
|
SU.[ExternalId] SsoExternalId,
|
||||||
OU.[Permissions]
|
OU.[Permissions],
|
||||||
|
PO.[ProviderId],
|
||||||
|
P.[Name] ProviderName
|
||||||
FROM
|
FROM
|
||||||
[dbo].[OrganizationUser] OU
|
[dbo].[OrganizationUser] OU
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
|
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
[dbo].[SsoUser] SU ON SU.[UserId] = OU.[UserId] AND SU.[OrganizationId] = OU.[OrganizationId]
|
[dbo].[SsoUser] SU ON SU.[UserId] = OU.[UserId] AND SU.[OrganizationId] = OU.[OrganizationId]
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[ProviderOrganization] PO ON PO.[OrganizationId] = O.[Id]
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[Provider] P ON P.[Id] = PO.[ProviderId]
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE VIEW [dbo].[ProviderOrganizationOrganizationDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
PO.[Id],
|
||||||
|
PO.[ProviderId],
|
||||||
|
PO.[OrganizationId],
|
||||||
|
O.[Name] OrganizationName,
|
||||||
|
PO.[Key],
|
||||||
|
PO.[Settings],
|
||||||
|
PO.[CreationDate],
|
||||||
|
PO.[RevisionDate]
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderOrganization] PO
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[Organization] O ON O.[Id] = PO.[OrganizationId]
|
15
src/Sql/dbo/Views/ProviderUserProviderDetailsView.sql
Normal file
15
src/Sql/dbo/Views/ProviderUserProviderDetailsView.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CREATE VIEW [dbo].[ProviderUserProviderDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
PU.[UserId],
|
||||||
|
PU.[ProviderId],
|
||||||
|
P.[Name],
|
||||||
|
PU.[Key],
|
||||||
|
PU.[Status],
|
||||||
|
PU.[Type],
|
||||||
|
P.[Enabled],
|
||||||
|
PU.[Permissions]
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUser] PU
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[Provider] P ON P.[Id] = PU.[ProviderId]
|
15
src/Sql/dbo/Views/ProviderUserUserDetailsView.sql
Normal file
15
src/Sql/dbo/Views/ProviderUserUserDetailsView.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CREATE VIEW [dbo].[ProviderUserUserDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
PU.[Id],
|
||||||
|
PU.[UserId],
|
||||||
|
PU.[ProviderId],
|
||||||
|
U.[Name],
|
||||||
|
ISNULL(U.[Email], PU.[Email]) Email,
|
||||||
|
PU.[Status],
|
||||||
|
PU.[Type],
|
||||||
|
PU.[Permissions]
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUser] PU
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[User] U ON U.[Id] = PU.[UserId]
|
@ -30,6 +30,7 @@ namespace Bit.Api.Test.Controllers
|
|||||||
private readonly ISsoUserRepository _ssoUserRepository;
|
private readonly ISsoUserRepository _ssoUserRepository;
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
|
|
||||||
public AccountsControllerTests()
|
public AccountsControllerTests()
|
||||||
{
|
{
|
||||||
@ -39,6 +40,7 @@ namespace Bit.Api.Test.Controllers
|
|||||||
_folderRepository = Substitute.For<IFolderRepository>();
|
_folderRepository = Substitute.For<IFolderRepository>();
|
||||||
_organizationService = Substitute.For<IOrganizationService>();
|
_organizationService = Substitute.For<IOrganizationService>();
|
||||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||||
|
_providerUserRepository = Substitute.For<IProviderUserRepository>();
|
||||||
_paymentService = Substitute.For<IPaymentService>();
|
_paymentService = Substitute.For<IPaymentService>();
|
||||||
_globalSettings = new GlobalSettings();
|
_globalSettings = new GlobalSettings();
|
||||||
_sut = new AccountsController(
|
_sut = new AccountsController(
|
||||||
@ -47,6 +49,7 @@ namespace Bit.Api.Test.Controllers
|
|||||||
_folderRepository,
|
_folderRepository,
|
||||||
_organizationService,
|
_organizationService,
|
||||||
_organizationUserRepository,
|
_organizationUserRepository,
|
||||||
|
_providerUserRepository,
|
||||||
_paymentService,
|
_paymentService,
|
||||||
_ssoUserRepository,
|
_ssoUserRepository,
|
||||||
_userRepository,
|
_userRepository,
|
||||||
|
@ -5,7 +5,7 @@ using AutoFixture.Xunit2;
|
|||||||
|
|
||||||
namespace Bit.Core.Test.AutoFixture.Attributes
|
namespace Bit.Core.Test.AutoFixture.Attributes
|
||||||
{
|
{
|
||||||
internal class CustomAutoDataAttribute : AutoDataAttribute
|
public class CustomAutoDataAttribute : AutoDataAttribute
|
||||||
{
|
{
|
||||||
public CustomAutoDataAttribute(params Type[] iCustomizationTypes) : this(iCustomizationTypes
|
public CustomAutoDataAttribute(params Type[] iCustomizationTypes) : this(iCustomizationTypes
|
||||||
.Select(t => (ICustomization)Activator.CreateInstance(t)).ToArray())
|
.Select(t => (ICustomization)Activator.CreateInstance(t)).ToArray())
|
||||||
|
@ -11,12 +11,14 @@ namespace Bit.Core.Test.Services
|
|||||||
private readonly InMemoryApplicationCacheService _sut;
|
private readonly InMemoryApplicationCacheService _sut;
|
||||||
|
|
||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
|
private readonly IProviderRepository _providerRepository;
|
||||||
|
|
||||||
public InMemoryApplicationCacheServiceTests()
|
public InMemoryApplicationCacheServiceTests()
|
||||||
{
|
{
|
||||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||||
|
_providerRepository = Substitute.For<IProviderRepository>();
|
||||||
|
|
||||||
_sut = new InMemoryApplicationCacheService(_organizationRepository);
|
_sut = new InMemoryApplicationCacheService(_organizationRepository, _providerRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove this test when we add actual tests. It only proves that
|
// Remove this test when we add actual tests. It only proves that
|
||||||
|
@ -12,15 +12,18 @@ namespace Bit.Core.Test.Services
|
|||||||
private readonly InMemoryServiceBusApplicationCacheService _sut;
|
private readonly InMemoryServiceBusApplicationCacheService _sut;
|
||||||
|
|
||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
|
private readonly IProviderRepository _providerRepository;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
public InMemoryServiceBusApplicationCacheServiceTests()
|
public InMemoryServiceBusApplicationCacheServiceTests()
|
||||||
{
|
{
|
||||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||||
|
_providerRepository = Substitute.For<IProviderRepository>();
|
||||||
_globalSettings = new GlobalSettings();
|
_globalSettings = new GlobalSettings();
|
||||||
|
|
||||||
_sut = new InMemoryServiceBusApplicationCacheService(
|
_sut = new InMemoryServiceBusApplicationCacheService(
|
||||||
_organizationRepository,
|
_organizationRepository,
|
||||||
|
_providerRepository,
|
||||||
_globalSettings
|
_globalSettings
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,7 @@ BEGIN
|
|||||||
[BusinessTaxNumber] NVARCHAR (30) NULL,
|
[BusinessTaxNumber] NVARCHAR (30) NULL,
|
||||||
[BillingEmail] NVARCHAR (256) NOT NULL,
|
[BillingEmail] NVARCHAR (256) NOT NULL,
|
||||||
[Status] TINYINT NOT NULL,
|
[Status] TINYINT NOT NULL,
|
||||||
|
[UseEvents] BIT NOT NULL,
|
||||||
[Enabled] BIT NOT NULL,
|
[Enabled] BIT NOT NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
@ -101,6 +102,29 @@ GO
|
|||||||
ALTER TABLE [dbo].[Provider] ALTER COLUMN [BillingEmail] NVARCHAR (256) NULL;
|
ALTER TABLE [dbo].[Provider] ALTER COLUMN [BillingEmail] NVARCHAR (256) NULL;
|
||||||
GO
|
GO
|
||||||
|
|
||||||
|
IF COL_LENGTH('[dbo].[Provider]', 'UseEvents') IS NULL
|
||||||
|
BEGIN
|
||||||
|
ALTER TABLE
|
||||||
|
[dbo].[Provider]
|
||||||
|
ADD
|
||||||
|
[UseEvents] BIT NULL
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
[dbo].[Provider]
|
||||||
|
SET
|
||||||
|
[UseEvents] = 0
|
||||||
|
WHERE
|
||||||
|
[UseEvents] IS NULL
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
[dbo].[Provider]
|
||||||
|
ALTER COLUMN
|
||||||
|
[UseEvents] BIT NOT NULL
|
||||||
|
GO
|
||||||
|
|
||||||
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'ProviderView')
|
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'ProviderView')
|
||||||
BEGIN
|
BEGIN
|
||||||
DROP VIEW [dbo].[ProviderView];
|
DROP VIEW [dbo].[ProviderView];
|
||||||
@ -132,6 +156,7 @@ CREATE PROCEDURE [dbo].[Provider_Create]
|
|||||||
@BusinessTaxNumber NVARCHAR(30),
|
@BusinessTaxNumber NVARCHAR(30),
|
||||||
@BillingEmail NVARCHAR(256),
|
@BillingEmail NVARCHAR(256),
|
||||||
@Status TINYINT,
|
@Status TINYINT,
|
||||||
|
@UseEvents BIT,
|
||||||
@Enabled BIT,
|
@Enabled BIT,
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
@ -151,6 +176,7 @@ BEGIN
|
|||||||
[BusinessTaxNumber],
|
[BusinessTaxNumber],
|
||||||
[BillingEmail],
|
[BillingEmail],
|
||||||
[Status],
|
[Status],
|
||||||
|
[UseEvents],
|
||||||
[Enabled],
|
[Enabled],
|
||||||
[CreationDate],
|
[CreationDate],
|
||||||
[RevisionDate]
|
[RevisionDate]
|
||||||
@ -167,6 +193,7 @@ BEGIN
|
|||||||
@BusinessTaxNumber,
|
@BusinessTaxNumber,
|
||||||
@BillingEmail,
|
@BillingEmail,
|
||||||
@Status,
|
@Status,
|
||||||
|
@UseEvents,
|
||||||
@Enabled,
|
@Enabled,
|
||||||
@CreationDate,
|
@CreationDate,
|
||||||
@RevisionDate
|
@RevisionDate
|
||||||
@ -191,6 +218,7 @@ CREATE PROCEDURE [dbo].[Provider_Update]
|
|||||||
@BusinessTaxNumber NVARCHAR(30),
|
@BusinessTaxNumber NVARCHAR(30),
|
||||||
@BillingEmail NVARCHAR(256),
|
@BillingEmail NVARCHAR(256),
|
||||||
@Status TINYINT,
|
@Status TINYINT,
|
||||||
|
@UseEvents BIT,
|
||||||
@Enabled BIT,
|
@Enabled BIT,
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
@ -210,6 +238,7 @@ BEGIN
|
|||||||
[BusinessTaxNumber] = @BusinessTaxNumber,
|
[BusinessTaxNumber] = @BusinessTaxNumber,
|
||||||
[BillingEmail] = @BillingEmail,
|
[BillingEmail] = @BillingEmail,
|
||||||
[Status] = @Status,
|
[Status] = @Status,
|
||||||
|
[UseEvents] = @UseEvents,
|
||||||
[Enabled] = @Enabled,
|
[Enabled] = @Enabled,
|
||||||
[CreationDate] = @CreationDate,
|
[CreationDate] = @CreationDate,
|
||||||
[RevisionDate] = @RevisionDate
|
[RevisionDate] = @RevisionDate
|
||||||
@ -923,7 +952,7 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
BEGIN TRANSACTION ProviderUser_DeleteMany_PUs
|
BEGIN TRANSACTION ProviderUser_DeleteMany_PUs
|
||||||
|
|
||||||
DELETE TOP(@BatchSize) OU
|
DELETE TOP(@BatchSize) PU
|
||||||
FROM
|
FROM
|
||||||
[dbo].[ProviderUser] PU
|
[dbo].[ProviderUser] PU
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
@ -984,3 +1013,256 @@ BEGIN
|
|||||||
END
|
END
|
||||||
END
|
END
|
||||||
GO
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[ProviderUser_ReadByProviderIdUserId]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[ProviderUser_ReadByProviderIdUserId]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[ProviderUser_ReadByProviderIdUserId]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER,
|
||||||
|
@UserId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserView]
|
||||||
|
WHERE
|
||||||
|
[ProviderId] = @ProviderId
|
||||||
|
AND [UserId] = @UserId
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'ProviderUserUserDetailsView')
|
||||||
|
BEGIN
|
||||||
|
DROP VIEW [dbo].[ProviderUserUserDetailsView];
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE VIEW [dbo].[ProviderUserUserDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
PU.[Id],
|
||||||
|
PU.[UserId],
|
||||||
|
PU.[ProviderId],
|
||||||
|
U.[Name],
|
||||||
|
ISNULL(U.[Email], PU.[Email]) Email,
|
||||||
|
PU.[Status],
|
||||||
|
PU.[Type],
|
||||||
|
PU.[Permissions]
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUser] PU
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[User] U ON U.[Id] = PU.[UserId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[ProviderUserUserDetails_ReadByProviderId]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[ProviderUserUserDetails_ReadByProviderId]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[ProviderUserUserDetails_ReadByProviderId]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserUserDetailsView]
|
||||||
|
WHERE
|
||||||
|
[ProviderId] = @ProviderId
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'ProviderUserProviderDetailsView')
|
||||||
|
BEGIN
|
||||||
|
DROP VIEW [dbo].[ProviderUserProviderDetailsView];
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE VIEW [dbo].[ProviderUserProviderDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
PU.[UserId],
|
||||||
|
PU.[ProviderId],
|
||||||
|
P.[Name],
|
||||||
|
PU.[Key],
|
||||||
|
PU.[Status],
|
||||||
|
PU.[Type],
|
||||||
|
P.[Enabled],
|
||||||
|
PU.[Permissions]
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUser] PU
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[Provider] P ON P.[Id] = PU.[ProviderId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[ProviderUserProviderDetails_ReadByUserIdStatus]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[ProviderUserProviderDetails_ReadByUserIdStatus]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[ProviderUserProviderDetails_ReadByUserIdStatus]
|
||||||
|
@UserId UNIQUEIDENTIFIER,
|
||||||
|
@Status TINYINT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserProviderDetailsView]
|
||||||
|
WHERE
|
||||||
|
[UserId] = @UserId
|
||||||
|
AND (@Status IS NULL OR [Status] = @Status)
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[Provider_ReadAbilities]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[Provider_ReadAbilities]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[Provider_ReadAbilities]
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[Id],
|
||||||
|
[UseEvents],
|
||||||
|
[Enabled]
|
||||||
|
FROM
|
||||||
|
[dbo].[Provider]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[User_ReadPublicKeysByProviderUserIds]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[User_ReadPublicKeysByProviderUserIds]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[User_ReadPublicKeysByProviderUserIds]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER,
|
||||||
|
@ProviderUserIds [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
PU.[Id],
|
||||||
|
U.[PublicKey]
|
||||||
|
FROM
|
||||||
|
@ProviderUserIds PUIDs
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[ProviderUser] PU ON PUIDs.Id = PU.Id AND PU.[Status] = 1 -- Accepted
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[User] U ON PU.UserId = U.Id
|
||||||
|
WHERE
|
||||||
|
PU.ProviderId = @ProviderId
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'ProviderOrganizationOrganizationDetailsView')
|
||||||
|
BEGIN
|
||||||
|
DROP VIEW [dbo].[ProviderOrganizationOrganizationDetailsView];
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE VIEW [dbo].[ProviderOrganizationOrganizationDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
PO.[Id],
|
||||||
|
PO.[ProviderId],
|
||||||
|
PO.[OrganizationId],
|
||||||
|
O.[Name] OrganizationName,
|
||||||
|
PO.[Key],
|
||||||
|
PO.[Settings],
|
||||||
|
PO.[CreationDate],
|
||||||
|
PO.[RevisionDate]
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderOrganization] PO
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[Organization] O ON O.[Id] = PO.[OrganizationId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID('[dbo].[ProviderOrganizationOrganizationDetails_ReadByProviderId]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[ProviderOrganizationOrganizationDetails_ReadByProviderId]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[ProviderOrganizationOrganizationDetails_ReadByProviderId]
|
||||||
|
@ProviderId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderOrganizationOrganizationDetailsView]
|
||||||
|
WHERE
|
||||||
|
[ProviderId] = @ProviderId
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'OrganizationUserOrganizationDetailsView')
|
||||||
|
BEGIN
|
||||||
|
DROP VIEW [dbo].[OrganizationUserOrganizationDetailsView];
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE VIEW [dbo].[OrganizationUserOrganizationDetailsView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
OU.[UserId],
|
||||||
|
OU.[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],
|
||||||
|
OU.[Key],
|
||||||
|
OU.[ResetPasswordKey],
|
||||||
|
O.[PublicKey],
|
||||||
|
O.[PrivateKey],
|
||||||
|
OU.[Status],
|
||||||
|
OU.[Type],
|
||||||
|
SU.[ExternalId] SsoExternalId,
|
||||||
|
OU.[Permissions],
|
||||||
|
PO.[ProviderId],
|
||||||
|
P.[Name] ProviderName
|
||||||
|
FROM
|
||||||
|
[dbo].[OrganizationUser] OU
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[SsoUser] SU ON SU.[UserId] = OU.[UserId] AND SU.[OrganizationId] = OU.[OrganizationId]
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[ProviderOrganization] PO ON PO.[OrganizationId] = O.[Id]
|
||||||
|
LEFT JOIN
|
||||||
|
[dbo].[Provider] P ON P.[Id] = PO.[ProviderId]
|
Loading…
Reference in New Issue
Block a user