CI: add dotnet --info / df -h / free -m diagnostics and an explicit 'Restore NuGet packages' step before build to isolate restore failures (build of e15f650 on main exited with code -1 and zero dotnet output).
#5
@@ -63,5 +63,13 @@ namespace PSInfisicalAPI.Endpoints
|
|||||||
public const string GetCertificatePolicy = "GetCertificatePolicy";
|
public const string GetCertificatePolicy = "GetCertificatePolicy";
|
||||||
|
|
||||||
public const string ListCertificateAuthorities = "ListCertificateAuthorities";
|
public const string ListCertificateAuthorities = "ListCertificateAuthorities";
|
||||||
|
|
||||||
|
public const string ListCertificateApplications = "ListCertificateApplications";
|
||||||
|
public const string GetCertificateApplication = "GetCertificateApplication";
|
||||||
|
public const string GetCertificateApplicationByName = "GetCertificateApplicationByName";
|
||||||
|
public const string ListCertificateApplicationProfiles = "ListCertificateApplicationProfiles";
|
||||||
|
public const string GetCertificateApplicationEnrollment = "GetCertificateApplicationEnrollment";
|
||||||
|
|
||||||
|
public const string GenerateScepDynamicChallenge = "GenerateScepDynamicChallenge";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -703,6 +703,67 @@ namespace PSInfisicalAPI.Endpoints
|
|||||||
Template = "/api/v1/cert-manager/ca",
|
Template = "/api/v1/cert-manager/ca",
|
||||||
RequiresAuthorization = true
|
RequiresAuthorization = true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Add(map, new InfisicalEndpointDefinition
|
||||||
|
{
|
||||||
|
Name = InfisicalEndpointNames.ListCertificateApplications,
|
||||||
|
Resource = "Pki",
|
||||||
|
Version = "v1",
|
||||||
|
Method = "GET",
|
||||||
|
Template = "/api/v1/cert-manager/applications",
|
||||||
|
RequiresAuthorization = true
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(map, new InfisicalEndpointDefinition
|
||||||
|
{
|
||||||
|
Name = InfisicalEndpointNames.GetCertificateApplication,
|
||||||
|
Resource = "Pki",
|
||||||
|
Version = "v1",
|
||||||
|
Method = "GET",
|
||||||
|
Template = "/api/v1/cert-manager/applications/{applicationId}",
|
||||||
|
RequiresAuthorization = true
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(map, new InfisicalEndpointDefinition
|
||||||
|
{
|
||||||
|
Name = InfisicalEndpointNames.GetCertificateApplicationByName,
|
||||||
|
Resource = "Pki",
|
||||||
|
Version = "v1",
|
||||||
|
Method = "GET",
|
||||||
|
Template = "/api/v1/cert-manager/applications/by-name/{name}",
|
||||||
|
RequiresAuthorization = true
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(map, new InfisicalEndpointDefinition
|
||||||
|
{
|
||||||
|
Name = InfisicalEndpointNames.ListCertificateApplicationProfiles,
|
||||||
|
Resource = "Pki",
|
||||||
|
Version = "v1",
|
||||||
|
Method = "GET",
|
||||||
|
Template = "/api/v1/cert-manager/applications/{applicationId}/profiles",
|
||||||
|
RequiresAuthorization = true
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(map, new InfisicalEndpointDefinition
|
||||||
|
{
|
||||||
|
Name = InfisicalEndpointNames.GetCertificateApplicationEnrollment,
|
||||||
|
Resource = "Pki",
|
||||||
|
Version = "v1",
|
||||||
|
Method = "GET",
|
||||||
|
Template = "/api/v1/cert-manager/applications/{applicationId}/profiles/{profileId}/enrollment",
|
||||||
|
RequiresAuthorization = true
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(map, new InfisicalEndpointDefinition
|
||||||
|
{
|
||||||
|
Name = InfisicalEndpointNames.GenerateScepDynamicChallenge,
|
||||||
|
Resource = "Pki",
|
||||||
|
Version = "v1",
|
||||||
|
Method = "POST",
|
||||||
|
Template = "/scep/applications/{applicationId}/profiles/{profileId}/challenge",
|
||||||
|
RequiresAuthorization = true,
|
||||||
|
ContainsSecretMaterialInResponse = true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InfisicalEndpointDefinition Get(string name)
|
public static InfisicalEndpointDefinition Get(string name)
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ namespace PSInfisicalAPI.Http
|
|||||||
string operationName,
|
string operationName,
|
||||||
IDictionary<string, string> pathParameters,
|
IDictionary<string, string> pathParameters,
|
||||||
IEnumerable<KeyValuePair<string, string>> queryParameters,
|
IEnumerable<KeyValuePair<string, string>> queryParameters,
|
||||||
string body)
|
string body,
|
||||||
|
IDictionary<string, string> extraHeaders = null)
|
||||||
{
|
{
|
||||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(nameof(endpointName)); }
|
if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(nameof(endpointName)); }
|
||||||
@@ -31,7 +32,7 @@ namespace PSInfisicalAPI.Http
|
|||||||
InfisicalEndpointDefinition definition = InfisicalEndpointRegistry.Get(endpointName);
|
InfisicalEndpointDefinition definition = InfisicalEndpointRegistry.Get(endpointName);
|
||||||
Uri uri = InfisicalUriBuilder.Build(connection.BaseUri, definition, pathParameters, queryParameters);
|
Uri uri = InfisicalUriBuilder.Build(connection.BaseUri, definition, pathParameters, queryParameters);
|
||||||
|
|
||||||
InfisicalHttpResponse response = ExecuteAuthorized(connection, definition, operationName, uri, body);
|
InfisicalHttpResponse response = ExecuteAuthorized(connection, definition, operationName, uri, body, extraHeaders);
|
||||||
|
|
||||||
if (response.StatusCode >= 200 && response.StatusCode < 300)
|
if (response.StatusCode >= 200 && response.StatusCode < 300)
|
||||||
{
|
{
|
||||||
@@ -49,7 +50,8 @@ namespace PSInfisicalAPI.Http
|
|||||||
string operationName,
|
string operationName,
|
||||||
IDictionary<string, string> pathParameters,
|
IDictionary<string, string> pathParameters,
|
||||||
IEnumerable<KeyValuePair<string, string>> queryParameters,
|
IEnumerable<KeyValuePair<string, string>> queryParameters,
|
||||||
string body)
|
string body,
|
||||||
|
IDictionary<string, string> extraHeaders = null)
|
||||||
{
|
{
|
||||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(nameof(endpointName)); }
|
if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(nameof(endpointName)); }
|
||||||
@@ -61,7 +63,7 @@ namespace PSInfisicalAPI.Http
|
|||||||
{
|
{
|
||||||
InfisicalEndpointDefinition definition = candidates[index];
|
InfisicalEndpointDefinition definition = candidates[index];
|
||||||
Uri uri = InfisicalUriBuilder.Build(connection.BaseUri, definition, pathParameters, queryParameters);
|
Uri uri = InfisicalUriBuilder.Build(connection.BaseUri, definition, pathParameters, queryParameters);
|
||||||
InfisicalHttpResponse response = ExecuteAuthorized(connection, definition, operationName, uri, body);
|
InfisicalHttpResponse response = ExecuteAuthorized(connection, definition, operationName, uri, body, extraHeaders);
|
||||||
|
|
||||||
if (response.StatusCode >= 200 && response.StatusCode < 300)
|
if (response.StatusCode >= 200 && response.StatusCode < 300)
|
||||||
{
|
{
|
||||||
@@ -95,7 +97,8 @@ namespace PSInfisicalAPI.Http
|
|||||||
InfisicalEndpointDefinition definition,
|
InfisicalEndpointDefinition definition,
|
||||||
string operationName,
|
string operationName,
|
||||||
Uri uri,
|
Uri uri,
|
||||||
string body)
|
string body,
|
||||||
|
IDictionary<string, string> extraHeaders = null)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
Dictionary<string, string> headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
headers["Accept"] = "application/json";
|
headers["Accept"] = "application/json";
|
||||||
@@ -118,6 +121,15 @@ namespace PSInfisicalAPI.Http
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extraHeaders != null)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, string> entry in extraHeaders)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(entry.Key)) { continue; }
|
||||||
|
headers[entry.Key] = entry.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InfisicalHttpRequest request = new InfisicalHttpRequest
|
InfisicalHttpRequest request = new InfisicalHttpRequest
|
||||||
{
|
{
|
||||||
OperationName = operationName,
|
OperationName = operationName,
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PSInfisicalAPI.Models
|
||||||
|
{
|
||||||
|
public sealed class InfisicalCertificateApplication
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string ProjectId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public int? ProfileCount { get; set; }
|
||||||
|
public int? MemberCount { get; set; }
|
||||||
|
public int? CertificateCount { get; set; }
|
||||||
|
public DateTimeOffset? CreatedAtUtc { get; set; }
|
||||||
|
public DateTimeOffset? UpdatedAtUtc { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InfisicalCertificateApplicationProfileAttachment
|
||||||
|
{
|
||||||
|
public string ApplicationId { get; set; }
|
||||||
|
public string ProfileId { get; set; }
|
||||||
|
public string ProfileSlug { get; set; }
|
||||||
|
public string ProfileDescription { get; set; }
|
||||||
|
public string ApiConfigId { get; set; }
|
||||||
|
public string EstConfigId { get; set; }
|
||||||
|
public string AcmeConfigId { get; set; }
|
||||||
|
public string ScepConfigId { get; set; }
|
||||||
|
public DateTimeOffset? CreatedAtUtc { get; set; }
|
||||||
|
public DateTimeOffset? UpdatedAtUtc { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PSInfisicalAPI.Models
|
||||||
|
{
|
||||||
|
public sealed class InfisicalCertificateApplicationEnrollment
|
||||||
|
{
|
||||||
|
public string ApplicationId { get; set; }
|
||||||
|
public string ProfileId { get; set; }
|
||||||
|
public InfisicalCertificateApplicationApiEnrollment Api { get; set; }
|
||||||
|
public InfisicalCertificateApplicationEstEnrollment Est { get; set; }
|
||||||
|
public InfisicalCertificateApplicationAcmeEnrollment Acme { get; set; }
|
||||||
|
public InfisicalCertificateApplicationScepEnrollment Scep { get; set; }
|
||||||
|
public bool ApiConfigured { get { return Api != null; } }
|
||||||
|
public bool EstConfigured { get; set; }
|
||||||
|
public bool AcmeConfigured { get; set; }
|
||||||
|
public bool ScepConfigured { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InfisicalCertificateApplicationApiEnrollment
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public bool? AutoRenew { get; set; }
|
||||||
|
public int? RenewBeforeDays { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InfisicalCertificateApplicationEstEnrollment
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public bool? DisableBootstrapCaValidation { get; set; }
|
||||||
|
public string EstEndpointUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InfisicalCertificateApplicationAcmeEnrollment
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public bool? SkipDnsOwnershipVerification { get; set; }
|
||||||
|
public bool? SkipEabBinding { get; set; }
|
||||||
|
public string DirectoryUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InfisicalCertificateApplicationScepEnrollment
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string ChallengeType { get; set; }
|
||||||
|
public bool? IncludeCaCertInResponse { get; set; }
|
||||||
|
public bool? AllowCertBasedRenewal { get; set; }
|
||||||
|
public int? DynamicChallengeExpiryMinutes { get; set; }
|
||||||
|
public int? DynamicChallengeMaxPending { get; set; }
|
||||||
|
public string ScepEndpointUrl { get; set; }
|
||||||
|
public string ChallengeEndpointUrl { get; set; }
|
||||||
|
public string RaCertificatePem { get; set; }
|
||||||
|
public string RaCertificateThumbprint { get; set; }
|
||||||
|
public DateTimeOffset? RaCertExpiresAtUtc { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace PSInfisicalAPI.Pki
|
||||||
|
{
|
||||||
|
internal sealed class InfisicalCertificateApplicationResponseDto
|
||||||
|
{
|
||||||
|
[JsonProperty("id")] public string Id { get; set; }
|
||||||
|
[JsonProperty("projectId")] public string ProjectId { get; set; }
|
||||||
|
[JsonProperty("name")] public string Name { get; set; }
|
||||||
|
[JsonProperty("description")] public string Description { get; set; }
|
||||||
|
[JsonProperty("profileCount")] public int? ProfileCount { get; set; }
|
||||||
|
[JsonProperty("memberCount")] public int? MemberCount { get; set; }
|
||||||
|
[JsonProperty("certificateCount")] public int? CertificateCount { get; set; }
|
||||||
|
[JsonProperty("createdAt")] public string CreatedAt { get; set; }
|
||||||
|
[JsonProperty("updatedAt")] public string UpdatedAt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationListResponseDto
|
||||||
|
{
|
||||||
|
[JsonProperty("applications")] public List<InfisicalCertificateApplicationResponseDto> Applications { get; set; }
|
||||||
|
[JsonProperty("total")] public int? Total { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationProfileAttachmentDto
|
||||||
|
{
|
||||||
|
[JsonProperty("applicationId")] public string ApplicationId { get; set; }
|
||||||
|
[JsonProperty("profileId")] public string ProfileId { get; set; }
|
||||||
|
[JsonProperty("profileSlug")] public string ProfileSlug { get; set; }
|
||||||
|
[JsonProperty("profileDescription")] public string ProfileDescription { get; set; }
|
||||||
|
[JsonProperty("apiConfigId")] public string ApiConfigId { get; set; }
|
||||||
|
[JsonProperty("estConfigId")] public string EstConfigId { get; set; }
|
||||||
|
[JsonProperty("acmeConfigId")] public string AcmeConfigId { get; set; }
|
||||||
|
[JsonProperty("scepConfigId")] public string ScepConfigId { get; set; }
|
||||||
|
[JsonProperty("createdAt")] public string CreatedAt { get; set; }
|
||||||
|
[JsonProperty("updatedAt")] public string UpdatedAt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationProfilesResponseDto
|
||||||
|
{
|
||||||
|
[JsonProperty("profiles")] public List<InfisicalCertificateApplicationProfileAttachmentDto> Profiles { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationEnrollmentResponseDto
|
||||||
|
{
|
||||||
|
[JsonProperty("applicationId")] public string ApplicationId { get; set; }
|
||||||
|
[JsonProperty("profileId")] public string ProfileId { get; set; }
|
||||||
|
[JsonProperty("api")] public InfisicalCertificateApplicationApiEnrollmentDto Api { get; set; }
|
||||||
|
[JsonProperty("est")] public InfisicalCertificateApplicationEstEnrollmentDto Est { get; set; }
|
||||||
|
[JsonProperty("acme")] public InfisicalCertificateApplicationAcmeEnrollmentDto Acme { get; set; }
|
||||||
|
[JsonProperty("scep")] public InfisicalCertificateApplicationScepEnrollmentDto Scep { get; set; }
|
||||||
|
[JsonProperty("estConfigured")] public bool? EstConfigured { get; set; }
|
||||||
|
[JsonProperty("acmeConfigured")] public bool? AcmeConfigured { get; set; }
|
||||||
|
[JsonProperty("scepConfigured")] public bool? ScepConfigured { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationApiEnrollmentDto
|
||||||
|
{
|
||||||
|
[JsonProperty("id")] public string Id { get; set; }
|
||||||
|
[JsonProperty("autoRenew")] public bool? AutoRenew { get; set; }
|
||||||
|
[JsonProperty("renewBeforeDays")] public int? RenewBeforeDays { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationEstEnrollmentDto
|
||||||
|
{
|
||||||
|
[JsonProperty("id")] public string Id { get; set; }
|
||||||
|
[JsonProperty("disableBootstrapCaValidation")] public bool? DisableBootstrapCaValidation { get; set; }
|
||||||
|
[JsonProperty("estEndpointUrl")] public string EstEndpointUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationAcmeEnrollmentDto
|
||||||
|
{
|
||||||
|
[JsonProperty("id")] public string Id { get; set; }
|
||||||
|
[JsonProperty("skipDnsOwnershipVerification")] public bool? SkipDnsOwnershipVerification { get; set; }
|
||||||
|
[JsonProperty("skipEabBinding")] public bool? SkipEabBinding { get; set; }
|
||||||
|
[JsonProperty("directoryUrl")] public string DirectoryUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class InfisicalCertificateApplicationScepEnrollmentDto
|
||||||
|
{
|
||||||
|
[JsonProperty("id")] public string Id { get; set; }
|
||||||
|
[JsonProperty("challengeType")] public string ChallengeType { get; set; }
|
||||||
|
[JsonProperty("includeCaCertInResponse")] public bool? IncludeCaCertInResponse { get; set; }
|
||||||
|
[JsonProperty("allowCertBasedRenewal")] public bool? AllowCertBasedRenewal { get; set; }
|
||||||
|
[JsonProperty("dynamicChallengeExpiryMinutes")] public int? DynamicChallengeExpiryMinutes { get; set; }
|
||||||
|
[JsonProperty("dynamicChallengeMaxPending")] public int? DynamicChallengeMaxPending { get; set; }
|
||||||
|
[JsonProperty("scepEndpointUrl")] public string ScepEndpointUrl { get; set; }
|
||||||
|
[JsonProperty("challengeEndpointUrl")] public string ChallengeEndpointUrl { get; set; }
|
||||||
|
[JsonProperty("raCertificatePem")] public string RaCertificatePem { get; set; }
|
||||||
|
[JsonProperty("raCertExpiresAt")] public string RaCertExpiresAt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
using PSInfisicalAPI.Models;
|
||||||
|
|
||||||
|
namespace PSInfisicalAPI.Pki
|
||||||
|
{
|
||||||
|
internal static class InfisicalCertificateApplicationMapper
|
||||||
|
{
|
||||||
|
public static InfisicalCertificateApplication Map(InfisicalCertificateApplicationResponseDto dto, string fallbackProjectId)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplication
|
||||||
|
{
|
||||||
|
Id = dto.Id,
|
||||||
|
ProjectId = !string.IsNullOrEmpty(dto.ProjectId) ? dto.ProjectId : fallbackProjectId,
|
||||||
|
Name = dto.Name,
|
||||||
|
Description = dto.Description,
|
||||||
|
ProfileCount = dto.ProfileCount,
|
||||||
|
MemberCount = dto.MemberCount,
|
||||||
|
CertificateCount = dto.CertificateCount,
|
||||||
|
CreatedAtUtc = ParseTimestamp(dto.CreatedAt),
|
||||||
|
UpdatedAtUtc = ParseTimestamp(dto.UpdatedAt)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InfisicalCertificateApplication[] MapMany(IEnumerable<InfisicalCertificateApplicationResponseDto> items, string fallbackProjectId)
|
||||||
|
{
|
||||||
|
if (items == null) { return Array.Empty<InfisicalCertificateApplication>(); }
|
||||||
|
List<InfisicalCertificateApplication> results = new List<InfisicalCertificateApplication>();
|
||||||
|
foreach (InfisicalCertificateApplicationResponseDto dto in items)
|
||||||
|
{
|
||||||
|
InfisicalCertificateApplication mapped = Map(dto, fallbackProjectId);
|
||||||
|
if (mapped != null) { results.Add(mapped); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InfisicalCertificateApplicationProfileAttachment MapAttachment(InfisicalCertificateApplicationProfileAttachmentDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplicationProfileAttachment
|
||||||
|
{
|
||||||
|
ApplicationId = dto.ApplicationId,
|
||||||
|
ProfileId = dto.ProfileId,
|
||||||
|
ProfileSlug = dto.ProfileSlug,
|
||||||
|
ProfileDescription = dto.ProfileDescription,
|
||||||
|
ApiConfigId = dto.ApiConfigId,
|
||||||
|
EstConfigId = dto.EstConfigId,
|
||||||
|
AcmeConfigId = dto.AcmeConfigId,
|
||||||
|
ScepConfigId = dto.ScepConfigId,
|
||||||
|
CreatedAtUtc = ParseTimestamp(dto.CreatedAt),
|
||||||
|
UpdatedAtUtc = ParseTimestamp(dto.UpdatedAt)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InfisicalCertificateApplicationProfileAttachment[] MapAttachments(IEnumerable<InfisicalCertificateApplicationProfileAttachmentDto> items)
|
||||||
|
{
|
||||||
|
if (items == null) { return Array.Empty<InfisicalCertificateApplicationProfileAttachment>(); }
|
||||||
|
List<InfisicalCertificateApplicationProfileAttachment> results = new List<InfisicalCertificateApplicationProfileAttachment>();
|
||||||
|
foreach (InfisicalCertificateApplicationProfileAttachmentDto dto in items)
|
||||||
|
{
|
||||||
|
InfisicalCertificateApplicationProfileAttachment mapped = MapAttachment(dto);
|
||||||
|
if (mapped != null) { results.Add(mapped); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InfisicalCertificateApplicationEnrollment MapEnrollment(InfisicalCertificateApplicationEnrollmentResponseDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplicationEnrollment
|
||||||
|
{
|
||||||
|
ApplicationId = dto.ApplicationId,
|
||||||
|
ProfileId = dto.ProfileId,
|
||||||
|
Api = MapApi(dto.Api),
|
||||||
|
Est = MapEst(dto.Est),
|
||||||
|
Acme = MapAcme(dto.Acme),
|
||||||
|
Scep = MapScep(dto.Scep),
|
||||||
|
EstConfigured = dto.EstConfigured.GetValueOrDefault(),
|
||||||
|
AcmeConfigured = dto.AcmeConfigured.GetValueOrDefault(),
|
||||||
|
ScepConfigured = dto.ScepConfigured.GetValueOrDefault()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InfisicalCertificateApplicationApiEnrollment MapApi(InfisicalCertificateApplicationApiEnrollmentDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplicationApiEnrollment { Id = dto.Id, AutoRenew = dto.AutoRenew, RenewBeforeDays = dto.RenewBeforeDays };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InfisicalCertificateApplicationEstEnrollment MapEst(InfisicalCertificateApplicationEstEnrollmentDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplicationEstEnrollment { Id = dto.Id, DisableBootstrapCaValidation = dto.DisableBootstrapCaValidation, EstEndpointUrl = dto.EstEndpointUrl };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InfisicalCertificateApplicationAcmeEnrollment MapAcme(InfisicalCertificateApplicationAcmeEnrollmentDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplicationAcmeEnrollment { Id = dto.Id, SkipDnsOwnershipVerification = dto.SkipDnsOwnershipVerification, SkipEabBinding = dto.SkipEabBinding, DirectoryUrl = dto.DirectoryUrl };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InfisicalCertificateApplicationScepEnrollment MapScep(InfisicalCertificateApplicationScepEnrollmentDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) { return null; }
|
||||||
|
return new InfisicalCertificateApplicationScepEnrollment
|
||||||
|
{
|
||||||
|
Id = dto.Id,
|
||||||
|
ChallengeType = dto.ChallengeType,
|
||||||
|
IncludeCaCertInResponse = dto.IncludeCaCertInResponse,
|
||||||
|
AllowCertBasedRenewal = dto.AllowCertBasedRenewal,
|
||||||
|
DynamicChallengeExpiryMinutes = dto.DynamicChallengeExpiryMinutes,
|
||||||
|
DynamicChallengeMaxPending = dto.DynamicChallengeMaxPending,
|
||||||
|
ScepEndpointUrl = dto.ScepEndpointUrl,
|
||||||
|
ChallengeEndpointUrl = dto.ChallengeEndpointUrl,
|
||||||
|
RaCertificatePem = dto.RaCertificatePem,
|
||||||
|
RaCertificateThumbprint = ComputeThumbprint(dto.RaCertificatePem),
|
||||||
|
RaCertExpiresAtUtc = ParseTimestamp(dto.RaCertExpiresAt)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ComputeThumbprint(string pem)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(pem)) { return null; }
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] der = Convert.FromBase64String(StripPemArmor(pem));
|
||||||
|
using (X509Certificate2 cert = new X509Certificate2(der))
|
||||||
|
{
|
||||||
|
return cert.Thumbprint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string StripPemArmor(string pem)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(pem.Length);
|
||||||
|
using (StringReader reader = new StringReader(pem))
|
||||||
|
{
|
||||||
|
string line;
|
||||||
|
while ((line = reader.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
string trimmed = line.Trim();
|
||||||
|
if (trimmed.Length == 0) { continue; }
|
||||||
|
if (trimmed.StartsWith("-----", StringComparison.Ordinal)) { continue; }
|
||||||
|
sb.Append(trimmed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DateTimeOffset? ParseTimestamp(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value)) { return null; }
|
||||||
|
DateTimeOffset parsed;
|
||||||
|
if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out parsed))
|
||||||
|
{
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -640,6 +640,233 @@ namespace PSInfisicalAPI.Pki
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InfisicalCertificateApplication[] ListCertificateApplications(InfisicalConnection connection, string projectId, int? limit, int? offset)
|
||||||
|
{
|
||||||
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
|
string resolvedProjectId = FirstNonEmpty(projectId, connection.ProjectId);
|
||||||
|
if (string.IsNullOrEmpty(resolvedProjectId)) { throw new InfisicalConfigurationException("ProjectId is required."); }
|
||||||
|
|
||||||
|
List<KeyValuePair<string, string>> query = new List<KeyValuePair<string, string>>();
|
||||||
|
if (limit.HasValue) { query.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString(CultureInfo.InvariantCulture))); }
|
||||||
|
if (offset.HasValue) { query.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString(CultureInfo.InvariantCulture))); }
|
||||||
|
|
||||||
|
Dictionary<string, string> headers = BuildProjectHeader(resolvedProjectId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information(Component, "Attempting to list Infisical certificate applications. Please Wait...");
|
||||||
|
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.ListCertificateApplications, "ListCertificateApplications", null, query, null, headers);
|
||||||
|
string body = response.Body;
|
||||||
|
response.Clear();
|
||||||
|
|
||||||
|
List<InfisicalCertificateApplicationResponseDto> source = ParseApplicationListBody(body);
|
||||||
|
InfisicalCertificateApplication[] mapped = InfisicalCertificateApplicationMapper.MapMany(source, resolvedProjectId);
|
||||||
|
_logger.Information(Component, "Infisical certificate application list retrieval was successful.");
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Error(Component, "Infisical certificate application list retrieval failed.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfisicalCertificateApplication GetCertificateApplication(InfisicalConnection connection, string applicationId, string projectId)
|
||||||
|
{
|
||||||
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
|
if (string.IsNullOrEmpty(applicationId)) { throw new InfisicalConfigurationException("ApplicationId is required."); }
|
||||||
|
|
||||||
|
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "applicationId", applicationId } };
|
||||||
|
string resolvedProjectId = FirstNonEmpty(projectId, connection.ProjectId);
|
||||||
|
Dictionary<string, string> headers = !string.IsNullOrEmpty(resolvedProjectId) ? BuildProjectHeader(resolvedProjectId) : null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information(Component, string.Concat("Attempting to retrieve Infisical certificate application '", applicationId, "'. Please Wait..."));
|
||||||
|
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.GetCertificateApplication, "GetCertificateApplication", pathParameters, null, null, headers);
|
||||||
|
string body = response.Body;
|
||||||
|
response.Clear();
|
||||||
|
|
||||||
|
InfisicalCertificateApplicationResponseDto inner = ParseApplicationSingleBody(body);
|
||||||
|
InfisicalCertificateApplication mapped = InfisicalCertificateApplicationMapper.Map(inner, resolvedProjectId);
|
||||||
|
_logger.Information(Component, "Infisical certificate application retrieval was successful.");
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Error(Component, "Infisical certificate application retrieval failed.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfisicalCertificateApplication GetCertificateApplicationByName(InfisicalConnection connection, string name, string projectId)
|
||||||
|
{
|
||||||
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
|
if (string.IsNullOrEmpty(name)) { throw new InfisicalConfigurationException("ApplicationName is required."); }
|
||||||
|
string resolvedProjectId = FirstNonEmpty(projectId, connection.ProjectId);
|
||||||
|
if (string.IsNullOrEmpty(resolvedProjectId)) { throw new InfisicalConfigurationException("ProjectId is required."); }
|
||||||
|
|
||||||
|
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "name", name } };
|
||||||
|
Dictionary<string, string> headers = BuildProjectHeader(resolvedProjectId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information(Component, string.Concat("Attempting to retrieve Infisical certificate application '", name, "' by name. Please Wait..."));
|
||||||
|
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.GetCertificateApplicationByName, "GetCertificateApplicationByName", pathParameters, null, null, headers);
|
||||||
|
string body = response.Body;
|
||||||
|
response.Clear();
|
||||||
|
|
||||||
|
InfisicalCertificateApplicationResponseDto inner = ParseApplicationSingleBody(body);
|
||||||
|
InfisicalCertificateApplication mapped = InfisicalCertificateApplicationMapper.Map(inner, resolvedProjectId);
|
||||||
|
_logger.Information(Component, "Infisical certificate application (by name) retrieval was successful.");
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Error(Component, "Infisical certificate application (by name) retrieval failed.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfisicalCertificateApplicationProfileAttachment[] ListCertificateApplicationProfiles(InfisicalConnection connection, string applicationId, string projectId)
|
||||||
|
{
|
||||||
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
|
if (string.IsNullOrEmpty(applicationId)) { throw new InfisicalConfigurationException("ApplicationId is required."); }
|
||||||
|
|
||||||
|
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "applicationId", applicationId } };
|
||||||
|
string resolvedProjectId = FirstNonEmpty(projectId, connection.ProjectId);
|
||||||
|
Dictionary<string, string> headers = !string.IsNullOrEmpty(resolvedProjectId) ? BuildProjectHeader(resolvedProjectId) : null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information(Component, string.Concat("Attempting to list profile attachments for Infisical certificate application '", applicationId, "'. Please Wait..."));
|
||||||
|
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.ListCertificateApplicationProfiles, "ListCertificateApplicationProfiles", pathParameters, null, null, headers);
|
||||||
|
string body = response.Body;
|
||||||
|
response.Clear();
|
||||||
|
|
||||||
|
List<InfisicalCertificateApplicationProfileAttachmentDto> source = ParseApplicationProfilesBody(body);
|
||||||
|
InfisicalCertificateApplicationProfileAttachment[] mapped = InfisicalCertificateApplicationMapper.MapAttachments(source);
|
||||||
|
_logger.Information(Component, "Infisical certificate application profile attachment listing was successful.");
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Error(Component, "Infisical certificate application profile attachment listing failed.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfisicalCertificateApplicationEnrollment GetCertificateApplicationEnrollment(InfisicalConnection connection, string applicationId, string profileId, string projectId)
|
||||||
|
{
|
||||||
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
|
if (string.IsNullOrEmpty(applicationId)) { throw new InfisicalConfigurationException("ApplicationId is required."); }
|
||||||
|
if (string.IsNullOrEmpty(profileId)) { throw new InfisicalConfigurationException("ProfileId is required."); }
|
||||||
|
|
||||||
|
Dictionary<string, string> pathParameters = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "applicationId", applicationId },
|
||||||
|
{ "profileId", profileId }
|
||||||
|
};
|
||||||
|
string resolvedProjectId = FirstNonEmpty(projectId, connection.ProjectId);
|
||||||
|
Dictionary<string, string> headers = !string.IsNullOrEmpty(resolvedProjectId) ? BuildProjectHeader(resolvedProjectId) : null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information(Component, string.Concat("Attempting to retrieve enrollment for application '", applicationId, "' / profile '", profileId, "'. Please Wait..."));
|
||||||
|
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.GetCertificateApplicationEnrollment, "GetCertificateApplicationEnrollment", pathParameters, null, null, headers);
|
||||||
|
InfisicalCertificateApplicationEnrollmentResponseDto dto = _serializer.Deserialize<InfisicalCertificateApplicationEnrollmentResponseDto>(response.Body);
|
||||||
|
response.Clear();
|
||||||
|
|
||||||
|
InfisicalCertificateApplicationEnrollment mapped = InfisicalCertificateApplicationMapper.MapEnrollment(dto);
|
||||||
|
_logger.Information(Component, "Infisical certificate application enrollment retrieval was successful.");
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Error(Component, "Infisical certificate application enrollment retrieval failed.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GenerateScepDynamicChallenge(InfisicalConnection connection, string applicationId, string profileId)
|
||||||
|
{
|
||||||
|
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||||
|
if (string.IsNullOrEmpty(applicationId)) { throw new InfisicalConfigurationException("ApplicationId is required."); }
|
||||||
|
if (string.IsNullOrEmpty(profileId)) { throw new InfisicalConfigurationException("ProfileId is required."); }
|
||||||
|
|
||||||
|
Dictionary<string, string> pathParameters = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "applicationId", applicationId },
|
||||||
|
{ "profileId", profileId }
|
||||||
|
};
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "Accept", "text/plain" }
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information(Component, string.Concat("Attempting to generate SCEP dynamic challenge for application '", applicationId, "' / profile '", profileId, "'. Please Wait..."));
|
||||||
|
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.GenerateScepDynamicChallenge, "GenerateScepDynamicChallenge", pathParameters, null, string.Empty, headers);
|
||||||
|
string body = response.Body != null ? response.Body.Trim() : null;
|
||||||
|
response.Clear();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(body)) { throw new InfisicalApiException("SCEP dynamic challenge response was empty."); }
|
||||||
|
_logger.Information(Component, "Infisical SCEP dynamic challenge generation was successful.");
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Error(Component, "Infisical SCEP dynamic challenge generation failed.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> BuildProjectHeader(string projectId)
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "x-infisical-project-id", projectId }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InfisicalCertificateApplicationResponseDto> ParseApplicationListBody(string body)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(body)) { return null; }
|
||||||
|
JToken token = JToken.Parse(body);
|
||||||
|
if (token.Type == JTokenType.Array)
|
||||||
|
{
|
||||||
|
return token.ToObject<List<InfisicalCertificateApplicationResponseDto>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
InfisicalCertificateApplicationListResponseDto wrapper = token.ToObject<InfisicalCertificateApplicationListResponseDto>();
|
||||||
|
return wrapper != null ? wrapper.Applications : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InfisicalCertificateApplicationResponseDto ParseApplicationSingleBody(string body)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(body)) { return null; }
|
||||||
|
JToken token = JToken.Parse(body);
|
||||||
|
if (token.Type != JTokenType.Object) { return null; }
|
||||||
|
JObject obj = (JObject)token;
|
||||||
|
|
||||||
|
if (obj["application"] is JObject inner) { return inner.ToObject<InfisicalCertificateApplicationResponseDto>(); }
|
||||||
|
return obj.ToObject<InfisicalCertificateApplicationResponseDto>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InfisicalCertificateApplicationProfileAttachmentDto> ParseApplicationProfilesBody(string body)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(body)) { return null; }
|
||||||
|
JToken token = JToken.Parse(body);
|
||||||
|
if (token.Type == JTokenType.Array)
|
||||||
|
{
|
||||||
|
return token.ToObject<List<InfisicalCertificateApplicationProfileAttachmentDto>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
InfisicalCertificateApplicationProfilesResponseDto wrapper = token.ToObject<InfisicalCertificateApplicationProfilesResponseDto>();
|
||||||
|
return wrapper != null ? wrapper.Profiles : null;
|
||||||
|
}
|
||||||
|
|
||||||
internal static InfisicalCertificateSearchRequestDto BuildSearchRequest(InfisicalCertificateSearchQuery query)
|
internal static InfisicalCertificateSearchRequestDto BuildSearchRequest(InfisicalCertificateSearchQuery query)
|
||||||
{
|
{
|
||||||
return new InfisicalCertificateSearchRequestDto
|
return new InfisicalCertificateSearchRequestDto
|
||||||
|
|||||||
Reference in New Issue
Block a user