From e679d3127abfd976e3af3d02783d869da77fb590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Wed, 30 Aug 2023 07:23:45 +0100 Subject: [PATCH] [AC-1585] Automatically verify managed members on an organization with a verified domain (#3207) --- .../src/Sso/Controllers/AccountController.cs | 15 ++++++++++- src/Core/Utilities/CoreHelpers.cs | 25 +++++++++++++++---- test/Core.Test/Utilities/CoreHelpersTests.cs | 21 ++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/bitwarden_license/src/Sso/Controllers/AccountController.cs b/bitwarden_license/src/Sso/Controllers/AccountController.cs index f9bb77837..40d4d1f42 100644 --- a/bitwarden_license/src/Sso/Controllers/AccountController.cs +++ b/bitwarden_license/src/Sso/Controllers/AccountController.cs @@ -47,6 +47,7 @@ public class AccountController : Controller private readonly IGlobalSettings _globalSettings; private readonly Core.Services.IEventService _eventService; private readonly IDataProtectorTokenFactory _dataProtector; + private readonly IOrganizationDomainRepository _organizationDomainRepository; public AccountController( IAuthenticationSchemeProvider schemeProvider, @@ -65,7 +66,8 @@ public class AccountController : Controller UserManager userManager, IGlobalSettings globalSettings, Core.Services.IEventService eventService, - IDataProtectorTokenFactory dataProtector) + IDataProtectorTokenFactory dataProtector, + IOrganizationDomainRepository organizationDomainRepository) { _schemeProvider = schemeProvider; _clientStore = clientStore; @@ -84,6 +86,7 @@ public class AccountController : Controller _eventService = eventService; _globalSettings = globalSettings; _dataProtector = dataProtector; + _organizationDomainRepository = organizationDomainRepository; } [HttpGet] @@ -513,11 +516,21 @@ public class AccountController : Controller } } + // If the email domain is verified, we can mark the email as verified + var emailVerified = false; + var emailDomain = CoreHelpers.GetEmailDomain(email); + if (!string.IsNullOrWhiteSpace(emailDomain)) + { + var organizationDomain = await _organizationDomainRepository.GetDomainByOrgIdAndDomainNameAsync(orgId, emailDomain); + emailVerified = organizationDomain?.VerifiedDate.HasValue ?? false; + } + // Create user record - all existing user flows are handled above var user = new User { Name = name, Email = email, + EmailVerified = emailVerified, ApiKey = CoreHelpers.SecureRandomString(30) }; await _userService.RegisterUserAsync(user); diff --git a/src/Core/Utilities/CoreHelpers.cs b/src/Core/Utilities/CoreHelpers.cs index addc21339..c128fa8e4 100644 --- a/src/Core/Utilities/CoreHelpers.cs +++ b/src/Core/Utilities/CoreHelpers.cs @@ -50,20 +50,20 @@ public static class CoreHelpers { var guidArray = startingGuid.ToByteArray(); - // Get the days and milliseconds which will be used to build the byte string + // Get the days and milliseconds which will be used to build the byte string var days = new TimeSpan(time.Ticks - _baseDateTicks); var msecs = time.TimeOfDay; - // Convert to a byte array - // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333 + // Convert to a byte array + // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333 var daysArray = BitConverter.GetBytes(days.Days); var msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds / 3.333333)); - // Reverse the bytes to match SQL Servers ordering + // Reverse the bytes to match SQL Servers ordering Array.Reverse(daysArray); Array.Reverse(msecsArray); - // Copy the bytes into the guid + // Copy the bytes into the guid Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2); Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4); @@ -817,4 +817,19 @@ public static class CoreHelpers .ToString(); } + + public static string GetEmailDomain(string email) + { + if (!string.IsNullOrWhiteSpace(email)) + { + var emailParts = email.Split('@', StringSplitOptions.RemoveEmptyEntries); + + if (emailParts.Length == 2) + { + return emailParts[1].Trim(); + } + } + + return null; + } } diff --git a/test/Core.Test/Utilities/CoreHelpersTests.cs b/test/Core.Test/Utilities/CoreHelpersTests.cs index b4a4034d9..4def69404 100644 --- a/test/Core.Test/Utilities/CoreHelpersTests.cs +++ b/test/Core.Test/Utilities/CoreHelpersTests.cs @@ -416,4 +416,25 @@ public class CoreHelpersTests { Assert.Equal(expected, CoreHelpers.ObfuscateEmail(input)); } + + [Theory] + [InlineData("user@example.com")] + [InlineData("user@example.com ")] + [InlineData("user.name@example.com")] + public void GetEmailDomain_Success(string email) + { + Assert.Equal("example.com", CoreHelpers.GetEmailDomain(email)); + } + + [Theory] + [InlineData("")] + [InlineData(null)] + [InlineData("userexample.com")] + [InlineData("user@")] + [InlineData("@example.com")] + [InlineData("user@ex@ample.com")] + public void GetEmailDomain_ReturnsNull(string wrongEmail) + { + Assert.Null(CoreHelpers.GetEmailDomain(wrongEmail)); + } }