diff --git a/src/Core/Resolvers/MsSqlQueryExecutor.cs b/src/Core/Resolvers/MsSqlQueryExecutor.cs
index b4f84757b3..4a2deb4394 100644
--- a/src/Core/Resolvers/MsSqlQueryExecutor.cs
+++ b/src/Core/Resolvers/MsSqlQueryExecutor.cs
@@ -516,6 +516,7 @@ public override string GetSessionParamsQuery(HttpContext? httpContext, IDictiona
// Counter to generate different param name for each of the sessionParam.
IncrementingInteger counter = new();
+ const string SESSION_KEY_NAME = $"{BaseQueryStructure.PARAM_NAME_PREFIX}session_key";
const string SESSION_PARAM_NAME = $"{BaseQueryStructure.PARAM_NAME_PREFIX}session_param";
StringBuilder sessionMapQuery = new();
@@ -528,10 +529,12 @@ public override string GetSessionParamsQuery(HttpContext? httpContext, IDictiona
foreach ((string claimType, string claimValue) in sessionParams)
{
+ string keyName = $"{SESSION_KEY_NAME}{counter.Current()}";
string paramName = $"{SESSION_PARAM_NAME}{counter.Next()}";
+ parameters.Add(keyName, new(claimType));
parameters.Add(paramName, new(claimValue));
// Append statement to set read only param value - can be set only once for a connection.
- string statementToSetReadOnlyParam = "EXEC sp_set_session_context " + $"'{claimType}', " + paramName + ", @read_only = 0;";
+ string statementToSetReadOnlyParam = "EXEC sp_set_session_context " + keyName + ", " + paramName + ", @read_only = 0;";
sessionMapQuery = sessionMapQuery.Append(statementToSetReadOnlyParam);
}
}
diff --git a/src/Service.Tests/Authentication/EasyAuthAuthenticationUnitTests.cs b/src/Service.Tests/Authentication/EasyAuthAuthenticationUnitTests.cs
index 35ef925dab..5a84f746dc 100644
--- a/src/Service.Tests/Authentication/EasyAuthAuthenticationUnitTests.cs
+++ b/src/Service.Tests/Authentication/EasyAuthAuthenticationUnitTests.cs
@@ -2,9 +2,11 @@
// Licensed under the MIT License.
#nullable enable
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Azure.DataApiBuilder.Config.ObjectModel;
@@ -344,6 +346,50 @@ await SendRequestAndGetHttpContextState(
ignoreCase: true);
}
+ ///
+ /// Tests we ensure that an invalid query in the EasyAuth header does not result in a successful request.
+ ///
+ [TestMethod]
+ public async Task TestInvalidQueryInHeader()
+ {
+ string header = @"
+ {
+ ""auth_typ"":""aad"",
+ ""claims"":[
+ {
+ ""typ"":""x', N'v';
+ SET IDENTITY_INSERT authors ON;
+ INSERT INTO authors (id, name, birthdate) VALUES (10001, 'Hidden Author', '2001-01-01');
+ SET IDENTITY_INSERT authors OFF;
+ SELECT 1 AS inserted FOR JSON PATH, WITHOUT_ARRAY_WRAPPER;
+ --"",
+ ""val"":""x""
+ }
+ ]
+ }";
+
+ string generatedToken = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(header));
+ HttpContext postMiddlewareContext =
+ await SendRequestAndGetHttpContextState(
+ generatedToken,
+ EasyAuthType.StaticWebApps,
+ clientRoleHeader: "authenticated");
+ Assert.AreEqual(expected: (int)HttpStatusCode.OK, actual: postMiddlewareContext.Response.StatusCode);
+
+ using IHost host = await WebHostBuilderHelper.CreateWebHost(EasyAuthType.StaticWebApps.ToString(), false);
+ TestServer server = host.GetTestServer();
+ HttpClient client = server.CreateClient();
+
+ HttpRequestMessage request = new(HttpMethod.Get, $"api/Author/id/10001");
+ HttpResponseMessage response = await client.SendAsync(request);
+ string responseBody = await response.Content.ReadAsStringAsync();
+
+ Assert.IsFalse(responseBody.Contains($"\"id\":10001"),
+ "The GET request should not return the invalid row.");
+ Assert.IsFalse(responseBody.Contains("Hidden Author"),
+ "The GET request should not return any information related to the invalid row.");
+ }
+
///
/// - Ensures an invalid EasyAuth header payload results in HTTP 401 Unauthorized response
/// A correctly configured EasyAuth environment guarantees an EasyAuth payload for authenticated requests.