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
8 changes: 3 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ Add support for using the cert upload feature to upload auth certs
Switch to .NET 8

1.1.1
Allow for manual specification of enrollment term length
Add Lifetime parameter to allow for manual specification of cert validity
Bugfix - Properly handle syncs of 0 records
Allow for manual specification of enrollment term length
Add Lifetime parameter to allow for manual specification of cert validity
Bugfix - Properly handle syncs of 0 records

1.1.2
Add Lifetime parameter to allow for manual specification of cert validity
Bugfix - Properly handle syncs of 0 records
Bugfix - Properly check for existance of Lifetime parameter
76 changes: 24 additions & 52 deletions sectigo-scm-caplugin/Client/SectigoClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -34,7 +38,9 @@ public SectigoClient(HttpClient client)

public async Task<Certificate> 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<Certificate>(response);
}

Expand Down Expand Up @@ -139,7 +145,7 @@ public async Task CertificateListProducer(BlockingCollection<Certificate> certs,
public async Task<List<Certificate>> 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<List<Certificate>>(response);
}
Expand All @@ -151,37 +157,26 @@ public async Task<bool> 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<RevocationResponse>(response).Result;
return failedResp.IsSuccess;//Should throw an exception with error message from API
var resp = ProcessResponse<RevocationResponse>(response).Result;

return true;//Should throw an exception with error message from API, should only hit this if success
}

public async Task<ListOrganizationsResponse> 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<List<Organization>>(response);

return new ListOrganizationsResponse { Organizations = orgsResponse };
}

public async Task<OrganizationDetailsResponse> 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<OrganizationDetailsResponse>(response);
return orgDetailsResponse;
}
Expand All @@ -203,6 +198,7 @@ public async Task<ListPersonsResponse> ListPersons(int orgId)

public async Task<ListCustomFieldsResponse> 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<List<CustomField>>(response) };
}
Expand All @@ -214,13 +210,14 @@ public async Task<ListSslProfilesResponse> 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<List<Profile>>(response) };
}

public async Task<List<Person>> 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<List<Person>>(response);
}
Expand All @@ -229,6 +226,7 @@ public async Task<int> 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<EnrollResponse>(response);

Expand All @@ -248,35 +246,14 @@ public async Task<int> Enroll(EnrollRequest request)
}
}

public async Task<int> Renew(int sslId)
{
try
{
var response = await RestClient.PostAsJsonAsync($"api/ssl/v1/renewById/{sslId}", "");
var renewResponse = await ProcessResponse<EnrollResponse>(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<X509Certificate2> 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);
Expand All @@ -287,24 +264,19 @@ public async Task<X509Certificate2> 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<T> ProcessResponse<T>(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<T>(responseContent);
}
else
{
var error = JsonConvert.DeserializeObject<Error>(await response.Content.ReadAsStringAsync());
var error = JsonConvert.DeserializeObject<Error>(responseContent);
throw new Exception($"{error.Code} | {error.Description}");
}
}
Expand Down
4 changes: 1 addition & 3 deletions sectigo-scm-caplugin/SectigoCAPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public async Task<EnrollmentResult> Enroll(string csr, string subject, Dictionar

int termLength;
var profileTerms = Task.Run(async () => await GetProfileTerms(int.Parse(productInfo.ProductID))).Result;
if (!string.IsNullOrEmpty(productInfo.ProductParameters[Constants.Config.LIFETIME]))
if (productInfo.ProductParameters.ContainsKey(Constants.Config.LIFETIME) && !string.IsNullOrEmpty(productInfo.ProductParameters[Constants.Config.LIFETIME]))
{
var tempTerm = int.Parse(productInfo.ProductParameters[Constants.Config.LIFETIME]);
if (profileTerms.Contains(tempTerm))
Expand Down Expand Up @@ -249,8 +249,6 @@ public async Task<EnrollmentResult> 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.");
Expand Down
Loading