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
17 changes: 10 additions & 7 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,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

Expand Down
3 changes: 2 additions & 1 deletion integration-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
6 changes: 0 additions & 6 deletions nameshield-caplugin.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
22 changes: 22 additions & 0 deletions nameshield-caplugin/API/RequestCertificate.cs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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; }
}
Expand Down
88 changes: 62 additions & 26 deletions nameshield-caplugin/Client/NameshieldClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -40,8 +41,8 @@ public async Task<ListOrganizationsResponse> ListOrganizations()
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving organizations: {error.Error.Code} | {error.Error.Message}");
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving organizations: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

Expand All @@ -57,26 +58,42 @@ public async Task<ListProductsResponse> ListProducts()
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving product list: {error.Error.Code} | {error.Error.Message}");
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving product list: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

public async Task<ListCertificatesResponse> 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<CertificatesData>(responseContent);
return new ListCertificatesResponse { Certificates = responseObj.Certificates };
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(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<Certificate> certList = new List<Certificate>();
do
{
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
Logger.LogTrace($"GET Certificates response: {responseContent}");
var responseObj = JsonConvert.DeserializeObject<CertificatesData>(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<ErrorData>(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<GetCertificateResponse> GetCertificate(string ID)
Expand All @@ -91,8 +108,8 @@ public async Task<GetCertificateResponse> GetCertificate(string ID)
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving certificate: {error.Error.Code} | {error.Error.Message}");
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving certificate: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

Expand All @@ -108,14 +125,16 @@ public async Task<GetCertificateProductResponse> GetCertificateProduct(string ID
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving certificate product: {error.Error.Code} | {error.Error.Message}");
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error retrieving certificate product: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

public async Task<RequestCertificateResponse> 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();
Expand All @@ -125,8 +144,25 @@ public async Task<RequestCertificateResponse> RequestCertificate(CertificateRequ
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error requesting certificate: {error.Error.Code} | {error.Error.Message}");
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error requesting certificate: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

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}");
}
}

Expand All @@ -141,8 +177,8 @@ public async Task<bool> RevokeCertificate(string serialNum)
}
else
{
var error = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error revoking certificate: {error.Error.Code} | {error.Error.Message}");
var errors = JsonConvert.DeserializeObject<ErrorData>(await response.Content.ReadAsStringAsync());
throw new Exception($"Error revoking certificate: {errors.Errors[0].Title} | {errors.Errors[0].Detail}");
}
}

Expand Down
19 changes: 19 additions & 0 deletions nameshield-caplugin/Models/Certificate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Certificate> 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; }
}
Expand Down
8 changes: 8 additions & 0 deletions nameshield-caplugin/Models/CertificateProduct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> Durations { get; set; }
}
Expand Down
Loading
Loading