Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<h1 align="center" style="border-bottom: none">
Nameshield Gateway AnyCA Gateway REST Plugin
Nameshield AnyCA Gateway REST Plugin
</h1>

<p align="center">
Expand Down Expand Up @@ -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.

Expand All @@ -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:

Expand All @@ -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

Expand Down
17 changes: 17 additions & 0 deletions nameshield-caplugin/Client/NameshieldClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,23 @@ public async Task<RequestCertificateResponse> RequestCertificate(CertificateRequ
}
}

public async Task<RequestCertificateResponse> 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<OrderData>(responseContent);
return new RequestCertificateResponse { Order = responseObj.Order };
}
else
{
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error pulling order details: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

public async Task<bool> RevokeCertificate(string serialNum)
{
var response = await RestClient.PostAsync($"ssl/v2/certificates/{serialNum}/revoke", null);
Expand Down
21 changes: 20 additions & 1 deletion nameshield-caplugin/NameshieldCAPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,14 +38,17 @@ public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDa

public async Task<EnrollmentResult> Enroll(string csr, string subject, Dictionary<string, string[]> 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;
}
Expand All @@ -58,6 +62,7 @@ public async Task<EnrollmentResult> 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))
Expand All @@ -72,10 +77,12 @@ public async Task<EnrollmentResult> 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;
}
Expand Down Expand Up @@ -105,8 +112,20 @@ public async Task<EnrollmentResult> 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,
Expand Down
Loading