Skip to content

Commit 8cba33f

Browse files
authored
Merge pull request #56 from Corsinvest/fix/authentication-cookie-container
Fix authentication cookie container for IIS environments
2 parents 4643530 + 26f5479 commit 8cba33f

File tree

4 files changed

+57
-45
lines changed

4 files changed

+57
-45
lines changed

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<TargetFrameworks>net8.0;net9.0;net10.0;netstandard2.0</TargetFrameworks>
44
<LangVersion>latest</LangVersion>
55
<ImplicitUsings>enable</ImplicitUsings>
6-
<Version>9.1.2</Version>
6+
<Version>9.1.3</Version>
77
<!--<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>-->
88

99
<Company>Corsinvest Srl</Company>

src/Corsinvest.ProxmoxVE.Api.Extension/Utils/ClientHelper.cs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,17 @@ public static async Task<PveClient> GetClientAndTryLoginAsync(string hostsAndPor
6464

6565
if (client == null) { throw new PveException("No reachable hosts found in the provided list"); }
6666

67-
try
68-
{
69-
client.ValidateCertificate = validateCertificate;
70-
client.LoggerFactory = loggerFactory;
71-
72-
if (!await AuthenticateAsync(client, username, password, apiToken))
73-
{
74-
var errorMessage = client.LastResult?.ReasonPhrase ?? "Authentication failed";
75-
throw new PveException($"Authentication failed for host {endpoint}: {errorMessage}");
76-
}
67+
client.ValidateCertificate = validateCertificate;
68+
client.LoggerFactory = loggerFactory;
7769

78-
loggerFactory?.CreateLogger<PveClient>()?.LogDebug("Successfully connected to Proxmox VE at {0}", endpoint);
79-
return client;
80-
}
81-
catch
70+
if (!await AuthenticateAsync(client, username, password, apiToken))
8271
{
83-
throw;
72+
var errorMessage = client.LastResult?.ReasonPhrase ?? "Authentication failed";
73+
throw new PveException($"Authentication failed for host {endpoint}: {errorMessage}");
8474
}
75+
76+
loggerFactory?.CreateLogger<PveClient>()?.LogDebug("Successfully connected to Proxmox VE at {0}", endpoint);
77+
return client;
8578
}
8679

8780
/// <summary>
@@ -115,24 +108,17 @@ public static async Task<T> GetClientAndTryLoginAsync<T>(string hostsAndPortHA,
115108

116109
if (client == null) { throw new PveException("No reachable hosts found in the provided list"); }
117110

118-
try
119-
{
120-
client.ValidateCertificate = validateCertificate;
121-
client.LoggerFactory = loggerFactory;
122-
123-
if (!await AuthenticateAsync(client, username, password, apiToken))
124-
{
125-
var errorMessage = client.LastResult?.ReasonPhrase ?? "Authentication failed";
126-
throw new PveException($"Authentication failed for host {endpoint}: {errorMessage}");
127-
}
111+
client.ValidateCertificate = validateCertificate;
112+
client.LoggerFactory = loggerFactory;
128113

129-
loggerFactory?.CreateLogger<T>()?.LogDebug("Successfully connected to Proxmox VE at {0}", endpoint);
130-
return client;
131-
}
132-
catch
114+
if (!await AuthenticateAsync(client, username, password, apiToken))
133115
{
134-
throw;
116+
var errorMessage = client.LastResult?.ReasonPhrase ?? "Authentication failed";
117+
throw new PveException($"Authentication failed for host {endpoint}: {errorMessage}");
135118
}
119+
120+
loggerFactory?.CreateLogger<T>()?.LogDebug("Successfully connected to Proxmox VE at {0}", endpoint);
121+
return client;
136122
}
137123

138124
/// <summary>

