1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

Add support for Key Connector OTP and account migration (#1663)

Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
This commit is contained in:
Oscar Hinton
2021-11-09 16:37:32 +01:00
committed by GitHub
parent f6bc35b2d0
commit fd37cb5a12
62 changed files with 3799 additions and 306 deletions

View File

@ -55,7 +55,6 @@ namespace Bit.Api.Test.Controllers
_organizationUserRepository,
_providerUserRepository,
_paymentService,
_ssoUserRepository,
_userRepository,
_userService,
_sendRepository,
@ -320,7 +319,7 @@ namespace Bit.Api.Test.Controllers
var user = GenerateExampleUser();
ConfigureUserServiceToReturnValidPrincipalFor(user);
ConfigureUserServiceToAcceptPasswordFor(user);
await _sut.ApiKey(new ApiKeyRequestModel());
await _sut.ApiKey(new SecretVerificationRequestModel());
}
[Fact]
@ -329,7 +328,7 @@ namespace Bit.Api.Test.Controllers
ConfigureUserServiceToReturnNullPrincipal();
await Assert.ThrowsAsync<UnauthorizedAccessException>(
() => _sut.ApiKey(new ApiKeyRequestModel())
() => _sut.ApiKey(new SecretVerificationRequestModel())
);
}
@ -340,7 +339,7 @@ namespace Bit.Api.Test.Controllers
ConfigureUserServiceToReturnValidPrincipalFor(user);
ConfigureUserServiceToRejectPasswordFor(user);
await Assert.ThrowsAsync<BadRequestException>(
() => _sut.ApiKey(new ApiKeyRequestModel())
() => _sut.ApiKey(new SecretVerificationRequestModel())
);
}
@ -350,7 +349,7 @@ namespace Bit.Api.Test.Controllers
var user = GenerateExampleUser();
ConfigureUserServiceToReturnValidPrincipalFor(user);
ConfigureUserServiceToAcceptPasswordFor(user);
await _sut.RotateApiKey(new ApiKeyRequestModel());
await _sut.RotateApiKey(new SecretVerificationRequestModel());
}
[Fact]
@ -359,7 +358,7 @@ namespace Bit.Api.Test.Controllers
ConfigureUserServiceToReturnNullPrincipal();
await Assert.ThrowsAsync<UnauthorizedAccessException>(
() => _sut.ApiKey(new ApiKeyRequestModel())
() => _sut.ApiKey(new SecretVerificationRequestModel())
);
}
@ -370,7 +369,7 @@ namespace Bit.Api.Test.Controllers
ConfigureUserServiceToReturnValidPrincipalFor(user);
ConfigureUserServiceToRejectPasswordFor(user);
await Assert.ThrowsAsync<BadRequestException>(
() => _sut.ApiKey(new ApiKeyRequestModel())
() => _sut.ApiKey(new SecretVerificationRequestModel())
);
}
@ -409,6 +408,8 @@ namespace Bit.Api.Test.Controllers
{
_userService.CheckPasswordAsync(user, Arg.Any<string>())
.Returns(Task.FromResult(true));
_userService.VerifySecretAsync(user, Arg.Any<string>())
.Returns(Task.FromResult(true));
}
private void ConfigureUserServiceToReturnValidIdFor(User user)

View File

