From aed82681de811a23a977e3b11effe97b437958ba Mon Sep 17 00:00:00 2001 From: Claudia Beatriz Murialdo Garrone Date: Wed, 28 Aug 2024 15:01:39 -0300 Subject: [PATCH 1/2] Fix: Ensure Basic Authentication adds the Authorization header correctly. --- .../GxClasses/Domain/GxHttpClient.cs | 12 +++++-- .../GxClasses/Helpers/HttpHelper.cs | 1 + .../DotNetUnitTest/Domain/GxHttpClientTest.cs | 36 +++++++++++++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs index 35b3136dc..501f52f33 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs @@ -488,6 +488,10 @@ public void AddAuthentication(int scheme, string realm, string user, string pass { if (scheme >= _Basic && scheme <= _Kerberos) _authCollection.Add(new GxAuthScheme(scheme, realm, user, password)); + if (scheme == _Basic) { + string authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{user}:{password}")); + AddHeader(HttpHeader.AUTHORIZATION, new AuthenticationHeaderValue("Basic", authHeader).ToString()); + } } public void AddProxyAuthentication(int scheme, string realm, string user, string password) @@ -727,7 +731,7 @@ void setContentHeaders(HttpRequestMessage request, string contentType) } InferContentType(contentType, request); } - void setHeaders(HttpRequestMessage request, CookieContainer cookies, out string contentType) + internal void SetHeaders(HttpRequestMessage request, CookieContainer cookies, out string contentType) { HttpRequestHeaders headers = request.Headers; contentType = null; @@ -864,7 +868,7 @@ HttpResponseMessage ExecuteRequest(string method, string requestUrl, bool contex RequestUri = new Uri(requestUrl), Method = new HttpMethod(method), }; - setHeaders(request, cookies, out string contentType); + SetHeaders(request, cookies, out string contentType); SetHttpVersion(request); bool disposableInstance = true; try @@ -926,7 +930,7 @@ async Task ExecuteRequestAsync(string method, string reques RequestUri = new Uri(requestUrl), Method = new HttpMethod(method), }; - setHeaders(request, cookies, out string contentType); + SetHeaders(request, cookies, out string contentType); SetHttpVersion(request); bool disposableInstance = true; try @@ -1581,6 +1585,8 @@ static ICredentials getCredentialCache(Uri URI, ArrayList authenticationCollecti } else { + //return new NetworkCredential(auth.User, auth.Password); + if (cc == null) { cc = new CredentialCache(); diff --git a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs index 65d9c4789..4cbf50c2e 100644 --- a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs +++ b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs @@ -52,6 +52,7 @@ public class HttpHeader internal static string TRANSFER_ENCODING = "Transfer-Encoding"; internal static string X_CSRF_TOKEN_HEADER = "X-XSRF-TOKEN"; internal static string X_CSRF_TOKEN_COOKIE = "XSRF-TOKEN"; + internal static string AUTHORIZATION = "Authorization"; } internal class HttpHeaderValue { diff --git a/dotnet/test/DotNetUnitTest/Domain/GxHttpClientTest.cs b/dotnet/test/DotNetUnitTest/Domain/GxHttpClientTest.cs index 68f3fa9ab..837ce5849 100644 --- a/dotnet/test/DotNetUnitTest/Domain/GxHttpClientTest.cs +++ b/dotnet/test/DotNetUnitTest/Domain/GxHttpClientTest.cs @@ -4,10 +4,14 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Text; using System.Threading.Tasks; using GeneXus.Application; using GeneXus.Http.Client; using Xunit; + + + #if !NETCORE using System.Web.SessionState; using System.Web; @@ -18,8 +22,10 @@ namespace xUnitTesting public class GxHttpClientTest { - const int MAX_CONNECTIONS= 5; - public GxHttpClientTest() { + const int MAX_CONNECTIONS = 5; + + public GxHttpClientTest() + { Environment.SetEnvironmentVariable("GX_HTTPCLIENT_MAX_PER_ROUTE", MAX_CONNECTIONS.ToString(), EnvironmentVariableTarget.Process); } [Fact] @@ -203,5 +209,31 @@ public void NoStoreHeader() Assert.Equal(0, result); } #endif + +#if NETCORE + [Fact] + public void BasicAuthenticationIncludesHeader() + { + GxContext context = new GxContext(); + using (GxHttpClient httpclient = new GxHttpClient(context)) + { + string url= "https://www.google.com/"; + string username = "user"; + string password = "pass"; + string credentialsBase64 = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")); + httpclient.AddAuthentication(0, string.Empty, username, password); + + HttpRequestMessage request = new HttpRequestMessage() + { + RequestUri = new Uri(url), + Method = HttpMethod.Post, + }; + httpclient.SetHeaders(request, null, out string contentType); + string headerValue = request.Headers.GetValues("Authorization").FirstOrDefault(); + Assert.Equal(headerValue, $"Basic {credentialsBase64}"); + } + } +#endif } + } From e127f668d53da87513c4f63c9b4fcc1002689c3d Mon Sep 17 00:00:00 2001 From: Claudia Murialdo Date: Mon, 6 Jan 2025 13:21:27 -0300 Subject: [PATCH 2/2] Use ISO-8859-1 encoding instead of UTF-8 to Base64-encode the header value for Basic Authentication (same behavior as the Java generator). --- .../dotnetframework/GxClasses/Domain/GxHttpClient.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs index 501f52f33..d3bab0d90 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/GxHttpClient.cs @@ -484,13 +484,19 @@ public string get_ProxyHost() { return _proxyHost; } +#if NETCORE + private static Encoding ISO_8859_1 = Encoding.Latin1; +#else + private static Encoding ISO_8859_1 = Encoding.GetEncoding("ISO-8859-1"); +#endif + private const string AuthenticationSchemeBasic = "Basic"; public void AddAuthentication(int scheme, string realm, string user, string password) { if (scheme >= _Basic && scheme <= _Kerberos) _authCollection.Add(new GxAuthScheme(scheme, realm, user, password)); if (scheme == _Basic) { - string authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{user}:{password}")); - AddHeader(HttpHeader.AUTHORIZATION, new AuthenticationHeaderValue("Basic", authHeader).ToString()); + string authHeader = Convert.ToBase64String(ISO_8859_1.GetBytes($"{user}:{password}")); + AddHeader(HttpHeader.AUTHORIZATION, new AuthenticationHeaderValue(AuthenticationSchemeBasic, authHeader).ToString()); } } @@ -1036,7 +1042,7 @@ async Task ReadResponseDataAsync() } } } - #endif +#endif bool UseOldHttpClient(string name) { if (Config.GetValueOf("useoldhttpclient", out string useOld) && useOld.StartsWith("y", StringComparison.OrdinalIgnoreCase))