mirror of
https://github.com/bitwarden/server.git
synced 2024-11-24 12:35:25 +01:00
EC-198 Added feature flag for 2FA Email for new device login (#1993)
* EC-198 added global setting flag for 2FA email on new device login feature * EC-198 Removed is development environment check on 2FA email new device login given that we can now rely on the global settings feature flag * EC-198 Improved IGlobalSettings and UserService code for testing
This commit is contained in:
parent
bbb55ef8de
commit
2e2d3075d1
@ -17,9 +17,7 @@ using Bit.Core.Utilities;
|
|||||||
using Fido2NetLib;
|
using Fido2NetLib;
|
||||||
using Fido2NetLib.Objects;
|
using Fido2NetLib.Objects;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using File = System.IO.File;
|
using File = System.IO.File;
|
||||||
@ -50,11 +48,10 @@ namespace Bit.Core.Services
|
|||||||
private readonly IReferenceEventService _referenceEventService;
|
private readonly IReferenceEventService _referenceEventService;
|
||||||
private readonly IFido2 _fido2;
|
private readonly IFido2 _fido2;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly IGlobalSettings _globalSettings;
|
||||||
private readonly IOrganizationService _organizationService;
|
private readonly IOrganizationService _organizationService;
|
||||||
private readonly IProviderUserRepository _providerUserRepository;
|
private readonly IProviderUserRepository _providerUserRepository;
|
||||||
private readonly IDeviceRepository _deviceRepository;
|
private readonly IDeviceRepository _deviceRepository;
|
||||||
private readonly IWebHostEnvironment _environment;
|
|
||||||
|
|
||||||
public UserService(
|
public UserService(
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
@ -81,11 +78,10 @@ namespace Bit.Core.Services
|
|||||||
IReferenceEventService referenceEventService,
|
IReferenceEventService referenceEventService,
|
||||||
IFido2 fido2,
|
IFido2 fido2,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
GlobalSettings globalSettings,
|
IGlobalSettings globalSettings,
|
||||||
IOrganizationService organizationService,
|
IOrganizationService organizationService,
|
||||||
IProviderUserRepository providerUserRepository,
|
IProviderUserRepository providerUserRepository,
|
||||||
IDeviceRepository deviceRepository,
|
IDeviceRepository deviceRepository)
|
||||||
IWebHostEnvironment environment)
|
|
||||||
: base(
|
: base(
|
||||||
store,
|
store,
|
||||||
optionsAccessor,
|
optionsAccessor,
|
||||||
@ -121,7 +117,6 @@ namespace Bit.Core.Services
|
|||||||
_organizationService = organizationService;
|
_organizationService = organizationService;
|
||||||
_providerUserRepository = providerUserRepository;
|
_providerUserRepository = providerUserRepository;
|
||||||
_deviceRepository = deviceRepository;
|
_deviceRepository = deviceRepository;
|
||||||
_environment = environment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid? GetProperUserId(ClaimsPrincipal principal)
|
public Guid? GetProperUserId(ClaimsPrincipal principal)
|
||||||
@ -1422,9 +1417,9 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task<bool> Needs2FABecauseNewDeviceAsync(User user, string deviceIdentifier, string grantType)
|
public async Task<bool> Needs2FABecauseNewDeviceAsync(User user, string deviceIdentifier, string grantType)
|
||||||
{
|
{
|
||||||
return user.EmailVerified
|
return _globalSettings.TwoFactorAuth.EmailOnNewDeviceLogin
|
||||||
|
&& user.EmailVerified
|
||||||
&& grantType != "authorization_code"
|
&& grantType != "authorization_code"
|
||||||
&& !_environment.IsDevelopment()
|
|
||||||
&& await IsNewDeviceAndNotTheFirstOneAsync(user, deviceIdentifier);
|
&& await IsNewDeviceAndNotTheFirstOneAsync(user, deviceIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ namespace Bit.Core.Settings
|
|||||||
public virtual AppleIapSettings AppleIap { get; set; } = new AppleIapSettings();
|
public virtual AppleIapSettings AppleIap { get; set; } = new AppleIapSettings();
|
||||||
public virtual SsoSettings Sso { get; set; } = new SsoSettings();
|
public virtual SsoSettings Sso { get; set; } = new SsoSettings();
|
||||||
public virtual StripeSettings Stripe { get; set; } = new StripeSettings();
|
public virtual StripeSettings Stripe { get; set; } = new StripeSettings();
|
||||||
|
public virtual ITwoFactorAuthSettings TwoFactorAuth { get; set; } = new TwoFactorAuthSettings();
|
||||||
|
|
||||||
public string BuildExternalUri(string explicitValue, string name)
|
public string BuildExternalUri(string explicitValue, string name)
|
||||||
{
|
{
|
||||||
@ -480,5 +481,10 @@ namespace Bit.Core.Settings
|
|||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
public int MaxNetworkRetries { get; set; } = 2;
|
public int MaxNetworkRetries { get; set; } = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TwoFactorAuthSettings : ITwoFactorAuthSettings
|
||||||
|
{
|
||||||
|
public bool EmailOnNewDeviceLogin { get; set; } = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using static Bit.Core.Settings.GlobalSettings;
|
namespace Bit.Core.Settings
|
||||||
|
|
||||||
namespace Bit.Core.Settings
|
|
||||||
{
|
{
|
||||||
public interface IGlobalSettings
|
public interface IGlobalSettings
|
||||||
{
|
{
|
||||||
@ -10,9 +8,11 @@ namespace Bit.Core.Settings
|
|||||||
string LicenseDirectory { get; set; }
|
string LicenseDirectory { get; set; }
|
||||||
string LicenseCertificatePassword { get; set; }
|
string LicenseCertificatePassword { get; set; }
|
||||||
int OrganizationInviteExpirationHours { get; set; }
|
int OrganizationInviteExpirationHours { get; set; }
|
||||||
|
bool DisableUserRegistration { get; set; }
|
||||||
IInstallationSettings Installation { get; set; }
|
IInstallationSettings Installation { get; set; }
|
||||||
IFileStorageSettings Attachment { get; set; }
|
IFileStorageSettings Attachment { get; set; }
|
||||||
IConnectionStringSettings Storage { get; set; }
|
IConnectionStringSettings Storage { get; set; }
|
||||||
IBaseServiceUriSettings BaseServiceUri { get; set; }
|
IBaseServiceUriSettings BaseServiceUri { get; set; }
|
||||||
|
ITwoFactorAuthSettings TwoFactorAuth { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
src/Core/Settings/ITwoFactorAuthSettings.cs
Normal file
7
src/Core/Settings/ITwoFactorAuthSettings.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Bit.Core.Settings
|
||||||
|
{
|
||||||
|
public interface ITwoFactorAuthSettings
|
||||||
|
{
|
||||||
|
bool EmailOnNewDeviceLogin { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -12,9 +12,7 @@ using Bit.Core.Services;
|
|||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using Bit.Test.Common.Helpers;
|
using Bit.Test.Common.Helpers;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using NSubstitute.ReceivedExtensions;
|
using NSubstitute.ReceivedExtensions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -38,8 +36,8 @@ namespace Bit.Core.Test.Services
|
|||||||
user.EmailVerified = true;
|
user.EmailVerified = true;
|
||||||
user.Email = userLicense.Email;
|
user.Email = userLicense.Email;
|
||||||
|
|
||||||
sutProvider.GetDependency<Settings.GlobalSettings>().SelfHosted = true;
|
sutProvider.GetDependency<Settings.IGlobalSettings>().SelfHosted = true;
|
||||||
sutProvider.GetDependency<Settings.GlobalSettings>().LicenseDirectory = tempDir.Directory;
|
sutProvider.GetDependency<Settings.IGlobalSettings>().LicenseDirectory = tempDir.Directory;
|
||||||
sutProvider.GetDependency<ILicensingService>()
|
sutProvider.GetDependency<ILicensingService>()
|
||||||
.VerifyLicense(userLicense)
|
.VerifyLicense(userLicense)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
@ -175,6 +173,9 @@ namespace Bit.Core.Test.Services
|
|||||||
new Device { Identifier = deviceIdInRepo }
|
new Device { Identifier = deviceIdInRepo }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||||
|
|
||||||
Assert.True(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
Assert.True(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +247,7 @@ namespace Bit.Core.Test.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Environment_Is_Development(SutProvider<UserService> sutProvider, User user)
|
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||||
{
|
{
|
||||||
user.Id = Guid.NewGuid();
|
user.Id = Guid.NewGuid();
|
||||||
user.EmailVerified = true;
|
user.EmailVerified = true;
|
||||||
@ -260,9 +261,7 @@ namespace Bit.Core.Test.Services
|
|||||||
new Device { Identifier = deviceIdInRepo }
|
new Device { Identifier = deviceIdInRepo }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sutProvider.GetDependency<IWebHostEnvironment>()
|
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(false);
|
||||||
.EnvironmentName
|
|
||||||
.Returns(Environments.Development);
|
|
||||||
|
|
||||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user