@ -891,5 +891,38 @@ namespace Bit.Core.Test.Services
Assert.False(result);
Assert.Contains("Cannot autoscale on self-hosted instance", failureMessage);
}
[Theory, PaidOrganizationAutoData]
public async Task Delete_Success(Organization organization, SutProvider<OrganizationService> sutProvider)
{
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
await sutProvider.Sut.DeleteAsync(organization);
await organizationRepository.Received().DeleteAsync(organization);
await applicationCacheService.Received().DeleteOrganizationAbilityAsync(organization.Id);
}
[Theory, PaidOrganizationAutoData]
public async Task Delete_Fails_KeyConnector(Organization organization, SutProvider<OrganizationService> sutProvider,
SsoConfig ssoConfig)
{
ssoConfig.Enabled = true;
ssoConfig.SetData(new SsoConfigurationData { UseKeyConnector = true });
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
ssoConfigRepository.GetByOrganizationIdAsync(organization.Id).Returns(ssoConfig);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.DeleteAsync(organization));
Assert.Contains("You cannot delete an Organization that is using Key Connector.", exception.Message);
await organizationRepository.DidNotReceiveWithAnyArgs().DeleteAsync(default);
await applicationCacheService.DidNotReceiveWithAnyArgs().DeleteOrganizationAbilityAsync(default);
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -125,6 +126,40 @@ namespace Bit.Core.Test.Services
.UpsertAsync(default);
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveAsync_SingleOrg_KeyConnectorEnabled_ThrowsBadRequest(
[PolicyFixtures.Policy(Enums.PolicyType.SingleOrg)] Core.Models.Table.Policy policy,
SutProvider<PolicyService> sutProvider)
{
policy.Enabled = false;
SetupOrg(sutProvider, policy.OrganizationId, new Organization
{
Id = policy.OrganizationId,
UsePolicies = true,
});
var ssoConfig = new SsoConfig { Enabled = true };
var data = new SsoConfigurationData { UseKeyConnector = true };
ssoConfig.SetData(data);
sutProvider.GetDependency<ISsoConfigRepository>()
.GetByOrganizationIdAsync(policy.OrganizationId)
.Returns(ssoConfig);
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(policy,
Substitute.For<IUserService>(),
Substitute.For<IOrganizationService>(),
Guid.NewGuid()));
Assert.Contains("KeyConnector is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await sutProvider.GetDependency<IPolicyRepository>()
.DidNotReceiveWithAnyArgs()
.UpsertAsync(default);
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveAsync_RequireSsoPolicy_NotEnabled_ThrowsBadRequestAsync([PolicyFixtures.Policy(Enums.PolicyType.RequireSso)] Core.Models.Table.Policy policy, SutProvider<PolicyService> sutProvider)
{

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Exceptions;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -21,7 +22,7 @@ namespace Bit.Core.Test.Services
var ssoConfig = new SsoConfig
{
Id = 1,
Data = "TESTDATA",
Data = "{}",
Enabled = true,
OrganizationId = Guid.NewGuid(),
CreationDate = utcNow.AddDays(-10),
@ -48,7 +49,7 @@ namespace Bit.Core.Test.Services
var ssoConfig = new SsoConfig
{
Id = default,
Data = "TESTDATA",
Data = "{}",
Enabled = true,
OrganizationId = Guid.NewGuid(),
CreationDate = utcNow.AddDays(-10),
@ -66,5 +67,67 @@ namespace Bit.Core.Test.Services
Assert.True(ssoConfig.CreationDate - utcNow < TimeSpan.FromSeconds(1));
Assert.True(ssoConfig.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveAsync_PreventDisablingKeyConnector(SutProvider<SsoConfigService> sutProvider, Guid orgId)
{
var utcNow = DateTime.UtcNow;
var oldSsoConfig = new SsoConfig
{
Id = 1,
Data = "{\"useKeyConnector\": true}",
Enabled = true,
OrganizationId = orgId,
CreationDate = utcNow.AddDays(-10),
RevisionDate = utcNow.AddDays(-10),
};
var newSsoConfig = new SsoConfig
{
Id = 1,
Data = "{}",
Enabled = true,
OrganizationId = orgId,
CreationDate = utcNow.AddDays(-10),
RevisionDate = utcNow,
};
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(oldSsoConfig);
ssoConfigRepository.UpsertAsync(newSsoConfig).Returns(Task.CompletedTask);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(newSsoConfig));
Assert.Contains("KeyConnector cannot be disabled at this moment.", exception.Message);
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
.UpsertAsync(default);
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveAsync_KeyConnector_SingleOrgNotEnabled(SutProvider<SsoConfigService> sutProvider)
{
var utcNow = DateTime.UtcNow;
var ssoConfig = new SsoConfig
{
Id = default,
Data = "{\"useKeyConnector\": true}",
Enabled = true,
OrganizationId = Guid.NewGuid(),
CreationDate = utcNow.AddDays(-10),
RevisionDate = utcNow.AddDays(-10),
};
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(ssoConfig));
Assert.Contains("KeyConnector requires Single Organization to be enabled.", exception.Message);
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
.UpsertAsync(default);
}
}
}