diff --git a/README.md b/README.md index bd13b56..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,19 +58,22 @@ 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: -3. Copy the unzipped directory (usually called `net6.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 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 diff --git a/integration-manifest.json b/integration-manifest.json index f7d15ff..3511222 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -8,7 +8,8 @@ "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", + "release_project": "nameshield-caplugin/nameshield-caplugin.csproj", "about": { "carest": { "ca_plugin_config": [ 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-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..ea34c2b 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 @@ -40,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}"); } } @@ -57,26 +58,42 @@ 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}"); } } 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 error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - throw new Exception($"Error retrieving certificate list: {error.Error.Code} | {error.Error.Message}"); - } + 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) @@ -91,8 +108,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}"); } } @@ -108,14 +125,16 @@ 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}"); } } 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 +144,25 @@ 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}"); + } + } + + 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}"); } } @@ -141,8 +177,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}"); } } diff --git a/nameshield-caplugin/Models/Certificate.cs b/nameshield-caplugin/Models/Certificate.cs index b519f0e..fe8b22b 100644 --- a/nameshield-caplugin/Models/Certificate.cs +++ b/nameshield-caplugin/Models/Certificate.cs @@ -6,38 +6,57 @@ 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 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 { + [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..cd7714b 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,15 +112,28 @@ 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)) + int time = 1; + while (string.Equals(status, "checked_out", StringComparison.OrdinalIgnoreCase) && time <= 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++; + 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.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." }; } + _logger.LogTrace($"Certificate enrolled successfully"); var cert = GetSingleRecord(response.Order.Relationships.Certificate.Data.id).Result; 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; } 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 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 - - - - - - -