From c356fe6023df785138ad032146ab8104ff6c9e2a Mon Sep 17 00:00:00 2001 From: David Galey Date: Tue, 1 Jul 2025 06:04:08 -0400 Subject: [PATCH 01/12] remove testbed project --- nameshield-caplugin.sln | 6 - nameshield-testbed/Program.cs | 132 ------------------- nameshield-testbed/nameshield-testbed.csproj | 15 --- 3 files changed, 153 deletions(-) delete mode 100644 nameshield-testbed/Program.cs delete mode 100644 nameshield-testbed/nameshield-testbed.csproj diff --git a/nameshield-caplugin.sln b/nameshield-caplugin.sln index c99563a..e345624 100644 --- a/nameshield-caplugin.sln +++ b/nameshield-caplugin.sln @@ -12,8 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution integration-manifest.json = integration-manifest.json EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nameshield-testbed", "nameshield-testbed\nameshield-testbed.csproj", "{6A22BA99-5C36-4CFE-B807-64CD27652F3C}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,10 +22,6 @@ Global {85906BEA-E3E6-413A-9E2C-6B9202449EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {85906BEA-E3E6-413A-9E2C-6B9202449EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {85906BEA-E3E6-413A-9E2C-6B9202449EC2}.Release|Any CPU.Build.0 = Release|Any CPU - {6A22BA99-5C36-4CFE-B807-64CD27652F3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6A22BA99-5C36-4CFE-B807-64CD27652F3C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6A22BA99-5C36-4CFE-B807-64CD27652F3C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6A22BA99-5C36-4CFE-B807-64CD27652F3C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/nameshield-testbed/Program.cs b/nameshield-testbed/Program.cs deleted file mode 100644 index cacc900..0000000 --- a/nameshield-testbed/Program.cs +++ /dev/null @@ -1,132 +0,0 @@ -// See https://aka.ms/new-console-template for more information -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; - -public class Program -{ - public static async Task Main(string[] args) - { - using (var client = new HttpClient()) - { - client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "21cee8c3-b472-443e-ba47-1fbac18d7b7e"); - - ListOrgs(client); - //OrderCertificate(client); - } - Console.ReadLine(); - Console.WriteLine("Hello, World!"); - } - - public static void ListOrgs(HttpClient client) - { - var response = client.GetAsync("https://ote-api.nameshield.net/ssl/v2/organizations").Result; - if (response.IsSuccessStatusCode) - { - var responseBody = response.Content.ReadAsStringAsync().Result; - - var responseObj = JsonConvert.DeserializeObject(responseBody); - Console.WriteLine(responseBody); - } - else - { - Console.WriteLine($"Error: {response.StatusCode}"); - var errorContent = response.Content.ReadAsStringAsync().Result; - var errorObj = JsonConvert.DeserializeObject(errorContent); - Console.WriteLine(errorContent); - } - } - - - public class ErrorData - { - [JsonProperty("errors")] - public Error Error { get; set; } - } - public class Error - { - [JsonProperty("code")] - public string Code { get; set; } - [JsonProperty("message")] - public string Message { get; set; } - } - - public class OrganizationData - { - [JsonProperty("data")] - public List Organizations { get; set; } - } - - public class Organization - { - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("attributes")] - public OrganizationAttributes Attributes { get; set; } - } - - public class OrganizationAttributes - { - [JsonProperty("name")] - public string Name { get; set; } - } - - public static async void OrderCertificate(HttpClient client) - { - var orderData = new JObject - { - ["data"] = new JObject - { - ["type"] = "order", - ["attributes"] = new JObject - { - ["action"] = "create", - ["csr"] = "-----BEGIN CERTIFICATE REQUEST-----MIICdjCCAV4CAQAwMTESMBAGA1UECgwJS2V5ZmFjdG9yMRswGQYDVQQDDBJrZXlmYWN0b3IudGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCENsFrFWrbrrVOr5XcO+yGBo4i5lGTyGNIqs1Thd0XwSRNXEHIKeQQsMbFK+vBGBCt66g6+5I60MkYbqItM5B5JlQJ79ChZu/Bb1WSNObf9Ie0T7olPUEUNecvjeHIREVWO1XdIM/eDkXIFfJykf0wJM1oAQbmhUVD2MYcbTCnc5GDWjWA2W3D2wHaK5eX8oTaEG/KwS9IttIxpuIHKyHlrPGDNzUrO3Ztbk2YyJ7EW6jJoIyzZpNQtQ+o5JVjfD5Q4vrPokmWolR2B+NwzmkNB2fA538UpZZGaedVTYHgKSpUCJGIJ+TSiywO784/LmWt52ji4452BmW6XXlPb5m3AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAOr+RROgM7YEMECD9ukTQ7uFjs09wEP8ZLXbgAlscnGtQzINjJkawCyx7CidQZz0FISBdc1YjUgBCKzfHiecYrR1FpHi+HwuvK1obbxqDz3xKZ3GW8paeNyXq6wFtAGKF4DSpeTpOnkg1Ydlh3vegT5FOXakA3g51wiRy9LquV0jNb8yL9FbvhOLG/XRDcAZ45rH9S9BwMY95o7xsmOOcZVcuCsHaQGFPM5h8VgQqAOLeRMC1tpzCRqg12yp+bbHd6yb4nNiAPSm1o+2iItDfkA+7kbA7o04JDRhFN+Oy/m5IHzyDStnhgENja3duVnK1nevLNj+pdKDm6n9FIieGjw==-----END CERTIFICATE REQUEST-----", - ["duration"] = "2 years", - }, - ["relationships"] = new JObject - { - ["product"] = new JObject - { - ["data"] = new JObject - { - ["type"] = "product", - ["id"] = "11" - } - }, - ["organization"] = new JObject - { - ["data"] = new JObject - { - ["type"] = "organization", - ["id"] = "BSVBG" - } - } - } - } - }; - - var content = new StringContent(orderData.ToString(), Encoding.UTF8, "application/json"); - Console.WriteLine(content.ReadAsStringAsync().Result); - var response = await client.PostAsync("https://ote-api.nameshield.net/ssl/v2/orders", content); - - if (response.IsSuccessStatusCode) - { - var responseBody = await response.Content.ReadAsStringAsync(); - Console.WriteLine(responseBody); - - } - else - { - Console.WriteLine($"Error: {response.StatusCode}"); - var errorContent = await response.Content.ReadAsStringAsync(); - Console.WriteLine(errorContent); - } - } -} diff --git a/nameshield-testbed/nameshield-testbed.csproj b/nameshield-testbed/nameshield-testbed.csproj deleted file mode 100644 index 7242ecf..0000000 --- a/nameshield-testbed/nameshield-testbed.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net8.0 - nameshield_testbed - disable - enable - - - - - - - From 028b38ad8277a466770c3ff6f080969085a72de5 Mon Sep 17 00:00:00 2001 From: David Galey Date: Tue, 1 Jul 2025 06:10:15 -0400 Subject: [PATCH 02/12] framework --- integration-manifest.json | 2 +- nameshield-caplugin/nameshield-caplugin.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-manifest.json b/integration-manifest.json index f7d15ff..374bc9f 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -8,7 +8,7 @@ "update_catalog": false, "description": "Nameshield plugin for the AnyCA REST Gateway framework", "gateway_framework": "24.2.0", - "release_dir": "nameshield-caplugin/bin/Release/net8.0", + "release_dir": "nameshield-caplugin/bin/Release/net6.0", "about": { "carest": { "ca_plugin_config": [ diff --git a/nameshield-caplugin/nameshield-caplugin.csproj b/nameshield-caplugin/nameshield-caplugin.csproj index 2ff43f5..054f6a7 100644 --- a/nameshield-caplugin/nameshield-caplugin.csproj +++ b/nameshield-caplugin/nameshield-caplugin.csproj @@ -1,7 +1,7 @@  - net8.0 + net6.0 Keyfactor.Extensions.CAPlugin.Nameshield enable disable From 358e19e85c7223ed5bb30d5aff43b80060bbaef2 Mon Sep 17 00:00:00 2001 From: David Galey Date: Tue, 1 Jul 2025 06:24:41 -0400 Subject: [PATCH 03/12] integration manifest --- integration-manifest.json | 73 ++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/integration-manifest.json b/integration-manifest.json index 374bc9f..7447d17 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,40 +1,41 @@ { - "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", - "integration_type": "anyca-plugin", - "name": "Nameshield AnyCA REST Gateway Plugin", - "status": "prototype", - "support_level": "community", - "link_github": false, - "update_catalog": false, - "description": "Nameshield plugin for the AnyCA REST Gateway framework", - "gateway_framework": "24.2.0", - "release_dir": "nameshield-caplugin/bin/Release/net6.0", - "about": { - "carest": { - "ca_plugin_config": [ - { - "name": "ApiUrl", - "description": "The base URL to send API requests to. Standard URLs are https://api.nameshield.net/ for production environment, and https://ote-api.nameshield.net/ for test and development" - }, - { - "name": "ApiToken", - "description": "The Bearer token to use to authenticate to the Nameshield API" - }, - { - "name": "Enabled", - "description": "Flag to Enable or Disable gateway functionality. Diabling is primarily used to allow creation of the CA prior to configuration information being available." - } - ], - "enrollment_config": [ - { - "name": "OrganizationId", - "description": "If you know your organization's ID in nameshield, you can supply that here and that will be used as the organization regardless of what values exist in the request or the Organization field" - }, - { - "name": "Organization", - "description": "If OrganizationId is empty, and an organization name is provided here, the Nameshield gateway will use that name to do organization lookups when enrolling. If neither OrganizationId nor Organization is supplied, the gateway will use whatever is in the O= field of the request subject." - } - ] + "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", + "integration_type": "anyca-plugin", + "name": "Nameshield AnyCA REST Gateway Plugin", + "status": "prototype", + "support_level": "community", + "link_github": false, + "update_catalog": false, + "description": "Nameshield plugin for the AnyCA REST Gateway framework", + "gateway_framework": "24.2.0", + "release_dir": "nameshield-caplugin/bin/Release", + "release_project": "nameshield-caplugin/nameshield-caplugin.csproj", + "about": { + "carest": { + "ca_plugin_config": [ + { + "name": "ApiUrl", + "description": "The base URL to send API requests to. Standard URLs are https://api.nameshield.net/ for production environment, and https://ote-api.nameshield.net/ for test and development" + }, + { + "name": "ApiToken", + "description": "The Bearer token to use to authenticate to the Nameshield API" + }, + { + "name": "Enabled", + "description": "Flag to Enable or Disable gateway functionality. Diabling is primarily used to allow creation of the CA prior to configuration information being available." } + ], + "enrollment_config": [ + { + "name": "OrganizationId", + "description": "If you know your organization's ID in nameshield, you can supply that here and that will be used as the organization regardless of what values exist in the request or the Organization field" + }, + { + "name": "Organization", + "description": "If OrganizationId is empty, and an organization name is provided here, the Nameshield gateway will use that name to do organization lookups when enrolling. If neither OrganizationId nor Organization is supplied, the gateway will use whatever is in the O= field of the request subject." + } + ] } + } } \ No newline at end of file From b0986ad3e03d587b0f3e9fb48fa15d3be38bd9c1 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Tue, 1 Jul 2025 10:26:37 +0000 Subject: [PATCH 04/12] Update generated docs --- integration-manifest.json | 74 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/integration-manifest.json b/integration-manifest.json index 7447d17..3511222 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,41 +1,41 @@ { - "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", - "integration_type": "anyca-plugin", - "name": "Nameshield AnyCA REST Gateway Plugin", - "status": "prototype", - "support_level": "community", - "link_github": false, - "update_catalog": false, - "description": "Nameshield plugin for the AnyCA REST Gateway framework", - "gateway_framework": "24.2.0", - "release_dir": "nameshield-caplugin/bin/Release", - "release_project": "nameshield-caplugin/nameshield-caplugin.csproj", - "about": { - "carest": { - "ca_plugin_config": [ - { - "name": "ApiUrl", - "description": "The base URL to send API requests to. Standard URLs are https://api.nameshield.net/ for production environment, and https://ote-api.nameshield.net/ for test and development" - }, - { - "name": "ApiToken", - "description": "The Bearer token to use to authenticate to the Nameshield API" - }, - { - "name": "Enabled", - "description": "Flag to Enable or Disable gateway functionality. Diabling is primarily used to allow creation of the CA prior to configuration information being available." + "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", + "integration_type": "anyca-plugin", + "name": "Nameshield AnyCA REST Gateway Plugin", + "status": "prototype", + "support_level": "community", + "link_github": false, + "update_catalog": false, + "description": "Nameshield plugin for the AnyCA REST Gateway framework", + "gateway_framework": "24.2.0", + "release_dir": "nameshield-caplugin/bin/Release", + "release_project": "nameshield-caplugin/nameshield-caplugin.csproj", + "about": { + "carest": { + "ca_plugin_config": [ + { + "name": "ApiUrl", + "description": "The base URL to send API requests to. Standard URLs are https://api.nameshield.net/ for production environment, and https://ote-api.nameshield.net/ for test and development" + }, + { + "name": "ApiToken", + "description": "The Bearer token to use to authenticate to the Nameshield API" + }, + { + "name": "Enabled", + "description": "Flag to Enable or Disable gateway functionality. Diabling is primarily used to allow creation of the CA prior to configuration information being available." + } + ], + "enrollment_config": [ + { + "name": "OrganizationId", + "description": "If you know your organization's ID in nameshield, you can supply that here and that will be used as the organization regardless of what values exist in the request or the Organization field" + }, + { + "name": "Organization", + "description": "If OrganizationId is empty, and an organization name is provided here, the Nameshield gateway will use that name to do organization lookups when enrolling. If neither OrganizationId nor Organization is supplied, the gateway will use whatever is in the O= field of the request subject." + } + ] } - ], - "enrollment_config": [ - { - "name": "OrganizationId", - "description": "If you know your organization's ID in nameshield, you can supply that here and that will be used as the organization regardless of what values exist in the request or the Organization field" - }, - { - "name": "Organization", - "description": "If OrganizationId is empty, and an organization name is provided here, the Nameshield gateway will use that name to do organization lookups when enrolling. If neither OrganizationId nor Organization is supplied, the gateway will use whatever is in the O= field of the request subject." - } - ] } - } } \ No newline at end of file From 29a3c9049568bf32de1c923003d8a338e605c1e6 Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 30 Jul 2025 00:04:18 -0400 Subject: [PATCH 05/12] fix json serialization --- nameshield-caplugin/API/RequestCertificate.cs | 22 +++++++++++++++++++ .../Client/NameshieldClient.cs | 9 +++++--- nameshield-caplugin/Models/Certificate.cs | 8 +++++++ .../Models/CertificateProduct.cs | 8 +++++++ nameshield-caplugin/Models/Error.cs | 17 +++++++++----- nameshield-caplugin/Models/Order.cs | 8 +++++++ nameshield-caplugin/Models/Organizations.cs | 5 +++++ nameshield-caplugin/Models/Products.cs | 8 +++++++ nameshield-caplugin/Models/Relationship.cs | 3 +++ nameshield-caplugin/NameshieldCAPlugin.cs | 4 ++-- nameshield-caplugin/NameshieldConfig.cs | 4 ++++ 11 files changed, 86 insertions(+), 10 deletions(-) diff --git a/nameshield-caplugin/API/RequestCertificate.cs b/nameshield-caplugin/API/RequestCertificate.cs index c69e9c6..3825962 100644 --- a/nameshield-caplugin/API/RequestCertificate.cs +++ b/nameshield-caplugin/API/RequestCertificate.cs @@ -1,11 +1,13 @@ using Keyfactor.Extensions.CAPlugin.Nameshield.Models; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.API @@ -28,42 +30,62 @@ public CertificateRequest() data.relationships.organization.data = new RelationshipData(); } + public string GetOrderData() + { + var orderData = new + { + data = data + }; + return System.Text.Json.JsonSerializer.Serialize(orderData); + } + + + [JsonPropertyName("data")] [JsonProperty("data")] public CertificateRequestData data { get; set; } } public class CertificateRequestData { + [JsonPropertyName("type")] [JsonProperty("type")] public string type { get; set; } + [JsonPropertyName("attributes")] [JsonProperty("attributes")] public CertificateRequestAttributes attributes { get; set; } + [JsonPropertyName("relationships")] [JsonProperty("relationships")] public CertificateRequestRelationships relationships { get; set; } } public class CertificateRequestAttributes { + [JsonPropertyName("action")] [JsonProperty("action")] public string action { get; set; } + [JsonPropertyName("csr")] [JsonProperty("csr")] public string csr { get; set; } + [JsonPropertyName("duration")] [JsonProperty("duration")] public string duration { get; set; } } public class CertificateRequestRelationships { + [JsonPropertyName("product")] [JsonProperty("product")] public CertRequestRel product { get; set; } + [JsonPropertyName("organization")] [JsonProperty("organization")] public CertRequestRel organization { get; set; } } public class CertRequestRel { + [JsonPropertyName("data")] [JsonProperty("data")] public RelationshipData data { get; set; } } diff --git a/nameshield-caplugin/Client/NameshieldClient.cs b/nameshield-caplugin/Client/NameshieldClient.cs index 6ff7d58..1125dbd 100644 --- a/nameshield-caplugin/Client/NameshieldClient.cs +++ b/nameshield-caplugin/Client/NameshieldClient.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Net.Http.Json; using System.Text; +using System.Text.Json; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Client @@ -115,7 +116,9 @@ public async Task GetCertificateProduct(string ID public async Task RequestCertificate(CertificateRequest req) { - var response = await RestClient.PostAsJsonAsync("ssl/v2/orders", req); + var body = req.GetOrderData(); + var content = new StringContent(body.ToString(), Encoding.UTF8, "application/json"); + var response = await RestClient.PostAsync("ssl/v2/orders", content); if (response.IsSuccessStatusCode) { string responseContent = await response.Content.ReadAsStringAsync(); @@ -125,8 +128,8 @@ public async Task RequestCertificate(CertificateRequ } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error requesting certificate: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error requesting certificate: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } diff --git a/nameshield-caplugin/Models/Certificate.cs b/nameshield-caplugin/Models/Certificate.cs index b519f0e..9c24920 100644 --- a/nameshield-caplugin/Models/Certificate.cs +++ b/nameshield-caplugin/Models/Certificate.cs @@ -6,38 +6,46 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class CertificateData { + [JsonPropertyName("data")] [JsonProperty("data")] public Certificate Certificate { get; set; } } public class CertificatesData { + [JsonPropertyName("data")] [JsonProperty("data")] public List Certificates { get; set; } } public class Certificate { + [JsonPropertyName("id")] [JsonProperty("id")] public string Id { get; set; } + [JsonPropertyName("attributes")] [JsonProperty("attributes")] public CertificateAttributes Attributes { get; set; } } public class CertificateAttributes { + [JsonPropertyName("status")] [JsonProperty("status")] public string Status { get; set; } + [JsonPropertyName("serial")] [JsonProperty("serial")] public string Serial { get; set; } + [JsonPropertyName("pem")] [JsonProperty("pem")] public string Pem { get; set; } } diff --git a/nameshield-caplugin/Models/CertificateProduct.cs b/nameshield-caplugin/Models/CertificateProduct.cs index e12d65e..e27b69e 100644 --- a/nameshield-caplugin/Models/CertificateProduct.cs +++ b/nameshield-caplugin/Models/CertificateProduct.cs @@ -6,32 +6,40 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class CertificateProductData { + [JsonPropertyName("data")] [JsonProperty("data")] public CertificateProduct CertificateProduct { get; set; } } public class CertificateProduct { + [JsonPropertyName("id")] [JsonProperty("id")] public string Id { get; set; } + [JsonPropertyName("attributes")] [JsonProperty("attributes")] public CertificateProductAttributes Attributes { get; set; } } public class CertificateProductAttributes { + [JsonPropertyName("name")] [JsonProperty("name")] public string Name { get; set; } + [JsonPropertyName("can_be_ordered")] [JsonProperty("can_be_ordered")] public bool CanBeOrdered { get; set; } + [JsonPropertyName("accept_reissue")] [JsonProperty("accept_reissue")] public bool CanReissue { get; set; } + [JsonPropertyName("allowed_durations")] [JsonProperty("allowed_durations")] public List Durations { get; set; } } diff --git a/nameshield-caplugin/Models/Error.cs b/nameshield-caplugin/Models/Error.cs index c40f0da..cec487c 100644 --- a/nameshield-caplugin/Models/Error.cs +++ b/nameshield-caplugin/Models/Error.cs @@ -4,20 +4,27 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class ErrorData { + [JsonPropertyName("errors")] [JsonProperty("errors")] - public Error Error { get; set; } + public List Errors { get; set; } } public class Error { - [JsonProperty("code")] - public string Code { get; set; } - [JsonProperty("message")] - public string Message { get; set; } + [JsonPropertyName("status")] + [JsonProperty("status")] + public string Status { get; set; } + [JsonPropertyName("title")] + [JsonProperty("title")] + public string Title { get; set; } + [JsonPropertyName("detail")] + [JsonProperty("detail")] + public string Detail { get; set; } } } diff --git a/nameshield-caplugin/Models/Order.cs b/nameshield-caplugin/Models/Order.cs index db398b6..aff4d17 100644 --- a/nameshield-caplugin/Models/Order.cs +++ b/nameshield-caplugin/Models/Order.cs @@ -6,40 +6,48 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class OrderData { + [JsonPropertyName("data")] [JsonProperty("data")] public Order Order { get; set; } } public class Order { + [JsonPropertyName("id")] [JsonProperty("id")] public string Id { get; set; } + [JsonPropertyName("attributes")] [JsonProperty("attributes")] public OrderAttributes Attributes { get; set; } + [JsonPropertyName("relationships")] [JsonProperty("relationships")] public OrderRelationships Relationships { get; set; } } public class OrderAttributes { + [JsonPropertyName("status")] [JsonProperty("status")] public string Status { get; set; } } public class OrderRelationships { + [JsonPropertyName("certificate")] [JsonProperty("certificate")] public OrderCertRelationship Certificate { get; set; } } public class OrderCertRelationship { + [JsonPropertyName("data")] [JsonProperty("data")] public RelationshipData Data { get; set; } } diff --git a/nameshield-caplugin/Models/Organizations.cs b/nameshield-caplugin/Models/Organizations.cs index d2db538..45f51cf 100644 --- a/nameshield-caplugin/Models/Organizations.cs +++ b/nameshield-caplugin/Models/Organizations.cs @@ -4,26 +4,31 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class OrganizationData { + [JsonPropertyName("data")] [JsonProperty("data")] public List Organizations { get; set; } } public class Organization { + [JsonPropertyName("id")] [JsonProperty("id")] public string Id { get; set; } + [JsonPropertyName("attributes")] [JsonProperty("attributes")] public OrganizationAttributes Attributes { get; set; } } public class OrganizationAttributes { + [JsonPropertyName("name")] [JsonProperty("name")] public string Name { get; set; } } diff --git a/nameshield-caplugin/Models/Products.cs b/nameshield-caplugin/Models/Products.cs index 2b77bdb..50a7399 100644 --- a/nameshield-caplugin/Models/Products.cs +++ b/nameshield-caplugin/Models/Products.cs @@ -4,32 +4,40 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class ProductsData { + [JsonPropertyName("data")] [JsonProperty("data")] public List Products { get; set; } } public class Product { + [JsonPropertyName("id")] [JsonProperty("id")] public string Id { get; set; } + [JsonPropertyName("attributes")] [JsonProperty("attributes")] public ProductAttributes Attributes { get; set; } } public class ProductAttributes { + [JsonPropertyName("name")] [JsonProperty("name")] public string Name { get; set; } + [JsonPropertyName("can_be_ordered")] [JsonProperty("can_be_ordered")] public bool CanBeOrdered { get; set; } + [JsonPropertyName("accept_reissue")] [JsonProperty("accept_reissue")] public bool CanReissue { get; set; } + [JsonPropertyName("allowed_durations")] [JsonProperty("allowed_durations")] public List Durations { get; set; } } diff --git a/nameshield-caplugin/Models/Relationship.cs b/nameshield-caplugin/Models/Relationship.cs index 30ae6e0..f5a7ced 100644 --- a/nameshield-caplugin/Models/Relationship.cs +++ b/nameshield-caplugin/Models/Relationship.cs @@ -4,15 +4,18 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield.Models { public class RelationshipData { + [JsonPropertyName("type")] [JsonProperty("type")] public string type { get; set; } + [JsonPropertyName("id")] [JsonProperty("id")] public string id { get; set; } } diff --git a/nameshield-caplugin/NameshieldCAPlugin.cs b/nameshield-caplugin/NameshieldCAPlugin.cs index eff347c..3aca18f 100644 --- a/nameshield-caplugin/NameshieldCAPlugin.cs +++ b/nameshield-caplugin/NameshieldCAPlugin.cs @@ -105,11 +105,11 @@ public async Task Enroll(string csr, string subject, Dictionar { throw new Exception($"Certificate request for subect {subject} was rejected"); } - else if (!string.Equals(status, "handled", StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(status, "delivered", StringComparison.OrdinalIgnoreCase)) { return new EnrollmentResult { - CARequestID = response.Order.Relationships.Certificate.Data.id, + CARequestID = response.Order.Id, Status = (int)EndEntityStatus.EXTERNALVALIDATION, StatusMessage = "Certificate is pending issuance and will be picked up by a future sync." }; diff --git a/nameshield-caplugin/NameshieldConfig.cs b/nameshield-caplugin/NameshieldConfig.cs index cf38e10..868c0ea 100644 --- a/nameshield-caplugin/NameshieldConfig.cs +++ b/nameshield-caplugin/NameshieldConfig.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Keyfactor.Extensions.CAPlugin.Nameshield @@ -12,12 +13,15 @@ public class NameshieldConfig { public NameshieldConfig() { } + [JsonPropertyName("ApiUrl")] [JsonProperty("ApiUrl")] public string ApiUrl { get; set; } + [JsonPropertyName("ApiToken")] [JsonProperty("ApiToken")] public string ApiToken { get; set; } + [JsonPropertyName("Enabled")] [JsonProperty("Enabled")] public bool Enabled { get; set; } = true; } From 80983ec043f635c240edc2c06de79ab18d1362b4 Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 30 Jul 2025 00:09:40 -0400 Subject: [PATCH 06/12] fix errors --- .../Client/NameshieldClient.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/nameshield-caplugin/Client/NameshieldClient.cs b/nameshield-caplugin/Client/NameshieldClient.cs index 1125dbd..1b95ae8 100644 --- a/nameshield-caplugin/Client/NameshieldClient.cs +++ b/nameshield-caplugin/Client/NameshieldClient.cs @@ -41,8 +41,8 @@ public async Task ListOrganizations() } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving organizations: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error retrieving organizations: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } @@ -58,8 +58,8 @@ public async Task ListProducts() } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving product list: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error retrieving product list: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } @@ -75,8 +75,8 @@ public async Task ListCertificates() } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving certificate list: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error retrieving certificate list: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } @@ -92,8 +92,8 @@ public async Task GetCertificate(string ID) } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving certificate: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error retrieving certificate: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } @@ -109,8 +109,8 @@ public async Task GetCertificateProduct(string ID } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving certificate product: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error retrieving certificate product: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } @@ -144,8 +144,8 @@ public async Task RevokeCertificate(string serialNum) } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error revoking certificate: {error.Error.Code} | {error.Error.Message}"); + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error revoking certificate: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); } } From 20d3c5bef601abbbc46fde402906b38a6eefd300 Mon Sep 17 00:00:00 2001 From: David Galey Date: Thu, 7 Aug 2025 10:40:56 -0400 Subject: [PATCH 07/12] paging for sync --- .../Client/NameshieldClient.cs | 42 +++++++++++++------ nameshield-caplugin/Models/Certificate.cs | 11 +++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/nameshield-caplugin/Client/NameshieldClient.cs b/nameshield-caplugin/Client/NameshieldClient.cs index 1b95ae8..e5de62e 100644 --- a/nameshield-caplugin/Client/NameshieldClient.cs +++ b/nameshield-caplugin/Client/NameshieldClient.cs @@ -65,19 +65,35 @@ public async Task ListProducts() public async Task ListCertificates() { - var response = await RestClient.GetAsync("ssl/v2/certificates?fields[certificate]=status,serial,pem"); - if (response.IsSuccessStatusCode) - { - string responseContent = await response.Content.ReadAsStringAsync(); - Logger.LogTrace($"GET Certificates response: {responseContent}"); - var responseObj = JsonConvert.DeserializeObject(responseContent); - return new ListCertificatesResponse { Certificates = responseObj.Certificates }; - } - else - { - var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving certificate list: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); - } + string url = "ssl/v2/certificates?fields[certificate]=status,serial,pem"; + var response = await RestClient.GetAsync(url); + List certList = new List(); + do + { + if (response.IsSuccessStatusCode) + { + string responseContent = await response.Content.ReadAsStringAsync(); + Logger.LogTrace($"GET Certificates response: {responseContent}"); + var responseObj = JsonConvert.DeserializeObject(responseContent); + certList.AddRange(responseObj.Certificates); + if (!string.IsNullOrEmpty(responseObj.Links.Next)) + { + Uri uri = new Uri(responseObj.Links.Next); + url = uri.PathAndQuery.Substring(1); // remove the leading / + response = await RestClient.GetAsync(url); + } + else + { + url = null; + } + } + else + { + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error retrieving certificate list: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); + } + } while (!string.IsNullOrEmpty(url)); + return new ListCertificatesResponse { Certificates = certList }; } public async Task GetCertificate(string ID) diff --git a/nameshield-caplugin/Models/Certificate.cs b/nameshield-caplugin/Models/Certificate.cs index 9c24920..fe8b22b 100644 --- a/nameshield-caplugin/Models/Certificate.cs +++ b/nameshield-caplugin/Models/Certificate.cs @@ -18,11 +18,22 @@ public class CertificateData public Certificate Certificate { get; set; } } + public class LinkData + { + [JsonPropertyName("next")] + [JsonProperty("next")] + public string Next { get; set; } + } + public class CertificatesData { [JsonPropertyName("data")] [JsonProperty("data")] public List Certificates { get; set; } + + [JsonPropertyName("links")] + [JsonProperty("links")] + public LinkData Links { get; set; } } public class Certificate From 6a6db185efffe35f77a4a07fb916d4700c52a09c Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Thu, 7 Aug 2025 14:43:50 +0000 Subject: [PATCH 08/12] Update generated docs --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd13b56..dcd2509 100644 --- a/README.md +++ b/README.md @@ -60,13 +60,16 @@ TODO Requirements is a required section 2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [Nameshield Gateway AnyCA Gateway REST plugin](https://github.com/Keyfactor/nameshield-caplugin/releases/latest) from GitHub. -3. Copy the unzipped directory (usually called `net6.0`) to the Extensions directory: +3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + ```shell + Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions ``` - > The directory containing the Nameshield Gateway AnyCA Gateway REST plugin DLLs (`net6.0`) can be named anything, as long as it is unique within the `Extensions` directory. + > The directory containing the Nameshield Gateway AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. 4. Restart the AnyCA Gateway REST service. From 875cbe8d32d170951e6e66936172fd6c0536a2c2 Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 2 Sep 2026 08:21:19 -0400 Subject: [PATCH 09/12] recheck status for checked_out orders --- .../Client/NameshieldClient.cs | 17 +++++++++++++++ nameshield-caplugin/NameshieldCAPlugin.cs | 21 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/nameshield-caplugin/Client/NameshieldClient.cs b/nameshield-caplugin/Client/NameshieldClient.cs index e5de62e..ea34c2b 100644 --- a/nameshield-caplugin/Client/NameshieldClient.cs +++ b/nameshield-caplugin/Client/NameshieldClient.cs @@ -149,6 +149,23 @@ public async Task RequestCertificate(CertificateRequ } } + public async Task GetOrderDetails(string reqId) + { + var response = await RestClient.GetAsync($"ssl/v2/orders/{reqId}"); + if (response.IsSuccessStatusCode) + { + string responseContent = await response.Content.ReadAsStringAsync(); + Logger.LogTrace($"GET Order Details response: {responseContent}"); + var responseObj = JsonConvert.DeserializeObject(responseContent); + return new RequestCertificateResponse { Order = responseObj.Order }; + } + else + { + var errors = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + throw new Exception($"Error pulling order details: {errors.Errors[0].Title} | {errors.Errors[0].Detail}"); + } + } + public async Task RevokeCertificate(string serialNum) { var response = await RestClient.PostAsync($"ssl/v2/certificates/{serialNum}/revoke", null); diff --git a/nameshield-caplugin/NameshieldCAPlugin.cs b/nameshield-caplugin/NameshieldCAPlugin.cs index 3aca18f..6469690 100644 --- a/nameshield-caplugin/NameshieldCAPlugin.cs +++ b/nameshield-caplugin/NameshieldCAPlugin.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.Metrics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -37,14 +38,17 @@ public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDa public async Task Enroll(string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, RequestFormat requestFormat, EnrollmentType enrollmnentType) { + _logger.MethodEntry(LogLevel.Debug); NameshieldClient client = NameshieldClient.InitializeClient(_config); var allProducts = Task.Run(async () => await client.ListProducts()).Result; + _logger.LogTrace($"Found {allProducts.Products.Count} products"); string productId = null; foreach (var product in allProducts.Products) { if (string.Equals(product.Attributes.Name, productInfo.ProductID)) { + _logger.LogTrace($"Found {productInfo.ProductID} product, using ID {product.Id}"); productId = product.Id; break; } @@ -58,6 +62,7 @@ public async Task Enroll(string csr, string subject, Dictionar if (productInfo.ProductParameters.ContainsKey(Constants.Config.Template.ORGANIZATION_ID) && !string.IsNullOrEmpty(productInfo.ProductParameters[Constants.Config.Template.ORGANIZATION_ID])) { orgId = productInfo.ProductParameters[Constants.Config.Template.ORGANIZATION_ID]; + _logger.LogTrace($"Using organization ID {orgId}"); } if (string.IsNullOrEmpty(orgId)) @@ -72,10 +77,12 @@ public async Task Enroll(string csr, string subject, Dictionar orgName = ParseSubject(subject, "O="); } var organizations = Task.Run(async () => await client.ListOrganizations()).Result; + _logger.LogTrace($"Found {organizations.Organizations.Count} organizations"); foreach (var organization in organizations.Organizations) { if (string.Equals(organization.Attributes.Name, orgName, StringComparison.OrdinalIgnoreCase)) { + _logger.LogTrace($"Found organization with name {orgName}, using ID {organization.Id}"); orgId = organization.Id; break; } @@ -105,8 +112,20 @@ public async Task Enroll(string csr, string subject, Dictionar { throw new Exception($"Certificate request for subect {subject} was rejected"); } - else if (!string.Equals(status, "delivered", StringComparison.OrdinalIgnoreCase)) + int time = 0; + while (string.Equals(status, "checked_out", StringComparison.OrdinalIgnoreCase) && time < 8) + { + _logger.LogTrace($"Cert retured CHECKED_OUT status, rechecking in 5 seconds. Pickup attempt {time} of 8"); + // Sleep for 5 seconds then try again, up to a max of 8 tries + Thread.Sleep(5000); + time++; + response = Task.Run(async () => await client.GetOrderDetails(response.Order.Id)).Result; + status = response.Order.Attributes.Status; + } + + if (!string.Equals(status, "delivered", StringComparison.OrdinalIgnoreCase)) { + _logger.LogTrace($"Cert request submitted successfully but not delivered, will be picked up by a fugure sync once it is issued."); return new EnrollmentResult { CARequestID = response.Order.Id, From 6bef37bc6b89a92fb946f055e5f4161e6fef275a Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Wed, 2 Sep 2026 12:22:55 +0000 Subject: [PATCH 10/12] Update generated docs --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dcd2509..0bfb158 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Nameshield Gateway AnyCA Gateway REST Plugin + Nameshield AnyCA Gateway REST Plugin

@@ -43,10 +43,10 @@ The Nameshield AnyCA Gateway REST plugin extends the capabilities of Nameshield ## Compatibility -The Nameshield Gateway AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2.0 and later. +The Nameshield AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2.0 and later. ## Support -The Nameshield Gateway AnyCA Gateway REST plugin is open source and community supported, meaning that there is **no SLA** applicable. +The Nameshield AnyCA Gateway REST plugin is open source and community supported, meaning that there is **no SLA** applicable. > To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. @@ -58,7 +58,7 @@ TODO Requirements is a required section 1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). -2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [Nameshield Gateway AnyCA Gateway REST plugin](https://github.com/Keyfactor/nameshield-caplugin/releases/latest) from GitHub. +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [Nameshield AnyCA Gateway REST plugin](https://github.com/Keyfactor/nameshield-caplugin/releases/latest) from GitHub. 3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: @@ -69,11 +69,11 @@ TODO Requirements is a required section Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions ``` - > The directory containing the Nameshield Gateway AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. + > The directory containing the Nameshield AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. 4. Restart the AnyCA Gateway REST service. -5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the Nameshield Gateway plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the Nameshield plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. ## Configuration From 93bb676505707f6e2796fc4d79a17b54532bb9f4 Mon Sep 17 00:00:00 2001 From: David Galey Date: Fri, 4 Sep 2026 15:35:02 -0400 Subject: [PATCH 11/12] logging --- nameshield-caplugin/NameshieldCAPlugin.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nameshield-caplugin/NameshieldCAPlugin.cs b/nameshield-caplugin/NameshieldCAPlugin.cs index 6469690..7372b89 100644 --- a/nameshield-caplugin/NameshieldCAPlugin.cs +++ b/nameshield-caplugin/NameshieldCAPlugin.cs @@ -112,11 +112,11 @@ public async Task Enroll(string csr, string subject, Dictionar { throw new Exception($"Certificate request for subect {subject} was rejected"); } - int time = 0; - while (string.Equals(status, "checked_out", StringComparison.OrdinalIgnoreCase) && time < 8) + int time = 1; + while (string.Equals(status, "checked_out", StringComparison.OrdinalIgnoreCase) && time <= 10) { - _logger.LogTrace($"Cert retured CHECKED_OUT status, rechecking in 5 seconds. Pickup attempt {time} of 8"); - // Sleep for 5 seconds then try again, up to a max of 8 tries + _logger.LogTrace($"Cert retured CHECKED_OUT status, rechecking in 5 seconds. Pickup attempt {time} of 10"); + // Sleep for 5 seconds then try again, up to a max of 10 tries Thread.Sleep(5000); time++; response = Task.Run(async () => await client.GetOrderDetails(response.Order.Id)).Result; @@ -133,6 +133,7 @@ public async Task Enroll(string csr, string subject, Dictionar StatusMessage = "Certificate is pending issuance and will be picked up by a future sync." }; } + _logger.LogTrace($"Certificate enrolled successfully"); var cert = GetSingleRecord(response.Order.Relationships.Certificate.Data.id).Result; From e254399e99589522d3201ece7b9e37dbaf60c06e Mon Sep 17 00:00:00 2001 From: David Galey Date: Fri, 4 Sep 2026 15:41:51 -0400 Subject: [PATCH 12/12] typos --- nameshield-caplugin/NameshieldCAPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nameshield-caplugin/NameshieldCAPlugin.cs b/nameshield-caplugin/NameshieldCAPlugin.cs index 7372b89..cd7714b 100644 --- a/nameshield-caplugin/NameshieldCAPlugin.cs +++ b/nameshield-caplugin/NameshieldCAPlugin.cs @@ -115,7 +115,7 @@ public async Task Enroll(string csr, string subject, Dictionar int time = 1; while (string.Equals(status, "checked_out", StringComparison.OrdinalIgnoreCase) && time <= 10) { - _logger.LogTrace($"Cert retured CHECKED_OUT status, rechecking in 5 seconds. Pickup attempt {time} of 10"); + _logger.LogTrace($"Cert request returned CHECKED_OUT status, rechecking in 5 seconds. Pickup attempt {time} of 10"); // Sleep for 5 seconds then try again, up to a max of 10 tries Thread.Sleep(5000); time++;