using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security;
using System.Text;
using System.Management.Automation;
using Newtonsoft.Json;
using PSProxmox.Models;
namespace PSProxmox.Session
{
///
/// Handles authentication and session management for Proxmox VE.
///
public class ProxmoxSession
{
///
/// Authenticates with the Proxmox VE API.
///
/// The server hostname or IP address.
/// The port number.
/// Whether to use HTTPS.
/// Whether to skip SSL certificate validation.
/// The username for authentication.
/// The password for authentication.
/// The realm for authentication.
/// The PowerShell cmdlet making the request.
/// A connection object with authentication information.
public static ProxmoxConnection Login(
string server,
int port,
bool useSSL,
bool skipCertificateValidation,
string username,
SecureString password,
string realm,
PSCmdlet cmdlet)
{
var connection = new ProxmoxConnection(server, port, useSSL, skipCertificateValidation, username, realm);
// Create the login URL
string loginUrl = $"{connection.ApiUrl}/access/ticket";
// Log the URL if verbose is enabled
if (cmdlet != null)
{
cmdlet.WriteVerbose($"Authenticating to {loginUrl}");
}
// Create the request
var request = (HttpWebRequest)WebRequest.Create(loginUrl);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// Skip certificate validation if requested
if (skipCertificateValidation && request.RequestUri.Scheme == "https")
{
request.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
}
// Convert SecureString to plain text (only for sending to API)
string plainPassword = new System.Net.NetworkCredential(string.Empty, password).Password;
// Create the request body
string postData = $"username={Uri.EscapeDataString(username)}&password={Uri.EscapeDataString(plainPassword)}&realm={Uri.EscapeDataString(realm)}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentLength = byteArray.Length;
// Send the request
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
}
// Get the response
try
{
using (var response = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
string responseText = reader.ReadToEnd();
var loginResponse = JsonConvert.DeserializeObject>(responseText);
if (loginResponse?.Data == null)
{
throw new Exception("Invalid response from server");
}
return connection.WithAuthentication(
loginResponse.Data.Ticket,
loginResponse.Data.CSRFPreventionToken);
}
}
catch (WebException ex)
{
if (ex.Response != null)
{
using (var errorResponse = (HttpWebResponse)ex.Response)
using (var reader = new StreamReader(errorResponse.GetResponseStream()))
{
string errorText = reader.ReadToEnd();
throw new Exception($"Authentication failed: {errorText}");
}
}
throw;
}
}
///
/// Logs out from the Proxmox VE API.
///
/// The connection to log out from.
/// The PowerShell cmdlet making the request.
public static void Logout(ProxmoxConnection connection, PSCmdlet cmdlet)
{
if (connection == null || !connection.IsAuthenticated)
{
return;
}
// Create the logout URL
string logoutUrl = $"{connection.ApiUrl}/access/ticket";
// Log the URL if verbose is enabled
if (cmdlet != null)
{
cmdlet.WriteVerbose($"Logging out from {logoutUrl}");
}
// Create the request
var request = (HttpWebRequest)WebRequest.Create(logoutUrl);
request.Method = "DELETE";
request.Headers.Add("Cookie", $"PVEAuthCookie={connection.Ticket}");
request.Headers.Add("CSRFPreventionToken", connection.CSRFPreventionToken);
// Skip certificate validation if requested
if (connection.SkipCertificateValidation && request.RequestUri.Scheme == "https")
{
request.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
}
// Send the request and ignore the response
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
// Just to ensure the request is completed
}
}
catch (WebException)
{
// Ignore errors during logout
}
}
}
}