diff --git a/CHANGELOG.md b/CHANGELOG.md index 509317c..dcc26c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,5 @@ Switch to .NET 8 1.1.1 Allow for manual specification of enrollment term length - -1.1.2 Add Lifetime parameter to allow for manual specification of cert validity Bugfix - Properly handle syncs of 0 records \ No newline at end of file diff --git a/README.md b/README.md index 1a4ca46..782a9e5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Sectigo Certificate Manager Gateway AnyCA Gateway REST Plugin + Sectigo Certificate Manager AnyCA Gateway REST Plugin

@@ -45,10 +45,10 @@ The Sectigo AnyCA Gateway REST plugin extends the capabilities of the Sectigo Ce ## Compatibility -The Sectigo Certificate Manager Gateway AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2.0 and later. +The Sectigo Certificate Manager AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2.0 and later. ## Support -The Sectigo Certificate Manager Gateway AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. +The Sectigo Certificate Manager AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. > 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. @@ -61,7 +61,7 @@ In addition, for the admin account you plan to use, make sure it has the API adm 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 [Sectigo Certificate Manager Gateway AnyCA Gateway REST plugin](https://github.com/Keyfactor/sectigo-scm-caplugin/releases/latest) from GitHub. +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [Sectigo Certificate Manager AnyCA Gateway REST plugin](https://github.com/Keyfactor/sectigo-scm-caplugin/releases/latest) from GitHub. 3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: @@ -72,11 +72,11 @@ In addition, for the admin account you plan to use, make sure it has the API adm Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions ``` - > The directory containing the Sectigo Certificate Manager 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 Sectigo Certificate Manager 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 Sectigo Certificate Manager 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 Sectigo Certificate Manager plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. ## Configuration diff --git a/sectigo-scm-caplugin/Client/SectigoClient.cs b/sectigo-scm-caplugin/Client/SectigoClient.cs index 66e7caf..583a233 100644 --- a/sectigo-scm-caplugin/Client/SectigoClient.cs +++ b/sectigo-scm-caplugin/Client/SectigoClient.cs @@ -8,6 +8,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Org.BouncyCastle.Asn1.Ocsp; + using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -19,6 +21,8 @@ using System.Threading; using System.Threading.Tasks; +using Error = Keyfactor.Extensions.CAPlugin.Sectigo.API.Error; + namespace Keyfactor.Extensions.CAPlugin.Sectigo.Client { public class SectigoClient @@ -34,7 +38,9 @@ public SectigoClient(HttpClient client) public async Task GetCertificate(int sslId) { - var response = await RestClient.GetAsync($"api/ssl/v1/{sslId}"); + string url = $"api/ssl/v1/{sslId}"; + Logger.LogTrace($"API Request: GET {url}"); + var response = await RestClient.GetAsync(url); return await ProcessResponse(response); } @@ -139,7 +145,7 @@ public async Task CertificateListProducer(BlockingCollection certs, public async Task> PageCertificates(int position = 0, int size = 25, string filter = "") { string filterQueryString = string.IsNullOrEmpty(filter) ? string.Empty : $"&{filter}"; - Logger.LogTrace($"API Request: api/ssl/v1?position={position}&size={size}{filterQueryString}".TrimEnd()); + Logger.LogTrace($"API Request: GET api/ssl/v1?position={position}&size={size}{filterQueryString}".TrimEnd()); var response = await RestClient.GetAsync($"api/ssl/v1?position={position}&size={size}{filterQueryString}".TrimEnd()); return await ProcessResponse>(response); } @@ -151,23 +157,17 @@ public async Task RevokeSslCertificateById(int sslId, int revcode, string reasonCode = revcode, reason = revreason }; + Logger.LogTrace($"API Request: POST api/ssl/v1/revoke/{sslId}\nParameters: {JsonConvert.SerializeObject(data, Formatting.Indented)}"); var response = await RestClient.PostAsJsonAsync($"api/ssl/v1/revoke/{sslId}", data); - if (response.IsSuccessStatusCode) - { - return true; - } - var failedResp = ProcessResponse(response).Result; - return failedResp.IsSuccess;//Should throw an exception with error message from API + var resp = ProcessResponse(response).Result; + + return true;//Should throw an exception with error message from API, should only hit this if success } public async Task ListOrganizations() { + Logger.LogTrace($"API Request: GET api/organization/v1"); var response = await RestClient.GetAsync("api/organization/v1"); - if (response.IsSuccessStatusCode) - { - string responseContent = await response.Content.ReadAsStringAsync(); - Logger.LogTrace($"Raw Response: {responseContent}"); - } var orgsResponse = await ProcessResponse>(response); return new ListOrganizationsResponse { Organizations = orgsResponse }; @@ -175,13 +175,8 @@ public async Task ListOrganizations() public async Task GetOrganizationDetails(int orgId) { + Logger.LogTrace($"API Request: GET api/organization/v1/{orgId}"); var response = await RestClient.GetAsync($"api/organization/v1/{orgId}"); - if (response.IsSuccessStatusCode) - { - string responseContent = await response.Content.ReadAsStringAsync(); - Logger.LogTrace($"Raw Response: {responseContent}"); - } - var orgDetailsResponse = await ProcessResponse(response); return orgDetailsResponse; } @@ -203,6 +198,7 @@ public async Task ListPersons(int orgId) public async Task ListCustomFields() { + Logger.LogTrace($"API Request: GET api/ssl/v1/customFields"); var response = await RestClient.GetAsync("api/ssl/v1/customFields"); return new ListCustomFieldsResponse { CustomFields = await ProcessResponse>(response) }; } @@ -214,13 +210,14 @@ public async Task ListSslProfiles(int? orgId = null) { urlSuffix = $"?organizationId={orgId}"; } - + Logger.LogTrace($"API Request: GET api/ssl/v1/types{urlSuffix}"); var response = await RestClient.GetAsync($"api/ssl/v1/types{urlSuffix}"); return new ListSslProfilesResponse { SslProfiles = await ProcessResponse>(response) }; } public async Task> PagePersons(int orgId, int position = 0, int size = 25) { + Logger.LogTrace($"API Request: GET api/person/v1?position={position}&size={size}&organizationId={orgId}"); var response = await RestClient.GetAsync($"api/person/v1?position={position}&size={size}&organizationId={orgId}"); return await ProcessResponse>(response); } @@ -229,6 +226,7 @@ public async Task Enroll(EnrollRequest request) { try { + Logger.LogTrace($"API Request: POST api/ssl/v1/enroll\nParameters: {JsonConvert.SerializeObject(request, Formatting.Indented)}"); var response = await RestClient.PostAsJsonAsync("api/ssl/v1/enroll", request); var enrollResponse = await ProcessResponse(response); @@ -248,35 +246,14 @@ public async Task Enroll(EnrollRequest request) } } - public async Task Renew(int sslId) - { - try - { - var response = await RestClient.PostAsJsonAsync($"api/ssl/v1/renewById/{sslId}", ""); - var renewResponse = await ProcessResponse(response); - - return renewResponse.sslId; - } - catch (InvalidOperationException invalidOp) - { - throw new Exception($"Invalid Operation. {invalidOp.Message}|{invalidOp.StackTrace}"); - } - catch (HttpRequestException httpEx) - { - throw new Exception($"HttpRequestException. {httpEx.Message}|{httpEx.StackTrace}"); - } - catch (Exception) - { - throw; - } - } - public async Task PickupCertificate(int sslId, string subject) { + Logger.LogTrace($"API Request: GET api/ssl/v1/collect/{sslId}/x509C0"); var response = await RestClient.GetAsync($"api/ssl/v1/collect/{sslId}/x509CO"); - + if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength > 0) { + Logger.LogTrace($"Raw response: {response.Content.ReadAsStringAsync()}"); string pemChain = await response.Content.ReadAsStringAsync(); string[] splitChain = pemChain.Replace("\r\n", string.Empty).Split(new string[] { "-----" }, StringSplitOptions.RemoveEmptyEntries); @@ -287,24 +264,19 @@ public async Task PickupCertificate(int sslId, string subject) //return new X509Certificate2(); } - public async Task Reissue(ReissueRequest request, int sslId) - { - var response = await RestClient.PostAsJsonAsync($"api/ssl/v1/replace/{sslId}", request); - response.EnsureSuccessStatusCode(); - } - #region Static Methods private static async Task ProcessResponse(HttpResponseMessage response) { + string responseContent = await response.Content.ReadAsStringAsync(); + Logger.LogDebug($"Raw API response: {responseContent}"); if (response.IsSuccessStatusCode) { - string responseContent = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(responseContent); } else { - var error = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + var error = JsonConvert.DeserializeObject(responseContent); throw new Exception($"{error.Code} | {error.Description}"); } } diff --git a/sectigo-scm-caplugin/SectigoCAPlugin.cs b/sectigo-scm-caplugin/SectigoCAPlugin.cs index c21ea3d..dcb46db 100644 --- a/sectigo-scm-caplugin/SectigoCAPlugin.cs +++ b/sectigo-scm-caplugin/SectigoCAPlugin.cs @@ -249,8 +249,6 @@ public async Task Enroll(string csr, string subject, Dictionar }; _logger.LogDebug($"Submit {enrollmentType} request"); - var jsonReq = JsonConvert.SerializeObject(request, Formatting.Indented); - _logger.LogDebug($"Request object: {jsonReq}"); sslId = Task.Run(async () => await client.Enroll(request)).Result; newCert = Task.Run(async () => await client.GetCertificate(sslId)).Result; _logger.LogDebug($"Enrolled for Certificate {newCert.CommonName} (ID: {newCert.Id}) | Status: {newCert.status}. Attempt to Pickup Certificate.");