src/Corsinvest.ProxmoxVE.Api.Shared/Utils/ByteHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static long ToBytes(string input)
2828
{
2929
if (string.IsNullOrWhiteSpace(input)) { throw new ArgumentException("Invalid input."); }
3030

31-
var pattern = @"^(\d+(\.\d+)?)\s*(" + string.Join("|", DecimalUnits) + string.Join("|", BinaryUnits) + ")$";
31+
var pattern = @"^(\d+(\.\d+)?)\s*(" + string.Join("|", DecimalUnits) + "|" + string.Join("|", BinaryUnits) + ")$";
3232
//@"^(\d+(\.\d+)?)\s*(B|KB|MB|GB|TB|PB|EB|KIB|MIB|GIB|TIB|PIB|EIB)$"
3333
var match = Regex.Match(input.Trim(), pattern, RegexOptions.IgnoreCase);
3434
if (!match.Success) { throw new FormatException("Invalid format. Use '1.5 GB' or '2 MiB'."); }

src/Corsinvest.ProxmoxVE.Api/PveClientBase.cs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using System.ComponentModel;
77
using System.Dynamic;
8+
using System.Net;
89
using System.Net.Http.Headers;
910
using System.Text;
1011
using System.Web;
@@ -25,8 +26,8 @@ public class PveClientBase(string host, int port = 8006, HttpClient? httpClient
2526
private ILogger<PveClientBase> _logger = NullLoggerFactory.Instance.CreateLogger<PveClientBase>();
2627
private ILoggerFactory _loggerFactory;
2728

28-
private HttpClient _httpClient;
29-
private readonly HttpClient? _externalHttpClient = httpClient;
29+
private HttpClient _internalHttpClient;
30+
private HttpClientHandler _internalHttpClientHandler;
3031

3132
/// <summary>
3233
/// Logger Factory
@@ -112,6 +113,12 @@ public async Task<bool> LoginAsync(string userName, string password, string real
112113

113114
CSRFPreventionToken = result.Response.data.CSRFPreventionToken;
114115
PVEAuthCookie = result.Response.data.ticket;
116+
117+
// Add cookie to CookieContainer for proper authentication in subsequent requests
118+
if (_internalHttpClientHandler?.CookieContainer != null)
119+
{
120+
_internalHttpClientHandler.CookieContainer.Add(new Uri(BaseAddress), new Cookie("PVEAuthCookie", PVEAuthCookie));
121+
}
115122
}
116123

117124
return result.IsSuccessStatusCode;
@@ -181,16 +188,21 @@ public async Task<Result> DeleteAsync(string resource, IDictionary<string, objec
181188
/// <returns></returns>
182189
public virtual HttpClient GetHttpClient()
183190
{
184-
if (_externalHttpClient != null) return _externalHttpClient;
191+
if (httpClient != null) return httpClient;
185192

186-
_httpClient ??= new HttpClient(new HttpClientHandler
193+
if (_internalHttpClient == null)
187194
{
188-
ServerCertificateCustomValidationCallback = !ValidateCertificate
189-
? (message, cert, chain, errors) => true
190-
: null
191-
});
195+
_internalHttpClientHandler = new HttpClientHandler
196+
{
197+
CookieContainer = new CookieContainer(),
198+
ServerCertificateCustomValidationCallback = !ValidateCertificate
199+
? (message, cert, chain, errors) => true
200+
: null
201+
};
202+
_internalHttpClient = new HttpClient(_internalHttpClientHandler);
203+
}
192204

193-
return _httpClient;
205+
return _internalHttpClient;
194206
}
195207

196208
/// <summary>
@@ -250,7 +262,7 @@ protected virtual async Task<Result> ExecuteRequestAsync(string resource,
250262
_logger.LogDebug("Method: {httpMethod}, Url: {uriString}", httpMethod, uriString);
251263
if (httpMethod != HttpMethod.Get)
252264
{
253-
var sensitiveParams = new[] { "password", "token", "ticket", "otp", "apitoken"};
265+
var sensitiveParams = new[] { "password", "token", "ticket", "otp", "apitoken" };
254266
_logger.LogDebug("Parameters: {parameters}", string.Join(Environment.NewLine, @params.Select(a =>
255267
{
256268
var paramName = a.Key.ToLower();
@@ -302,6 +314,20 @@ protected virtual async Task<Result> ExecuteRequestAsync(string resource,
302314
catch (TaskCanceledException ex) when (!cts.Token.IsCancellationRequested)
303315
{
304316
_logger.LogError(ex, ex.Message);
317+
318+
response = new(HttpStatusCode.RequestTimeout)
319+
{
320+
ReasonPhrase = ex.Message,
321+
};
322+
}
323+
catch (Exception ex)
324+
{
325+
_logger.LogError(ex, ex.Message);
326+
327+
response = new(HttpStatusCode.InternalServerError)
328+
{
329+
ReasonPhrase = ex.Message,
330+
};
305331
}
306332

307333
if (_logger.IsEnabled(LogLevel.Debug))
@@ -378,14 +404,14 @@ public async Task<bool> WaitForTaskToFinishAsync(string task, int wait = 500, lo
378404
if (timeout < wait) { timeout = wait + 5000; }
379405
var timeStart = DateTime.Now;
380406

381-
while (isRunning && (DateTime.Now - timeStart).Milliseconds < timeout)
407+
while (isRunning && (DateTime.Now - timeStart).TotalMilliseconds < timeout)
382408
{
383-
Thread.Sleep(wait);
409+
await Task.Delay(wait);
384410
isRunning = await TaskIsRunningAsync(task);
385411
}
386412

387413
//check timeout
388-
return (DateTime.Now - timeStart).Milliseconds < timeout;
414+
return (DateTime.Now - timeStart).TotalMilliseconds < timeout;
389415
}
390416

391417
/// <summary>

0 commit comments

Comments
 (0)