diff --git a/src/Core/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenable.cs b/src/Core/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenable.cs index 6dbb7bae3e4b..7714abb283d7 100644 --- a/src/Core/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenable.cs +++ b/src/Core/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenable.cs @@ -10,23 +10,18 @@ namespace Bit.Core.Auth.Models.Business.Tokenables; public class SsoEmail2faSessionTokenable : ExpiringTokenable { // Just over 2 min expiration (client expires session after 2 min) - private const double _tokenLifetimeInMinutes = 2.05; - public static TimeSpan GetTokenLifetime() => TimeSpan.FromMinutes(_tokenLifetimeInMinutes); - + private static readonly TimeSpan _tokenLifetime = TimeSpan.FromMinutes(2.05); public const string ClearTextPrefix = "BwSsoEmail2FaSessionToken_"; public const string DataProtectorPurpose = "SsoEmail2faSessionTokenDataProtector"; public const string TokenIdentifier = "SsoEmail2faSessionToken"; - public string Identifier { get; set; } = TokenIdentifier; public Guid Id { get; set; } public string Email { get; set; } - - [JsonConstructor] public SsoEmail2faSessionTokenable() { - ExpirationDate = DateTime.UtcNow.Add(GetTokenLifetime()); + ExpirationDate = DateTime.UtcNow.Add(_tokenLifetime); } public SsoEmail2faSessionTokenable(User user) : this() @@ -34,14 +29,12 @@ public SsoEmail2faSessionTokenable(User user) : this() Id = user?.Id ?? default; Email = user?.Email; } - public bool TokenIsValid(User user) { if (Id == default || Email == default || user == null) { return false; } - return Id == user.Id && Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase); } diff --git a/test/Core.Test/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenableTests.cs b/test/Core.Test/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenableTests.cs deleted file mode 100644 index 0274b666c590..000000000000 --- a/test/Core.Test/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenableTests.cs +++ /dev/null @@ -1,173 +0,0 @@ -using AutoFixture.Xunit2; -using Bit.Core.Auth.Models.Business.Tokenables; -using Bit.Core.Entities; -using Bit.Core.Tokens; -using Xunit; -namespace Bit.Core.Test.Auth.Models.Business.Tokenables; - -// Note: test names follow MethodName_StateUnderTest_ExpectedBehavior pattern. -public class SsoEmail2faSessionTokenableTests -{ - // Allow a small tolerance for possible execution delays or clock precision. - private readonly TimeSpan _timeTolerance = TimeSpan.FromMilliseconds(10); - - /// - /// Tests the default constructor behavior when passed a null user. - /// - [Fact] - public void Constructor_NullUser_PropertiesSetToDefault() - { - var token = new SsoEmail2faSessionTokenable(null); - - Assert.Equal(default, token.Id); - Assert.Equal(default, token.Email); - } - - /// - /// Tests that when a valid user is provided to the constructor, the resulting token properties match the user. - /// - [Theory, AutoData] - public void Constructor_ValidUser_PropertiesSetFromUser(User user) - { - var token = new SsoEmail2faSessionTokenable(user); - - Assert.Equal(user.Id, token.Id); - Assert.Equal(user.Email, token.Email); - } - - /// - /// Tests the default expiration behavior immediately after initialization. - /// - [Fact] - public void Constructor_AfterInitialization_ExpirationSetToExpectedDuration() - { - var token = new SsoEmail2faSessionTokenable(); - var expectedExpiration = DateTime.UtcNow + SsoEmail2faSessionTokenable.GetTokenLifetime(); - - Assert.True(expectedExpiration - token.ExpirationDate < _timeTolerance); - } - - /// - /// Tests that a custom expiration date is preserved after token initialization. - /// - [Fact] - public void Constructor_CustomExpirationDate_ExpirationMatchesProvidedValue() - { - var customExpiration = DateTime.UtcNow.AddHours(3); - var token = new SsoEmail2faSessionTokenable - { - ExpirationDate = customExpiration - }; - - Assert.True(Math.Abs((customExpiration - token.ExpirationDate).TotalMilliseconds) < _timeTolerance.TotalMilliseconds); - } - - /// - /// Tests the validity of a token initialized with a null user. - /// - [Fact] - public void Valid_NullUser_ReturnsFalse() - { - var token = new SsoEmail2faSessionTokenable(null); - - Assert.False(token.Valid); - } - - /// - /// Tests the validity of a token with a non-matching identifier. - /// - [Theory, AutoData] - public void Valid_WrongIdentifier_ReturnsFalse(User user) - { - var token = new SsoEmail2faSessionTokenable(user) - { - Identifier = "not correct" - }; - - Assert.False(token.Valid); - } - - /// - /// Tests the token validity when user ID is null. - /// - [Theory, AutoData] - public void TokenIsValid_NullUserId_ReturnsFalse(User user) - { - user.Id = default; // Guid.Empty - var token = new SsoEmail2faSessionTokenable(user); - - Assert.False(token.TokenIsValid(user)); - } - - /// - /// Tests the token validity when user's email is null. - /// - [Theory, AutoData] - public void TokenIsValid_NullEmail_ReturnsFalse(User user) - { - user.Email = null; - var token = new SsoEmail2faSessionTokenable(user); - - Assert.False(token.TokenIsValid(user)); - } - - /// - /// Tests the token validity when user ID and email match the token properties. - /// - [Theory, AutoData] - public void TokenIsValid_MatchingUserIdAndEmail_ReturnsTrue(User user) - { - var token = new SsoEmail2faSessionTokenable(user); - - Assert.True(token.TokenIsValid(user)); - } - - /// - /// Ensures that the token is invalid when the provided user's ID doesn't match the token's ID. - /// - [Theory, AutoData] - public void TokenIsValid_WrongUserId_ReturnsFalse(User user) - { - // Given a token initialized with a user's details - var token = new SsoEmail2faSessionTokenable(user); - - // modify the user's ID - user.Id = Guid.NewGuid(); - - // Then the token should be considered invalid - Assert.False(token.TokenIsValid(user)); - } - - /// - /// Ensures that the token is invalid when the provided user's email doesn't match the token's email. - /// - [Theory, AutoData] - public void TokenIsValid_WrongEmail_ReturnsFalse(User user) - { - // Given a token initialized with a user's details - var token = new SsoEmail2faSessionTokenable(user); - - // modify the user's email - user.Email = "nonMatchingEmail@example.com"; - - // Then the token should be considered invalid - Assert.False(token.TokenIsValid(user)); - } - - /// - /// Tests the deserialization of a token to ensure that the expiration date is preserved. - /// - [Theory, AutoData] - public void FromToken_SerializedToken_PreservesExpirationDate(User user) - { - var expectedDateTime = DateTime.UtcNow.AddHours(-5); - var token = new SsoEmail2faSessionTokenable(user) - { - ExpirationDate = expectedDateTime - }; - - var result = Tokenable.FromToken(token.ToToken()); - - Assert.Equal(expectedDateTime, result.ExpirationDate, precision: _timeTolerance); - } -}