From 85b299ccfce49563d46dfbc25ae295cc0a4207a0 Mon Sep 17 00:00:00 2001
From: Ike <137194738+ike-kottlowski@users.noreply.github.com>
Date: Fri, 21 Mar 2025 18:18:17 -0400
Subject: [PATCH] feat : matching request email to session email (#5541)
* feat : matching request email to session email
* feat : implement AuthRequestHeaderValidator
* fix : matching table definitions between migrator and sql project.
* fix : fixing tests
---
.../AuthRequestHeaderValidator.cs | 39 +++++++++++++++++++
.../IAuthRequestHeaderValidator.cs | 12 ++++++
.../OpaqueKeyExchangeGrantValidator.cs | 19 +++++----
.../ResourceOwnerPasswordValidator.cs | 33 +++-------------
.../Utilities/ServiceCollectionExtensions.cs | 1 +
.../Utilities/ServiceCollectionExtensions.cs | 2 +-
.../Tables/OpaqueKeyExchangeCredential.sql | 2 +-
.../openid-configuration.json | 3 +-
...0_00_CreateOpaqueKeyExchangeCredential.sql | 6 ---
9 files changed, 73 insertions(+), 44 deletions(-)
create mode 100644 src/Identity/IdentityServer/RequestValidators/AuthRequestHeaderValidator.cs
create mode 100644 src/Identity/IdentityServer/RequestValidators/IAuthRequestHeaderValidator.cs
diff --git a/src/Identity/IdentityServer/RequestValidators/AuthRequestHeaderValidator.cs b/src/Identity/IdentityServer/RequestValidators/AuthRequestHeaderValidator.cs
new file mode 100644
index 0000000000..5beb6e0537
--- /dev/null
+++ b/src/Identity/IdentityServer/RequestValidators/AuthRequestHeaderValidator.cs
@@ -0,0 +1,39 @@
+using Bit.Core.Context;
+using Bit.Core.Utilities;
+
+namespace Bit.Identity.IdentityServer.RequestValidators;
+
+public class AuthRequestHeaderValidator : IAuthRequestHeaderValidator
+{
+ private readonly ICurrentContext _currentContext;
+
+ public AuthRequestHeaderValidator(ICurrentContext currentContext)
+ {
+ _currentContext = currentContext;
+ }
+
+ public bool ValidateAuthEmailHeader(string userEmail)
+ {
+ if (_currentContext.HttpContext.Request.Headers.TryGetValue("Auth-Email", out var authEmailHeader))
+ {
+ try
+ {
+ var authEmailDecoded = CoreHelpers.Base64UrlDecodeString(authEmailHeader);
+ if (authEmailDecoded != userEmail)
+ {
+ return false;
+ }
+ }
+ catch (Exception e) when (e is InvalidOperationException || e is FormatException)
+ {
+ // Invalid B64 encoding
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/Identity/IdentityServer/RequestValidators/IAuthRequestHeaderValidator.cs b/src/Identity/IdentityServer/RequestValidators/IAuthRequestHeaderValidator.cs
new file mode 100644
index 0000000000..80b6660aa1
--- /dev/null
+++ b/src/Identity/IdentityServer/RequestValidators/IAuthRequestHeaderValidator.cs
@@ -0,0 +1,12 @@
+namespace Bit.Identity.IdentityServer.RequestValidators;
+
+public interface IAuthRequestHeaderValidator
+{
+ ///
+ /// This method matches the Email in the header the input email. Implementation depends on
+ /// GrantValidator.
+ ///
+ /// email fetched by grantValidator
+ /// true if the emails match false otherwise
+ bool ValidateAuthEmailHeader(string userEmail);
+}
diff --git a/src/Identity/IdentityServer/RequestValidators/OpaqueKeyExchangeGrantValidator.cs b/src/Identity/IdentityServer/RequestValidators/OpaqueKeyExchangeGrantValidator.cs
index 42f30eb82d..4e8c38b725 100644
--- a/src/Identity/IdentityServer/RequestValidators/OpaqueKeyExchangeGrantValidator.cs
+++ b/src/Identity/IdentityServer/RequestValidators/OpaqueKeyExchangeGrantValidator.cs
@@ -19,6 +19,7 @@ public class OpaqueKeyExchangeGrantValidator : BaseRequestValidator userManager,
@@ -28,15 +29,16 @@ public class OpaqueKeyExchangeGrantValidator : BaseRequestValidator logger,
+ ILogger logger,
ICurrentContext currentContext,
GlobalSettings globalSettings,
- ISsoConfigRepository ssoConfigRepository,
IUserRepository userRepository,
IPolicyService policyService,
IFeatureService featureService,
+ ISsoConfigRepository ssoConfigRepository,
IUserDecryptionOptionsBuilder userDecryptionOptionsBuilder,
- IOpaqueKeyExchangeService opaqueKeyExchangeService)
+ IOpaqueKeyExchangeService opaqueKeyExchangeService,
+ IAuthRequestHeaderValidator authRequestHeaderValidator)
: base(
userManager,
userService,
@@ -56,6 +58,7 @@ public class OpaqueKeyExchangeGrantValidator : BaseRequestValidator "opaque-ke";
@@ -81,10 +84,12 @@ public class OpaqueKeyExchangeGrantValidator : BaseRequestValidator userManager,
IUserService userService,
@@ -40,7 +41,8 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
var issuerUri = new Uri(globalSettings.BaseServiceUri.InternalIdentity);
var identityServerBuilder = services
diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs
index 3255d1044b..66bdba2903 100644
--- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs
+++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs
@@ -110,7 +110,7 @@ public static class ServiceCollectionExtensions
public static void AddBaseServices(this IServiceCollection services, IGlobalSettings globalSettings)
{
services.AddScoped();
- services.AddSingleton();
+ services.AddScoped();
services.AddUserServices(globalSettings);
services.AddTrialInitiationServices();
services.AddOrganizationServices(globalSettings);
diff --git a/src/Sql/Auth/dbo/Tables/OpaqueKeyExchangeCredential.sql b/src/Sql/Auth/dbo/Tables/OpaqueKeyExchangeCredential.sql
index 8e7f23f124..caacd157cf 100644
--- a/src/Sql/Auth/dbo/Tables/OpaqueKeyExchangeCredential.sql
+++ b/src/Sql/Auth/dbo/Tables/OpaqueKeyExchangeCredential.sql
@@ -8,7 +8,7 @@
[EncryptedPrivateKey] VARCHAR(MAX) NOT NULL,
[EncryptedUserKey] VARCHAR(MAX) NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
- CONSTRAINT [PK_OpaqueKeyExchangeCredential] PRIMARY KEY CLUSTERED ([Id] ASC),
+ CONSTRAINT [PK_OpaqueKeyExchangeCredential] PRIMARY KEY CLUSTERED ([UserId]),
CONSTRAINT [FK_OpaqueKeyExchangeCredential_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
);
diff --git a/test/Identity.IntegrationTest/openid-configuration.json b/test/Identity.IntegrationTest/openid-configuration.json
index 4d74f66009..7d67f09f50 100644
--- a/test/Identity.IntegrationTest/openid-configuration.json
+++ b/test/Identity.IntegrationTest/openid-configuration.json
@@ -43,7 +43,8 @@
"password",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:openid:params:grant-type:ciba",
- "webauthn"
+ "webauthn",
+ "opaque-ke"
],
"response_types_supported": [
"code",
diff --git a/util/Migrator/DbScripts/2025-03-20_00_CreateOpaqueKeyExchangeCredential.sql b/util/Migrator/DbScripts/2025-03-20_00_CreateOpaqueKeyExchangeCredential.sql
index 8b2850eeb2..4fbb5dcc69 100644
--- a/util/Migrator/DbScripts/2025-03-20_00_CreateOpaqueKeyExchangeCredential.sql
+++ b/util/Migrator/DbScripts/2025-03-20_00_CreateOpaqueKeyExchangeCredential.sql
@@ -1,8 +1,3 @@
-
-
-
-
-
IF OBJECT_ID('[dbo].[OpaqueKeyExchangeCredential]') IS NULL
BEGIN
CREATE TABLE [dbo].[OpaqueKeyExchangeCredential]
@@ -28,7 +23,6 @@ BEGIN
END
GO
-
CREATE OR ALTER PROCEDURE [dbo].[OpaqueKeyExchangeCredential_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@UserId UNIQUEIDENTIFIER,