diff --git a/bitwarden_license/src/Sso/Controllers/AccountController.cs b/bitwarden_license/src/Sso/Controllers/AccountController.cs index 7141f8429d..afbef321a9 100644 --- a/bitwarden_license/src/Sso/Controllers/AccountController.cs +++ b/bitwarden_license/src/Sso/Controllers/AccountController.cs @@ -680,22 +680,10 @@ public class AccountController : Controller ApiKey = CoreHelpers.SecureRandomString(30) }; - /* - The feature flag is checked here so that we can send the new MJML welcome email templates. - The other organization invites flows have an OrganizationUser allowing the RegisterUserCommand the ability - to fetch the Organization. The old method RegisterUser(User) here does not have that context, so we need - to use a new method RegisterSSOAutoProvisionedUserAsync(User, Organization) to send the correct email. - [PM-28057]: Prefer RegisterSSOAutoProvisionedUserAsync for SSO auto-provisioned users. - TODO: Remove Feature flag: PM-28221 - */ - if (_featureService.IsEnabled(FeatureFlagKeys.MjmlWelcomeEmailTemplates)) - { - await _registerUserCommand.RegisterSSOAutoProvisionedUserAsync(newUser, organization); - } - else - { - await _registerUserCommand.RegisterUser(newUser); - } + // Always use RegisterSSOAutoProvisionedUserAsync to ensure organization context is available + // for domain validation (BlockClaimedDomainAccountCreation policy) and welcome emails. + // The feature flag logic for welcome email templates is handled internally by RegisterUserCommand. + await _registerUserCommand.RegisterSSOAutoProvisionedUserAsync(newUser, organization); // If the organization has 2fa policy enabled, make sure to default jit user 2fa to email var twoFactorPolicy = diff --git a/bitwarden_license/test/SSO.Test/Controllers/AccountControllerTest.cs b/bitwarden_license/test/SSO.Test/Controllers/AccountControllerTest.cs index b276174814..66cb018923 100644 --- a/bitwarden_license/test/SSO.Test/Controllers/AccountControllerTest.cs +++ b/bitwarden_license/test/SSO.Test/Controllers/AccountControllerTest.cs @@ -6,7 +6,6 @@ using Bit.Core.Auth.Entities; using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Data; using Bit.Core.Auth.Repositories; -using Bit.Core.Auth.UserFeatures.Registration; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Repositories; @@ -21,7 +20,6 @@ using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using NSubstitute; @@ -1013,133 +1011,6 @@ public class AccountControllerTest } } - [Theory, BitAutoData] - public async Task AutoProvisionUserAsync_WithFeatureFlagEnabled_CallsRegisterSSOAutoProvisionedUser( - SutProvider sutProvider) - { - // Arrange - var orgId = Guid.NewGuid(); - var providerUserId = "ext-new-user"; - var email = "newuser@example.com"; - var organization = new Organization { Id = orgId, Name = "Test Org", Seats = null }; - - // No existing user (JIT provisioning scenario) - sutProvider.GetDependency().GetByEmailAsync(email).Returns((User?)null); - sutProvider.GetDependency().GetByIdAsync(orgId).Returns(organization); - sutProvider.GetDependency().GetByOrganizationEmailAsync(orgId, email) - .Returns((OrganizationUser?)null); - - // Feature flag enabled - sutProvider.GetDependency() - .IsEnabled(FeatureFlagKeys.MjmlWelcomeEmailTemplates) - .Returns(true); - - // Mock the RegisterSSOAutoProvisionedUserAsync to return success - sutProvider.GetDependency() - .RegisterSSOAutoProvisionedUserAsync(Arg.Any(), Arg.Any()) - .Returns(IdentityResult.Success); - - var claims = new[] - { - new Claim(JwtClaimTypes.Email, email), - new Claim(JwtClaimTypes.Name, "New User") - } as IEnumerable; - var config = new SsoConfigurationData(); - - var method = typeof(AccountController).GetMethod( - "CreateUserAndOrgUserConditionallyAsync", - BindingFlags.Instance | BindingFlags.NonPublic); - Assert.NotNull(method); - - // Act - var task = (Task<(User user, Organization organization, OrganizationUser orgUser)>)method!.Invoke( - sutProvider.Sut, - new object[] - { - orgId.ToString(), - providerUserId, - claims, - null!, - config - })!; - - var result = await task; - - // Assert - await sutProvider.GetDependency().Received(1) - .RegisterSSOAutoProvisionedUserAsync( - Arg.Is(u => u.Email == email && u.Name == "New User"), - Arg.Is(o => o.Id == orgId && o.Name == "Test Org")); - - Assert.NotNull(result.user); - Assert.Equal(email, result.user.Email); - Assert.Equal(organization.Id, result.organization.Id); - } - - [Theory, BitAutoData] - public async Task AutoProvisionUserAsync_WithFeatureFlagDisabled_CallsRegisterUserInstead( - SutProvider sutProvider) - { - // Arrange - var orgId = Guid.NewGuid(); - var providerUserId = "ext-legacy-user"; - var email = "legacyuser@example.com"; - var organization = new Organization { Id = orgId, Name = "Test Org", Seats = null }; - - // No existing user (JIT provisioning scenario) - sutProvider.GetDependency().GetByEmailAsync(email).Returns((User?)null); - sutProvider.GetDependency().GetByIdAsync(orgId).Returns(organization); - sutProvider.GetDependency().GetByOrganizationEmailAsync(orgId, email) - .Returns((OrganizationUser?)null); - - // Feature flag disabled - sutProvider.GetDependency() - .IsEnabled(FeatureFlagKeys.MjmlWelcomeEmailTemplates) - .Returns(false); - - // Mock the RegisterUser to return success - sutProvider.GetDependency() - .RegisterUser(Arg.Any()) - .Returns(IdentityResult.Success); - - var claims = new[] - { - new Claim(JwtClaimTypes.Email, email), - new Claim(JwtClaimTypes.Name, "Legacy User") - } as IEnumerable; - var config = new SsoConfigurationData(); - - var method = typeof(AccountController).GetMethod( - "CreateUserAndOrgUserConditionallyAsync", - BindingFlags.Instance | BindingFlags.NonPublic); - Assert.NotNull(method); - - // Act - var task = (Task<(User user, Organization organization, OrganizationUser orgUser)>)method!.Invoke( - sutProvider.Sut, - new object[] - { - orgId.ToString(), - providerUserId, - claims, - null!, - config - })!; - - var result = await task; - - // Assert - await sutProvider.GetDependency().Received(1) - .RegisterUser(Arg.Is(u => u.Email == email && u.Name == "Legacy User")); - - // Verify the new method was NOT called - await sutProvider.GetDependency().DidNotReceive() - .RegisterSSOAutoProvisionedUserAsync(Arg.Any(), Arg.Any()); - - Assert.NotNull(result.user); - Assert.Equal(email, result.user.Email); - } - [Theory, BitAutoData] public void ExternalChallenge_WithMatchingOrgId_Succeeds( SutProvider sutProvider,