Skip to content

Commit ead5bbd

Browse files
[PM-21281] Email TOTP sent twice when user only has Email MFA enabled (#5782)
* fix: addressed bug where email token is sent twice, * test: updating tests to have correct DI and removing test for automatic email of TOTP.
1 parent 3f95513 commit ead5bbd

File tree

3 files changed

+11
-15
lines changed

3 files changed

+11
-15
lines changed

src/Core/Auth/Models/Business/Tokenables/SsoEmail2faSessionTokenable.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
namespace Bit.Core.Auth.Models.Business.Tokenables;
66

7-
// This token just provides a verifiable authN mechanism for the API service
8-
// TwoFactorController.cs SendEmailLogin anonymous endpoint so it cannot be
9-
// used maliciously.
7+
/// <summary>
8+
/// This token provides a verifiable authN mechanism for the TwoFactorController.SendEmailLoginAsync
9+
/// anonymous endpoint so it cannot used maliciously.
10+
/// </summary>
1011
public class SsoEmail2faSessionTokenable : ExpiringTokenable
1112
{
1213
// Just over 2 min expiration (client expires session after 2 min)

src/Identity/IdentityServer/RequestValidators/TwoFactorAuthenticationValidator.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ public async Task<Dictionary<string, object>> BuildTwoFactorResultAsync(User use
9191
{ "TwoFactorProviders2", providers },
9292
};
9393

94-
// If we have email as a 2FA provider, we might need an SsoEmail2fa Session Token
94+
// If we have an Email 2FA provider we need this session token so SSO users
95+
// can re-request an email TOTP. The TwoFactorController.SendEmailLoginAsync
96+
// endpoint requires a way to authenticate the user before sending another email with
97+
// a TOTP, this token acts as the authentication mechanism.
9598
if (enabledProviders.Any(p => p.Key == TwoFactorProviderType.Email))
9699
{
97100
twoFactorResultDict.Add("SsoEmail2faSessionToken",
@@ -100,12 +103,6 @@ public async Task<Dictionary<string, object>> BuildTwoFactorResultAsync(User use
100103
twoFactorResultDict.Add("Email", user.Email);
101104
}
102105

103-
if (enabledProviders.Count == 1 && enabledProviders.First().Key == TwoFactorProviderType.Email)
104-
{
105-
// Send email now if this is their only 2FA method
106-
await _userService.SendTwoFactorEmailAsync(user);
107-
}
108-
109106
return twoFactorResultDict;
110107
}
111108

test/Identity.Test/IdentityServer/TwoFactorAuthenticationValidatorTests.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ public async void BuildTwoFactorResultAsync_IndividualProviders_ReturnsNotNull(
252252

253253
[Theory]
254254
[BitAutoData(TwoFactorProviderType.Email)]
255-
public async void BuildTwoFactorResultAsync_IndividualEmailProvider_SendsEmail_SetsSsoToken_ReturnsNotNull(
256-
TwoFactorProviderType providerType,
257-
User user)
255+
public async void BuildTwoFactorResultAsync_SetsSsoToken_ReturnsNotNull(
256+
TwoFactorProviderType providerType,
257+
User user)
258258
{
259259
// Arrange
260260
var providerTypeInt = (int)providerType;
@@ -276,8 +276,6 @@ public async void BuildTwoFactorResultAsync_IndividualEmailProvider_SendsEmail_S
276276
Assert.True(providers.ContainsKey(providerTypeInt.ToString()));
277277
Assert.True(result.ContainsKey("SsoEmail2faSessionToken"));
278278
Assert.True(result.ContainsKey("Email"));
279-
280-
await _userService.Received(1).SendTwoFactorEmailAsync(Arg.Any<User>());
281279
}
282280

283281
[Theory]

0 commit comments

Comments
 (0)