Files
ps.ipam/classlib/Helpers/SessionManager.cs

166 lines
4.9 KiB
C#

namespace PS.IPAM.Helpers;
using System;
using System.Management.Automation;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
/// <summary>
/// Manages phpIPAM API sessions including creation, validation, and lifecycle.
/// </summary>
public static class SessionManager
{
private static Session? _currentSession;
/// <summary>
/// Gets or sets the current active session.
/// </summary>
public static Session? CurrentSession
{
get => _currentSession;
set => _currentSession = value;
}
/// <summary>
/// Tests the current session status.
/// </summary>
/// <returns>The session status indicating validity or issues.</returns>
public static SessionStatus GetSessionStatus()
{
if (_currentSession == null)
{
return SessionStatus.NoSession;
}
if (_currentSession.Expires == null)
{
return SessionStatus.Valid;
}
return _currentSession.Expires < DateTime.Now
? SessionStatus.Expired
: SessionStatus.Valid;
}
/// <summary>
/// Creates a new session using username/password credentials.
/// </summary>
/// <param name="url">The phpIPAM server URL.</param>
/// <param name="appId">The API application ID.</param>
/// <param name="credentials">The PowerShell credential object.</param>
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
/// <returns>The created session.</returns>
public static async Task<Session> CreateSessionWithCredentialsAsync(
string url,
string appId,
PSCredential credentials,
bool ignoreSsl = false)
{
var uri = $"{url}/api/{appId}/user";
var auth = Convert.ToBase64String(
Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPasswordString(credentials)}"));
using var client = CreateHttpClient(ignoreSsl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
var response = await client.PostAsync(uri, null);
var content = await response.Content.ReadAsStringAsync();
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(content);
if (jsonResponse?.success != true)
{
throw new InvalidOperationException(
jsonResponse?.error?.ToString() ?? "Failed to create session");
}
var token = jsonResponse.data.token.ToString();
var expires = DateTime.Parse(jsonResponse.data.expires.ToString());
_currentSession = new Session(
AuthType.Credentials,
token,
appId,
url,
expires,
credentials
);
return _currentSession;
}
/// <summary>
/// Creates a new session using a static API token.
/// </summary>
/// <param name="url">The phpIPAM server URL.</param>
/// <param name="appId">The API application ID.</param>
/// <param name="token">The API token.</param>
/// <returns>The created session.</returns>
public static Session CreateSessionWithToken(string url, string appId, string token)
{
_currentSession = new Session(
AuthType.Token,
token,
appId,
url,
null,
null
);
return _currentSession;
}
/// <summary>
/// Closes the current session and clears session data.
/// </summary>
public static void CloseSession()
{
_currentSession = null;
}
/// <summary>
/// Creates an HttpClient with optional SSL bypass.
/// </summary>
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
/// <param name="handler">Optional custom message handler for testing.</param>
/// <returns>A configured HttpClient instance.</returns>
public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null)
{
if (handler != null)
{
return new HttpClient(handler);
}
if (ignoreSsl)
{
var sslHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
};
return new HttpClient(sslHandler);
}
return new HttpClient();
}
/// <summary>
/// Extracts the plain text password from a PSCredential object.
/// </summary>
private static string GetPasswordString(PSCredential credential)
{
var ptr = Marshal.SecureStringToBSTR(credential.Password);
try
{
return Marshal.PtrToStringBSTR(ptr);
}
finally
{
Marshal.ZeroFreeBSTR(ptr);
}
}
}