From adaa335ed6611889a6af215dd864dfd251792b59 Mon Sep 17 00:00:00 2001 From: David Galey Date: Fri, 7 Apr 2023 08:56:11 -0400 Subject: [PATCH 01/39] Properly log JSON request body objects --- CHANGELOG.md | 28 ++- GoDaddy.sln | 4 +- GoDaddy/API/APIProcessor.cs | 406 +++++++++++++++++++----------------- 3 files changed, 228 insertions(+), 210 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d38975..95f7897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,21 @@ -v1.0.4/1.0.5 -- Update nuget packages +v1.0.0: +- Original Version -v1.0.3 -- Code cleanup, publish to github. +v1.0.1 +- Added support for 5 OV and 2 EV GoDaddy products +- Added Renew/Reissue functionality -v1.0.2 -- Remove PEM header before returning certificates during sync and enrollment +v1.0.2 +- Remove PEM header before returning certificates during sync and enrollment -v1.0.1 -- Added support for 5 OV and 2 EV GoDaddy products -- Added Renew/Reissue functionality +v1.0.3 +- Code cleanup, publish to github. -v1.0.0: -- Original Version +v1.0.4/1.0.5 +- Update nuget packages + +v1.0.6 +- Code cleanup + +v1.0.7 +- Improved logging \ No newline at end of file diff --git a/GoDaddy.sln b/GoDaddy.sln index cf6ff0c..5a48d55 100644 --- a/GoDaddy.sln +++ b/GoDaddy.sln @@ -8,11 +8,11 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5D9941D2-A44F-4593-A33E-F5E0C861CAEB}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore - CHANGELOG.MD = CHANGELOG.MD + CHANGELOG.md = CHANGELOG.md GoDaddy.sln.licenseheader = GoDaddy.sln.licenseheader integration-manifest.json = integration-manifest.json README.md = README.md - README.md.tpl = README.md.tpl + readme_source.md = readme_source.md EndProjectSection EndProject Global diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 1258212..d228679 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -1,11 +1,11 @@ // Copyright 2021 Keyfactor -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,234 +21,246 @@ namespace Keyfactor.AnyGateway.GoDaddy.API { - class APIProcessor : LoggingClientBase - { - private string ApiUrl { get; set; } - private string ApiKey { get; set; } - private string ShopperId { get; set; } + internal class APIProcessor : LoggingClientBase + { + private string ApiUrl { get; set; } + private string ApiKey { get; set; } + private string ShopperId { get; set; } + public APIProcessor(string apiUrl, string apiKey, string shopperId) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - public APIProcessor(string apiUrl, string apiKey, string shopperId) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + ApiUrl = apiUrl; + ApiKey = apiKey; + ShopperId = shopperId; - ApiUrl = apiUrl; - ApiKey = apiKey; - ShopperId = shopperId; + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - } + public string EnrollCSR(string csr, POSTCertificateRequest requestBody) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - public string EnrollCSR(string csr, POSTCertificateRequest requestBody) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - - string rtnMessage = string.Empty; + string rtnMessage = string.Empty; - string RESOURCE = "v1/certificates"; - RestRequest request = new RestRequest(RESOURCE, Method.POST); + string RESOURCE = "v1/certificates"; + RestRequest request = new RestRequest(RESOURCE, Method.POST); - request.AddJsonBody(requestBody); + request.AddJsonBody(requestBody); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return SubmitRequest(request); - } + Logger.Trace($"Json Request Body: {JsonConvert.SerializeObject(requestBody)}"); - public string RenewReissueCSR(string certificateId, string csr, POSTCertificateRenewalRequest requestBody, bool isRenew) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + return SubmitRequest(request); + } - string rtnMessage = string.Empty; - string endpoint = isRenew ? "renew" : "reissue"; + public string RenewReissueCSR(string certificateId, string csr, POSTCertificateRenewalRequest requestBody, bool isRenew) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - string RESOURCE = $"v1/certificates/{certificateId}/{endpoint}"; - RestRequest request = new RestRequest(RESOURCE, Method.POST); + string rtnMessage = string.Empty; + string endpoint = isRenew ? "renew" : "reissue"; - request.AddJsonBody(requestBody); + string RESOURCE = $"v1/certificates/{certificateId}/{endpoint}"; + RestRequest request = new RestRequest(RESOURCE, Method.POST); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + request.AddJsonBody(requestBody); - return SubmitRequest(request); - } + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - public string GetCertificates(string customerId, int pageNumber, int pageSize) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Logger.Trace($"Json Request Body: {JsonConvert.SerializeObject(requestBody)}"); - string rtnMessage = string.Empty; + return SubmitRequest(request); + } - string RESOURCE = $"v2/customers/{customerId}/certificates?offset={pageNumber.ToString()}&limit={pageSize.ToString()}"; - RestRequest request = new RestRequest(RESOURCE, Method.GET); + public string GetCertificates(string customerId, int pageNumber, int pageSize) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + string rtnMessage = string.Empty; - return SubmitRequest(request); - } + string RESOURCE = $"v2/customers/{customerId}/certificates?offset={pageNumber.ToString()}&limit={pageSize.ToString()}"; + RestRequest request = new RestRequest(RESOURCE, Method.GET); - public string GetCertificate(string certificateId) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - string rtnMessage = string.Empty; + return SubmitRequest(request); + } - string RESOURCE = $"v1/certificates/{certificateId}"; - RestRequest request = new RestRequest(RESOURCE, Method.GET); + public string GetCertificate(string certificateId) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + string rtnMessage = string.Empty; - return SubmitRequest(request); - } + string RESOURCE = $"v1/certificates/{certificateId}"; + RestRequest request = new RestRequest(RESOURCE, Method.GET); - public string DownloadCertificate(string certificateId) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - string rtnMessage = string.Empty; + return SubmitRequest(request); + } - string RESOURCE = $"v1/certificates/{certificateId}/download"; - RestRequest request = new RestRequest(RESOURCE, Method.GET); + public string DownloadCertificate(string certificateId) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + string rtnMessage = string.Empty; - return SubmitRequest(request); - } - - public void RevokeCertificate(string certificateId, POSTCertificateRevokeRequest.REASON reason) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + string RESOURCE = $"v1/certificates/{certificateId}/download"; + RestRequest request = new RestRequest(RESOURCE, Method.GET); - string rtnMessage = string.Empty; + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - string RESOURCE = $"v1/certificates/{certificateId}/revoke"; - RestRequest request = new RestRequest(RESOURCE, Method.POST); + return SubmitRequest(request); + } - POSTCertificateRevokeRequest body = new POSTCertificateRevokeRequest(); - body.reason = reason.ToString(); + public void RevokeCertificate(string certificateId, POSTCertificateRevokeRequest.REASON reason) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - request.AddJsonBody(body); - SubmitRequest(request); + string rtnMessage = string.Empty; - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - } + string RESOURCE = $"v1/certificates/{certificateId}/revoke"; + RestRequest request = new RestRequest(RESOURCE, Method.POST); - public string GetCustomerId() - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + POSTCertificateRevokeRequest body = new POSTCertificateRevokeRequest(); + body.reason = reason.ToString(); - string rtnMessage = string.Empty; - - string RESOURCE = $"v1/shoppers/{ShopperId}?includes=customerId"; - RestRequest request = new RestRequest(RESOURCE, Method.GET); - - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - - return SubmitRequest(request); - } - - public static int MapReturnStatus(CertificateStatusEnum status) - { - PKIConstants.Microsoft.RequestDisposition returnStatus = PKIConstants.Microsoft.RequestDisposition.UNKNOWN; - - switch (status) - { - case CertificateStatusEnum.DENIED: - returnStatus = PKIConstants.Microsoft.RequestDisposition.DENIED; - break; - case CertificateStatusEnum.EXPIRED: - case CertificateStatusEnum.CURRENT: - case CertificateStatusEnum.ISSUED: - returnStatus = PKIConstants.Microsoft.RequestDisposition.ISSUED; - break; - case CertificateStatusEnum.PENDING_ISSUANCE: - returnStatus = PKIConstants.Microsoft.RequestDisposition.EXTERNAL_VALIDATION; - break; - case CertificateStatusEnum.REVOKED: - returnStatus = PKIConstants.Microsoft.RequestDisposition.REVOKED; - break; - default: - returnStatus = PKIConstants.Microsoft.RequestDisposition.FAILED; - break; - } - - return Convert.ToInt32(returnStatus); - } - - public static POSTCertificateRevokeRequest.REASON MapRevokeReason(uint reason) - { - POSTCertificateRevokeRequest.REASON returnReason = POSTCertificateRevokeRequest.REASON.PRIVILEGE_WITHDRAWN; - - switch (reason) - { - case 1: - returnReason = POSTCertificateRevokeRequest.REASON.KEY_COMPROMISE; - break; - case 3: - returnReason = POSTCertificateRevokeRequest.REASON.AFFILIATION_CHANGED; - break; - case 4: - returnReason = POSTCertificateRevokeRequest.REASON.SUPERSEDED; - break; - case 5: - returnReason = POSTCertificateRevokeRequest.REASON.CESSATION_OF_OPERATION; - break; - } - - return returnReason; - } - - - #region Private Methods - private string SubmitRequest(RestRequest request) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - Logger.Trace($"Request Resource: {request.Resource}"); - Logger.Trace($"Request Method: {request.Method.ToString()}"); - Logger.Trace($"Request Body: {(request.Body == null ? string.Empty : request.Body.Value.ToString())}"); - - IRestResponse response; - - RestClient client = new RestClient(ApiUrl); - request.AddHeader("Authorization", ApiKey); - - try - { - response = client.Execute(request); - } - catch (Exception ex) - { - string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}"); - Logger.Error(exceptionMessage); - throw new GoDaddyException(exceptionMessage); - } - - if (response.StatusCode != System.Net.HttpStatusCode.OK && - response.StatusCode != System.Net.HttpStatusCode.Accepted && - response.StatusCode != System.Net.HttpStatusCode.Created && - response.StatusCode != System.Net.HttpStatusCode.NoContent) - { - string errorMessage; - - try - { - APIError error = JsonConvert.DeserializeObject(response.Content); - errorMessage = $"{error.code}: {error.message}"; - } - catch (JsonReaderException ex) - { - errorMessage = response.Content; - } - - string exceptionMessage = $"Error processing {request.Resource}: {errorMessage}"; - Logger.Error(exceptionMessage); - throw new GoDaddyException(exceptionMessage); - } - - Logger.Trace($"API Result: {response.Content}"); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - - return response.Content; - } - #endregion - } -} + request.AddJsonBody(body); + + Logger.Trace($"Json Request Body: {JsonConvert.SerializeObject(body)}"); + SubmitRequest(request); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } + + public string GetCustomerId() + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + string rtnMessage = string.Empty; + + string RESOURCE = $"v1/shoppers/{ShopperId}?includes=customerId"; + RestRequest request = new RestRequest(RESOURCE, Method.GET); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + return SubmitRequest(request); + } + + public static int MapReturnStatus(CertificateStatusEnum status) + { + PKIConstants.Microsoft.RequestDisposition returnStatus = PKIConstants.Microsoft.RequestDisposition.UNKNOWN; + + switch (status) + { + case CertificateStatusEnum.DENIED: + returnStatus = PKIConstants.Microsoft.RequestDisposition.DENIED; + break; + + case CertificateStatusEnum.EXPIRED: + case CertificateStatusEnum.CURRENT: + case CertificateStatusEnum.ISSUED: + returnStatus = PKIConstants.Microsoft.RequestDisposition.ISSUED; + break; + + case CertificateStatusEnum.PENDING_ISSUANCE: + returnStatus = PKIConstants.Microsoft.RequestDisposition.EXTERNAL_VALIDATION; + break; + + case CertificateStatusEnum.REVOKED: + returnStatus = PKIConstants.Microsoft.RequestDisposition.REVOKED; + break; + + default: + returnStatus = PKIConstants.Microsoft.RequestDisposition.FAILED; + break; + } + + return Convert.ToInt32(returnStatus); + } + + public static POSTCertificateRevokeRequest.REASON MapRevokeReason(uint reason) + { + POSTCertificateRevokeRequest.REASON returnReason = POSTCertificateRevokeRequest.REASON.PRIVILEGE_WITHDRAWN; + + switch (reason) + { + case 1: + returnReason = POSTCertificateRevokeRequest.REASON.KEY_COMPROMISE; + break; + + case 3: + returnReason = POSTCertificateRevokeRequest.REASON.AFFILIATION_CHANGED; + break; + + case 4: + returnReason = POSTCertificateRevokeRequest.REASON.SUPERSEDED; + break; + + case 5: + returnReason = POSTCertificateRevokeRequest.REASON.CESSATION_OF_OPERATION; + break; + } + + return returnReason; + } + + #region Private Methods + + private string SubmitRequest(RestRequest request) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Logger.Trace($"Request Resource: {request.Resource}"); + Logger.Trace($"Request Method: {request.Method.ToString()}"); + + IRestResponse response; + + RestClient client = new RestClient(ApiUrl); + request.AddHeader("Authorization", ApiKey); + + try + { + response = client.Execute(request); + } + catch (Exception ex) + { + string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}"); + Logger.Error(exceptionMessage); + throw new GoDaddyException(exceptionMessage); + } + + if (response.StatusCode != System.Net.HttpStatusCode.OK && + response.StatusCode != System.Net.HttpStatusCode.Accepted && + response.StatusCode != System.Net.HttpStatusCode.Created && + response.StatusCode != System.Net.HttpStatusCode.NoContent) + { + string errorMessage; + + try + { + APIError error = JsonConvert.DeserializeObject(response.Content); + errorMessage = $"{error.code}: {error.message}"; + } + catch (JsonReaderException ex) + { + errorMessage = response.Content; + } + + string exceptionMessage = $"Error processing {request.Resource}: {errorMessage}"; + Logger.Error(exceptionMessage); + throw new GoDaddyException(exceptionMessage); + } + + Logger.Trace($"API Result: {response.Content}"); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + return response.Content; + } + + #endregion Private Methods + } +} \ No newline at end of file From 5d8ce0e0ff4c9a535086dfa05b76c2c5f8f7bbfc Mon Sep 17 00:00:00 2001 From: kfadmin Date: Fri, 7 Apr 2023 17:17:32 +0000 Subject: [PATCH 02/39] changes --- GoDaddy/API/APIProcessor.cs | 9 +++++++-- readme_source.md | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index d228679..f1b5d3a 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -27,7 +27,12 @@ internal class APIProcessor : LoggingClientBase private string ApiKey { get; set; } private string ShopperId { get; set; } - public APIProcessor(string apiUrl, string apiKey, string shopperId) + + private const string NO_CERTS_PURCHASED_MESSAGE = "Failed to create certificate order"; + private const string NO_CERTS_PURCHASED_REPL_MESSAGE = "Failed to create certificate order. This error often occurs if there are no certificates purchased to fulfill this enrollment request. " + + "Please check your GoDaddy account to make sure you have the correct SSL certificate product purchased to cover this enrollment."; + + public APIProcessor(string apiUrl, string apiKey, string shopperId) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -228,7 +233,7 @@ private string SubmitRequest(RestRequest request) } catch (Exception ex) { - string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}"); + string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}").Replace(NO_CERTS_PURCHASED_MESSAGE, NO_CERTS_PURCHASED_REPL_MESSAGE); Logger.Error(exceptionMessage); throw new GoDaddyException(exceptionMessage); } diff --git a/readme_source.md b/readme_source.md index de9e089..a532f39 100644 --- a/readme_source.md +++ b/readme_source.md @@ -28,6 +28,8 @@ To begin, you must have the AnyGateway Service installed and operational before A production GoDaddy account must be set up that will be associated with the gateway and an API Key/Secret created. For more information on how to create an API Key, follow the instructions [here](https://developer.godaddy.com/keys). +For enrollment, make sure you have pre-purchased enough certificates of the type you will be enrolling before attempting to enroll certificates via this gateway. The gateway itself does not purchase certificates and requires that the product (certificate) be pre-purchased for the gateway to enroll it successfully. + ### Installation and Configuration ##### Step 1 - Install the GoDaddy root and intermediate certificates. From 2df9e8a37c15388840afbd17806a8955b7d5e4b9 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Fri, 7 Apr 2023 17:23:45 +0000 Subject: [PATCH 03/39] changes --- readme_source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme_source.md b/readme_source.md index a532f39..92165f8 100644 --- a/readme_source.md +++ b/readme_source.md @@ -28,7 +28,7 @@ To begin, you must have the AnyGateway Service installed and operational before A production GoDaddy account must be set up that will be associated with the gateway and an API Key/Secret created. For more information on how to create an API Key, follow the instructions [here](https://developer.godaddy.com/keys). -For enrollment, make sure you have pre-purchased enough certificates of the type you will be enrolling before attempting to enroll certificates via this gateway. The gateway itself does not purchase certificates and requires that the product (certificate) be pre-purchased for the gateway to enroll it successfully. +For enrollment, make sure you have pre-purchased enough certificates of the type you will be enrolling before attempting to enroll certificates via this gateway. The gateway itself does not purchase certificates and requires that the product (certificate) be pre-purchased for the gateway to enroll it successfully. The certificate may be purchased using any payment method including but not limited to GoDaddy's Good as Gold or in store credits, but just having these funds available is not enough. The product MUST actually be pre-purchased using an available payment method. ### Installation and Configuration From b53e9bb2c785e27001fad47e593eee14b758ed4b Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 7 Apr 2023 17:36:24 +0000 Subject: [PATCH 04/39] Update generated README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5c55f7f..94a9daf 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ To begin, you must have the AnyGateway Service installed and operational before A production GoDaddy account must be set up that will be associated with the gateway and an API Key/Secret created. For more information on how to create an API Key, follow the instructions [here](https://developer.godaddy.com/keys). +For enrollment, make sure you have pre-purchased enough certificates of the type you will be enrolling before attempting to enroll certificates via this gateway. The gateway itself does not purchase certificates and requires that the product (certificate) be pre-purchased for the gateway to enroll it successfully. The certificate may be purchased using any payment method including but not limited to GoDaddy's Good as Gold or in store credits, but just having these funds available is not enough. The product MUST actually be pre-purchased using an available payment method. + ### Installation and Configuration ##### Step 1 - Install the GoDaddy root and intermediate certificates. From 1b6d723454dd39e6da556c63f3d9dcd244f454cb Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 12 Apr 2023 13:02:36 -0400 Subject: [PATCH 05/39] adding more logging --- GoDaddy/API/APIProcessor.cs | 9 +- GoDaddy/GoDaddyCAProxy.cs | 480 +++++++++++++++++++++++++++++++++++- 2 files changed, 473 insertions(+), 16 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index f1b5d3a..0f91af3 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -27,12 +27,12 @@ internal class APIProcessor : LoggingClientBase private string ApiKey { get; set; } private string ShopperId { get; set; } - private const string NO_CERTS_PURCHASED_MESSAGE = "Failed to create certificate order"; - private const string NO_CERTS_PURCHASED_REPL_MESSAGE = "Failed to create certificate order. This error often occurs if there are no certificates purchased to fulfill this enrollment request. " + - "Please check your GoDaddy account to make sure you have the correct SSL certificate product purchased to cover this enrollment."; - public APIProcessor(string apiUrl, string apiKey, string shopperId) + private const string NO_CERTS_PURCHASED_REPL_MESSAGE = "Failed to create certificate order. This error often occurs if there are no certificates purchased to fulfill this enrollment request. " + + "Please check your GoDaddy account to make sure you have the correct SSL certificate product purchased to cover this enrollment."; + + public APIProcessor(string apiUrl, string apiKey, string shopperId) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -237,6 +237,7 @@ private string SubmitRequest(RestRequest request) Logger.Error(exceptionMessage); throw new GoDaddyException(exceptionMessage); } + Logger.Trace($"Response Status Code: {response.StatusCode}"); if (response.StatusCode != System.Net.HttpStatusCode.OK && response.StatusCode != System.Net.HttpStatusCode.Accepted && diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 7e7912b..9cea146 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -1,16 +1,472 @@ -// Copyright 2021 Keyfactor // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using CAProxy.AnyGateway.Interfaces; using CAProxy.AnyGateway.Models; using CAProxy.Common; using CSS.Common; using CSS.Common.Logging; using Keyfactor.PKI; using Keyfactor.PKI.PEM; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using Keyfactor.AnyGateway.GoDaddy.API; using Keyfactor.AnyGateway.GoDaddy.Models; namespace Keyfactor.AnyGateway.GoDaddy { public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector { private APIProcessor _api { get; set; } private string _rootType { get; set; } private int _syncPageSize { get; set; } private int _enrollmentRetries { get; set; } private int _secondsBetweenEnrollmentRetries { get; set; } private string[][] _connectionKeys = new string[][] { new string[] { "ApiUrl", "string" }, new string[] { "ApiKey", "string" }, new string[] { "ShopperId", "string" }, new string[] { "RootType", "string" }, new string[] { "SyncPageSize", "int" }, new string[] { "EnrollmentRetries", "int" }, new string[] { "SecondsBetweenEnrollmentRetries", "int" } }; #region Interface Methods public override void Initialize(ICAConnectorConfigProvider configProvider) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); foreach (KeyValuePair configEntry in configProvider.CAConnectionData) Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); ValidateParameters(configProvider.CAConnectionData, _connectionKeys); string apiUrl = configProvider.CAConnectionData["ApiUrl"].ToString(); string apiKey = configProvider.CAConnectionData["ApiKey"].ToString(); string shopperId = configProvider.CAConnectionData["ShopperId"].ToString(); _rootType = configProvider.CAConnectionData["RootType"].ToString(); _syncPageSize = Convert.ToInt32(configProvider.CAConnectionData["SyncPageSize"]); _enrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["EnrollmentRetries"]); _secondsBetweenEnrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"]); _api = new APIProcessor(apiUrl, apiKey, shopperId); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } public override void Ping() { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } public override void ValidateCAConnectionInfo(Dictionary connectionInfo) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); ValidateParameters(connectionInfo, _connectionKeys); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } [Obsolete] public override void Synchronize(ICertificateDataReader certificateDataReader, BlockingCollection blockingBuffer, CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, CancellationToken cancelToken, string logicalName) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); throw new NotImplementedException(); } public override void Synchronize(ICertificateDataReader certificateDataReader, BlockingCollection blockingBuffer, CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, CancellationToken cancelToken) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); string customerId = JsonConvert.DeserializeObject(_api.GetCustomerId()).customerId; int pageNumber = 1; bool wasLastPage = false; do { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); foreach (CertificateDetails certificate in certificates.certificates) { Thread.Sleep(1000); try { string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId)).pems.certificate); CertificateStatusEnum certStatus = CertificateStatusEnum.ISSUED; if (!Enum.TryParse(certificate.status, out certStatus)) certStatus = CertificateStatusEnum.CANCELED; blockingBuffer.Add(new CAConnectorCertificate { CARequestID = certificate.certificateId, Certificate = issuedCert, CSR = string.Empty, ResolutionDate = certificate.completedAt, RevocationDate = certificate.revokedAt, RevocationReason = null, Status = APIProcessor.MapReturnStatus(certStatus), SubmissionDate = certificate.createdAt, ProductID = certificate.type }); } catch (GoDaddyException) { } } wasLastPage = certificates.pagination.previous == certificates.pagination.last; pageNumber++; } while (!wasLastPage); blockingBuffer.CompleteAdding(); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } [Obsolete] public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, CSS.PKI.PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); throw new NotImplementedException(); } public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader, string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, CSS.PKI.PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); foreach (KeyValuePair configEntry in productInfo.ProductParameters) Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); +// Copyright 2021 Keyfactor +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - string[][] parameterKeys = new string[][] { }; if (enrollmentType == RequestUtilities.EnrollmentType.New) - parameterKeys = new string[][] { new string[] { "Email", "string" }, new string[] { "FirstName", "string" }, new string[] { "LastName", "string" }, new string[] { "Phone", "string" }, new string[] { "CertificatePeriodInYears", "int" } }; else - parameterKeys = new string[][] { new string[] { "PriorCertSN", "string" } }; +using CAProxy.AnyGateway.Interfaces; using CAProxy.AnyGateway.Models; using CAProxy.Common; using CSS.Common; using CSS.Common.Logging; using Keyfactor.PKI; using Keyfactor.PKI.PEM; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using Keyfactor.AnyGateway.GoDaddy.API; using Keyfactor.AnyGateway.GoDaddy.Models; namespace Keyfactor.AnyGateway.GoDaddy { + public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector + { + private APIProcessor _api { get; set; } + private string _rootType { get; set; } + private int _syncPageSize { get; set; } + private int _enrollmentRetries { get; set; } + private int _secondsBetweenEnrollmentRetries { get; set; } - ValidateParameters(productInfo.ProductParameters, parameterKeys); - POSTCertificateEnrollmentResponse enrollmentResponse = new POSTCertificateEnrollmentResponse(); try { - switch (enrollmentType) { case RequestUtilities.EnrollmentType.New: - switch (productInfo.ProductID) { case "DV_SSL": case "DV_WILDCARD_SSL": case "UCC_DV_SSL": enrollmentResponse = EnrollDV(productInfo, csr, san); break; case "OV_SSL": case "OV_CS": case "OV_DS": case "OV_WILDCARD_SSL": case "UCC_OV_SSL": enrollmentResponse = EnrollOV(productInfo, csr, san); break; case "EV_SSL": case "UCC_EV_SSL": enrollmentResponse = EnrollEV(productInfo, csr, san); break; default: return new EnrollmentResult { Status = 30, StatusMessage = $"Error attempting to enroll certificate {subject}: Invalid Product ID - {productInfo.ProductID}." }; } break; case RequestUtilities.EnrollmentType.Renew: case RequestUtilities.EnrollmentType.Reissue: - CAConnectorCertificate certificate = certificateDataReader.GetCertificateRecord(DataConversion.HexToBytes(productInfo.ProductParameters["PriorCertSN"])); enrollmentResponse = RenewReissue(certificate.CARequestID, productInfo, csr, san, enrollmentType == RequestUtilities.EnrollmentType.Renew); break; default: return new EnrollmentResult { Status = 30, StatusMessage = $"Unsupported EnrollmentType: {enrollmentType}" }; } } catch (Exception ex) { return new EnrollmentResult { Status = 30, StatusMessage = $"Error attempting to enroll certificate {subject}: {ex.Message}." }; } EnrollmentResult result = new EnrollmentResult(); CertificateStatusEnum certStatus = CertificateStatusEnum.PENDING_ISSUANCE; for(int i = 0; i < _enrollmentRetries; i++) { try { GETCertificateDetailsResponse certResponse = JsonConvert.DeserializeObject(_api.GetCertificate(enrollmentResponse.certificateId)); Enum.TryParse(certResponse.status, out certStatus); if (certStatus == CertificateStatusEnum.ISSUED) break; } catch (Exception) { } Thread.Sleep(_secondsBetweenEnrollmentRetries * 1000); } string pemCertificate = certStatus == CertificateStatusEnum.ISSUED ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId)).pems.certificate) : string.Empty; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); return new EnrollmentResult { CARequestID = enrollmentResponse.certificateId, Certificate = pemCertificate, Status = APIProcessor.MapReturnStatus(certStatus), StatusMessage = $"GoDaddy Status = {certStatus.ToString()}" }; } public override CAConnectorCertificate GetSingleRecord(string caRequestID) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); CertificateStatusEnum certStatus = CertificateStatusEnum.PENDING_ISSUANCE; GETCertificateDetailsResponse certResponse = JsonConvert.DeserializeObject(_api.GetCertificate(caRequestID)); Enum.TryParse(certResponse.status, out certStatus); string issuedCert = string.Empty; if (certStatus == CertificateStatusEnum.ISSUED || certStatus == CertificateStatusEnum.REVOKED || certStatus == CertificateStatusEnum.EXPIRED) { issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID)).pems.certificate); - } + private string[][] _connectionKeys = new string[][] { new string[] { "ApiUrl", "string" }, + new string[] { "ApiKey", "string" }, + new string[] { "ShopperId", "string" }, + new string[] { "RootType", "string" }, + new string[] { "SyncPageSize", "int" }, + new string[] { "EnrollmentRetries", "int" }, + new string[] { "SecondsBetweenEnrollmentRetries", "int" } }; - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); return new CAConnectorCertificate() { CARequestID = caRequestID, Certificate = issuedCert, CSR = certResponse.csr, ResolutionDate = certResponse.createdAt, RevocationDate = certResponse.revokedAt, RevocationReason = null, Status = APIProcessor.MapReturnStatus(certStatus), SubmissionDate = certResponse.createdAt }; } public override int Revoke(string caRequestID, string hexSerialNumber, uint revocationReason) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); try { _api.RevokeCertificate(caRequestID, APIProcessor.MapRevokeReason(revocationReason)); } catch (Exception ex) { return Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.FAILED); } Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); return Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED); } public override void ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } #endregion #region Private Methods private string RemovePEMHeader(string pem) { - return string.IsNullOrEmpty(pem) ? string.Empty : PemUtilities.DERToPEM(PemUtilities.PEMToDER(pem), PemUtilities.PemObjectType.NoHeaders); } private void ValidateParameters(Dictionary connectionData, string[][] keysToValidate) { List errors = new List(); foreach (string[] connectionKey in keysToValidate) { if (!connectionData.ContainsKey(connectionKey[0])) errors.Add($"CAConnection configuration value {connectionKey} not found."); else if (connectionKey[1] == "int") { int value; bool isIntValue = int.TryParse(connectionData[connectionKey[0]].ToString(), out value); if (!isIntValue) errors.Add($"CAConnection configuration value {connectionKey} must contain an integer. Found {connectionData[connectionKey[0]]}"); } } if (errors.Count > 0) throw new GoDaddyException(string.Join(System.Environment.NewLine, errors.ToArray())); } private POSTCertificateEnrollmentResponse EnrollDV (EnrollmentProductInfo productInfo, string csr, Dictionary san) { POSTCertificatesV1DVRequest certRequest = new POSTCertificatesV1DVRequest(); certRequest.contact = new ContactInfo(); certRequest.contact.email = productInfo.ProductParameters["Email"]; certRequest.contact.nameFirst = productInfo.ProductParameters["FirstName"]; certRequest.contact.nameLast = productInfo.ProductParameters["LastName"]; certRequest.contact.phone = productInfo.ProductParameters["Phone"]; certRequest.SetCSR(csr); certRequest.period = Convert.ToInt32(productInfo.ProductParameters["CertificatePeriodInYears"]); certRequest.productType = productInfo.ProductID; certRequest.rootType = _rootType; certRequest.slotSize = productInfo.ProductParameters.Keys.Contains("SlotSize") ? productInfo.ProductParameters["SlotSize"] : "FIVE"; List sans = new List(); foreach (string[] sanValues in san.Values) { foreach (string sanValue in sanValues) sans.Add(sanValue); } certRequest.subjectAlternativeNames = sans.ToArray(); string response = _api.EnrollCSR(csr, certRequest); return JsonConvert.DeserializeObject(response); } private POSTCertificateEnrollmentResponse EnrollOV(EnrollmentProductInfo productInfo, string csr, Dictionary san) { POSTCertificatesV1OVRequest certRequest = new POSTCertificatesV1OVRequest(); certRequest.contact = new ContactInfo(); certRequest.contact.jobTitle = productInfo.ProductParameters["JobTitle"]; certRequest.contact.email = productInfo.ProductParameters["Email"]; certRequest.contact.nameFirst = productInfo.ProductParameters["FirstName"]; certRequest.contact.nameLast = productInfo.ProductParameters["LastName"]; certRequest.contact.phone = productInfo.ProductParameters["Phone"]; certRequest.organization = new OrganizationInfo(); certRequest.organization.address = new AddressInfo(); certRequest.organization.address.address1 = productInfo.ProductParameters["OrganizationAddress"]; certRequest.organization.address.city = productInfo.ProductParameters["OrganizationCity"]; certRequest.organization.address.state = productInfo.ProductParameters["OrganizationState"]; certRequest.organization.address.country = productInfo.ProductParameters["OrganizationCountry"]; certRequest.organization.name = productInfo.ProductParameters["OrganizationName"]; certRequest.organization.phone = productInfo.ProductParameters["OrganizationPhone"]; certRequest.SetCSR(csr); certRequest.period = Convert.ToInt32(productInfo.ProductParameters["CertificatePeriodInYears"]); certRequest.productType = productInfo.ProductID; certRequest.rootType = _rootType; certRequest.slotSize = productInfo.ProductParameters.Keys.Contains("SlotSize") ? productInfo.ProductParameters["SlotSize"] : "FIVE"; List sans = new List(); foreach (string[] sanValues in san.Values) { foreach (string sanValue in sanValues) sans.Add(sanValue); } certRequest.subjectAlternativeNames = sans.ToArray(); string response = _api.EnrollCSR(csr, certRequest); return JsonConvert.DeserializeObject(response); } private POSTCertificateEnrollmentResponse EnrollEV(EnrollmentProductInfo productInfo, string csr, Dictionary san) { POSTCertificatesV1EVRequest certRequest = new POSTCertificatesV1EVRequest(); certRequest.contact = new ContactInfo(); certRequest.contact.jobTitle = productInfo.ProductParameters["JobTitle"]; certRequest.contact.email = productInfo.ProductParameters["Email"]; certRequest.contact.nameFirst = productInfo.ProductParameters["FirstName"]; certRequest.contact.nameLast = productInfo.ProductParameters["LastName"]; certRequest.contact.phone = productInfo.ProductParameters["Phone"]; certRequest.organization = new OrganizationInfo(); certRequest.organization.address = new AddressInfo(); certRequest.organization.address.address1 = productInfo.ProductParameters["OrganizationAddress"]; certRequest.organization.address.city = productInfo.ProductParameters["OrganizationCity"]; certRequest.organization.address.state = productInfo.ProductParameters["OrganizationState"]; certRequest.organization.address.country = productInfo.ProductParameters["OrganizationCountry"]; certRequest.organization.name = productInfo.ProductParameters["OrganizationName"]; certRequest.organization.phone = productInfo.ProductParameters["OrganizationPhone"]; certRequest.organization.jurisdictionOfIncorporation = new JurisdictionInfo(); certRequest.organization.jurisdictionOfIncorporation.state = productInfo.ProductParameters["JurisdictionState"]; certRequest.organization.jurisdictionOfIncorporation.country = productInfo.ProductParameters["JurisdictionCountry"]; certRequest.organization.registrationNumber = productInfo.ProductParameters["RegistrationNumber"]; certRequest.SetCSR(csr); certRequest.period = Convert.ToInt32(productInfo.ProductParameters["CertificatePeriodInYears"]); certRequest.productType = productInfo.ProductID; certRequest.rootType = _rootType; certRequest.slotSize = productInfo.ProductParameters.Keys.Contains("SlotSize") ? productInfo.ProductParameters["SlotSize"] : "FIVE"; List sans = new List(); foreach (string[] sanValues in san.Values) { foreach (string sanValue in sanValues) sans.Add(sanValue); } certRequest.subjectAlternativeNames = sans.ToArray(); string response = _api.EnrollCSR(csr, certRequest); return JsonConvert.DeserializeObject(response); } private POSTCertificateEnrollmentResponse RenewReissue(string certificateId, EnrollmentProductInfo productInfo, string csr, Dictionary san, bool isRenew) { POSTCertificateRenewalRequest certRequest = new POSTCertificateRenewalRequest(); certRequest.SetCSR(csr); certRequest.rootType = _rootType; List sans = new List(); foreach (string[] sanValues in san.Values) { foreach (string sanValue in sanValues) sans.Add(sanValue); } certRequest.subjectAlternativeNames = sans.ToArray(); string response = _api.RenewReissueCSR(certificateId, csr, certRequest, isRenew); return JsonConvert.DeserializeObject(response); } #endregion } } \ No newline at end of file + + + #region Interface Methods + public override void Initialize(ICAConnectorConfigProvider configProvider) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + foreach (KeyValuePair configEntry in configProvider.CAConnectionData) + Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); + ValidateParameters(configProvider.CAConnectionData, _connectionKeys); + + string apiUrl = configProvider.CAConnectionData["ApiUrl"].ToString(); + string apiKey = configProvider.CAConnectionData["ApiKey"].ToString(); + string shopperId = configProvider.CAConnectionData["ShopperId"].ToString(); + _rootType = configProvider.CAConnectionData["RootType"].ToString(); + _syncPageSize = Convert.ToInt32(configProvider.CAConnectionData["SyncPageSize"]); + _enrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["EnrollmentRetries"]); + _secondsBetweenEnrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"]); + + _api = new APIProcessor(apiUrl, apiKey, shopperId); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } + + public override void Ping() + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } + + public override void ValidateCAConnectionInfo(Dictionary connectionInfo) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + ValidateParameters(connectionInfo, _connectionKeys); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } + + [Obsolete] + public override void Synchronize(ICertificateDataReader certificateDataReader, BlockingCollection blockingBuffer, CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, CancellationToken cancelToken, string logicalName) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + throw new NotImplementedException(); + } + + public override void Synchronize(ICertificateDataReader certificateDataReader, BlockingCollection blockingBuffer, CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, CancellationToken cancelToken) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + string customerId = JsonConvert.DeserializeObject(_api.GetCustomerId()).customerId; + + int pageNumber = 1; + bool wasLastPage = false; + + do + { + GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); + + foreach (CertificateDetails certificate in certificates.certificates) + { + Thread.Sleep(1000); + try + { + string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId)).pems.certificate); + CertificateStatusEnum certStatus = CertificateStatusEnum.ISSUED; + if (!Enum.TryParse(certificate.status, out certStatus)) + certStatus = CertificateStatusEnum.CANCELED; + + blockingBuffer.Add(new CAConnectorCertificate + { + CARequestID = certificate.certificateId, + Certificate = issuedCert, + CSR = string.Empty, + ResolutionDate = certificate.completedAt, + RevocationDate = certificate.revokedAt, + RevocationReason = null, + Status = APIProcessor.MapReturnStatus(certStatus), + SubmissionDate = certificate.createdAt, + ProductID = certificate.type + }); + } + catch (GoDaddyException) { } + } + + wasLastPage = certificates.pagination.previous == certificates.pagination.last; + pageNumber++; + } while (!wasLastPage); + + blockingBuffer.CompleteAdding(); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } + + [Obsolete] + public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, CSS.PKI.PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + throw new NotImplementedException(); + } + + public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader, string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, CSS.PKI.PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + foreach (KeyValuePair configEntry in productInfo.ProductParameters) + { + Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); + } + + string[][] parameterKeys; + if (enrollmentType == RequestUtilities.EnrollmentType.New) + parameterKeys = new string[][] { new string[] { "Email", "string" }, + new string[] { "FirstName", "string" }, + new string[] { "LastName", "string" }, + new string[] { "Phone", "string" }, + new string[] { "CertificatePeriodInYears", "int" } }; + else + parameterKeys = new string[][] { new string[] { "PriorCertSN", "string" } }; + + ValidateParameters(productInfo.ProductParameters, parameterKeys); + + POSTCertificateEnrollmentResponse enrollmentResponse; + + try + { + switch (enrollmentType) + { + case RequestUtilities.EnrollmentType.New: + switch (productInfo.ProductID) + { + case "DV_SSL": + case "DV_WILDCARD_SSL": + case "UCC_DV_SSL": + enrollmentResponse = EnrollDV(productInfo, csr, san); + break; + + case "OV_SSL": + case "OV_CS": + case "OV_DS": + case "OV_WILDCARD_SSL": + case "UCC_OV_SSL": + enrollmentResponse = EnrollOV(productInfo, csr, san); + break; + + case "EV_SSL": + case "UCC_EV_SSL": + enrollmentResponse = EnrollEV(productInfo, csr, san); + break; + + default: + return new EnrollmentResult { Status = 30, StatusMessage = $"Error attempting to enroll certificate {subject}: Invalid Product ID - {productInfo.ProductID}." }; + } + + break; + + case RequestUtilities.EnrollmentType.Renew: + case RequestUtilities.EnrollmentType.Reissue: + CAConnectorCertificate certificate = certificateDataReader.GetCertificateRecord(DataConversion.HexToBytes(productInfo.ProductParameters["PriorCertSN"])); + enrollmentResponse = RenewReissue(certificate.CARequestID, productInfo, csr, san, enrollmentType == RequestUtilities.EnrollmentType.Renew); + break; + + default: + return new EnrollmentResult { Status = 30, StatusMessage = $"Unsupported EnrollmentType: {enrollmentType}" }; + } + } + catch (Exception ex) + { + return new EnrollmentResult { Status = 30, StatusMessage = $"Error attempting to enroll certificate {subject}: {ex.Message}." }; + } Logger.Trace($"Enrollment issued for certificate ID {enrollmentResponse.certificateId}"); + + CertificateStatusEnum certStatus = CertificateStatusEnum.PENDING_ISSUANCE; + for (int i = 0; i < _enrollmentRetries; i++) + { + try + { + GETCertificateDetailsResponse certResponse = JsonConvert.DeserializeObject(_api.GetCertificate(enrollmentResponse.certificateId)); + Enum.TryParse(certResponse.status, out certStatus); + if (certStatus == CertificateStatusEnum.ISSUED) + break; + } + catch (Exception exc) { string errMsg = $"Error retrieving certificate defails for ID {enrollmentResponse.certificateId}:\n{LogHandler.FlattenException(exc)}"; if (i + 1 < _enrollmentRetries) + { + errMsg += $"\nRetrying... (Attempt {i + 1} of {_enrollmentRetries})"; + } else + { + errMsg += $"Retrieving certificate failed."; + } Logger.Error(errMsg); } + + Thread.Sleep(_secondsBetweenEnrollmentRetries * 1000); + } + + string pemCertificate = certStatus == CertificateStatusEnum.ISSUED ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId)).pems.certificate) : string.Empty; + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + return new EnrollmentResult + { + CARequestID = enrollmentResponse.certificateId, + Certificate = pemCertificate, + Status = APIProcessor.MapReturnStatus(certStatus), + StatusMessage = $"GoDaddy Status = {certStatus.ToString()}" + }; + } + + public override CAConnectorCertificate GetSingleRecord(string caRequestID) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Logger.Trace($"Getting record for CARequestID: {caRequestID}"); + CertificateStatusEnum certStatus = CertificateStatusEnum.PENDING_ISSUANCE; + + GETCertificateDetailsResponse certResponse = JsonConvert.DeserializeObject(_api.GetCertificate(caRequestID)); + Enum.TryParse(certResponse.status, out certStatus); + + string issuedCert = string.Empty; + if (certStatus == CertificateStatusEnum.ISSUED || certStatus == CertificateStatusEnum.REVOKED || certStatus == CertificateStatusEnum.EXPIRED) + { + issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID)).pems.certificate); + } + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + return new CAConnectorCertificate() + { + CARequestID = caRequestID, + Certificate = issuedCert, + CSR = certResponse.csr, + ResolutionDate = certResponse.createdAt, + RevocationDate = certResponse.revokedAt, + RevocationReason = null, + Status = APIProcessor.MapReturnStatus(certStatus), + SubmissionDate = certResponse.createdAt + }; + } + + public override int Revoke(string caRequestID, string hexSerialNumber, uint revocationReason) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + try + { + _api.RevokeCertificate(caRequestID, APIProcessor.MapRevokeReason(revocationReason)); + } + catch (Exception ex) + { + return Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.FAILED); + } + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + return Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED); + } + + public override void ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + } + + + + + + + + #endregion Interface Methods + + #region Private Methods + private string RemovePEMHeader(string pem) + { + return string.IsNullOrEmpty(pem) ? string.Empty : PemUtilities.DERToPEM(PemUtilities.PEMToDER(pem), PemUtilities.PemObjectType.NoHeaders); + } + + private void ValidateParameters(Dictionary connectionData, string[][] keysToValidate) + { + List errors = new List(); + + foreach (string[] connectionKey in keysToValidate) + { + if (!connectionData.ContainsKey(connectionKey[0])) + errors.Add($"CAConnection configuration value {connectionKey} not found."); + else if (connectionKey[1] == "int") + { + int value; + bool isIntValue = int.TryParse(connectionData[connectionKey[0]].ToString(), out value); + if (!isIntValue) + errors.Add($"CAConnection configuration value {connectionKey} must contain an integer. Found {connectionData[connectionKey[0]]}"); + } + } + + if (errors.Count > 0) + throw new GoDaddyException(string.Join(System.Environment.NewLine, errors.ToArray())); + } + + private POSTCertificateEnrollmentResponse EnrollDV(EnrollmentProductInfo productInfo, string csr, Dictionary san) + { + POSTCertificatesV1DVRequest certRequest = new POSTCertificatesV1DVRequest(); + + certRequest.contact = new ContactInfo(); + certRequest.contact.email = productInfo.ProductParameters["Email"]; + certRequest.contact.nameFirst = productInfo.ProductParameters["FirstName"]; + certRequest.contact.nameLast = productInfo.ProductParameters["LastName"]; + certRequest.contact.phone = productInfo.ProductParameters["Phone"]; + certRequest.SetCSR(csr); + + certRequest.period = Convert.ToInt32(productInfo.ProductParameters["CertificatePeriodInYears"]); + certRequest.productType = productInfo.ProductID; + certRequest.rootType = _rootType; + certRequest.slotSize = productInfo.ProductParameters.Keys.Contains("SlotSize") ? productInfo.ProductParameters["SlotSize"] : "FIVE"; + + List sans = new List(); + foreach (string[] sanValues in san.Values) + { + foreach (string sanValue in sanValues) + { + sans.Add(sanValue); + } + } + certRequest.subjectAlternativeNames = sans.ToArray(); + + string response = _api.EnrollCSR(csr, certRequest); + + return JsonConvert.DeserializeObject(response); + } + + private POSTCertificateEnrollmentResponse EnrollOV(EnrollmentProductInfo productInfo, string csr, Dictionary san) + { + POSTCertificatesV1OVRequest certRequest = new POSTCertificatesV1OVRequest(); + + certRequest.contact = new ContactInfo(); + certRequest.contact.jobTitle = productInfo.ProductParameters["JobTitle"]; + certRequest.contact.email = productInfo.ProductParameters["Email"]; + certRequest.contact.nameFirst = productInfo.ProductParameters["FirstName"]; + certRequest.contact.nameLast = productInfo.ProductParameters["LastName"]; + certRequest.contact.phone = productInfo.ProductParameters["Phone"]; + + certRequest.organization = new OrganizationInfo(); + certRequest.organization.address = new AddressInfo(); + certRequest.organization.address.address1 = productInfo.ProductParameters["OrganizationAddress"]; + certRequest.organization.address.city = productInfo.ProductParameters["OrganizationCity"]; + certRequest.organization.address.state = productInfo.ProductParameters["OrganizationState"]; + certRequest.organization.address.country = productInfo.ProductParameters["OrganizationCountry"]; + certRequest.organization.name = productInfo.ProductParameters["OrganizationName"]; + certRequest.organization.phone = productInfo.ProductParameters["OrganizationPhone"]; + + certRequest.SetCSR(csr); + + certRequest.period = Convert.ToInt32(productInfo.ProductParameters["CertificatePeriodInYears"]); + certRequest.productType = productInfo.ProductID; + certRequest.rootType = _rootType; + certRequest.slotSize = productInfo.ProductParameters.Keys.Contains("SlotSize") ? productInfo.ProductParameters["SlotSize"] : "FIVE"; + + List sans = new List(); + foreach (string[] sanValues in san.Values) + { + foreach (string sanValue in sanValues) + sans.Add(sanValue); + } + certRequest.subjectAlternativeNames = sans.ToArray(); + + string response = _api.EnrollCSR(csr, certRequest); + return JsonConvert.DeserializeObject(response); + } + + private POSTCertificateEnrollmentResponse EnrollEV(EnrollmentProductInfo productInfo, string csr, Dictionary san) + { + POSTCertificatesV1EVRequest certRequest = new POSTCertificatesV1EVRequest(); + + certRequest.contact = new ContactInfo(); + certRequest.contact.jobTitle = productInfo.ProductParameters["JobTitle"]; + certRequest.contact.email = productInfo.ProductParameters["Email"]; + certRequest.contact.nameFirst = productInfo.ProductParameters["FirstName"]; + certRequest.contact.nameLast = productInfo.ProductParameters["LastName"]; + certRequest.contact.phone = productInfo.ProductParameters["Phone"]; + + certRequest.organization = new OrganizationInfo(); + certRequest.organization.address = new AddressInfo(); + certRequest.organization.address.address1 = productInfo.ProductParameters["OrganizationAddress"]; + certRequest.organization.address.city = productInfo.ProductParameters["OrganizationCity"]; + certRequest.organization.address.state = productInfo.ProductParameters["OrganizationState"]; + certRequest.organization.address.country = productInfo.ProductParameters["OrganizationCountry"]; + certRequest.organization.name = productInfo.ProductParameters["OrganizationName"]; + certRequest.organization.phone = productInfo.ProductParameters["OrganizationPhone"]; + + certRequest.organization.jurisdictionOfIncorporation = new JurisdictionInfo(); + certRequest.organization.jurisdictionOfIncorporation.state = productInfo.ProductParameters["JurisdictionState"]; + certRequest.organization.jurisdictionOfIncorporation.country = productInfo.ProductParameters["JurisdictionCountry"]; + certRequest.organization.registrationNumber = productInfo.ProductParameters["RegistrationNumber"]; + + certRequest.SetCSR(csr); + + certRequest.period = Convert.ToInt32(productInfo.ProductParameters["CertificatePeriodInYears"]); + certRequest.productType = productInfo.ProductID; + certRequest.rootType = _rootType; + certRequest.slotSize = productInfo.ProductParameters.Keys.Contains("SlotSize") ? productInfo.ProductParameters["SlotSize"] : "FIVE"; + + List sans = new List(); + foreach (string[] sanValues in san.Values) + { + foreach (string sanValue in sanValues) + sans.Add(sanValue); + } + certRequest.subjectAlternativeNames = sans.ToArray(); + + string response = _api.EnrollCSR(csr, certRequest); + return JsonConvert.DeserializeObject(response); + } + + private POSTCertificateEnrollmentResponse RenewReissue(string certificateId, EnrollmentProductInfo productInfo, string csr, Dictionary san, bool isRenew) + { + POSTCertificateRenewalRequest certRequest = new POSTCertificateRenewalRequest(); + + certRequest.SetCSR(csr); + certRequest.rootType = _rootType; + + List sans = new List(); + foreach (string[] sanValues in san.Values) + { + foreach (string sanValue in sanValues) + sans.Add(sanValue); + } + certRequest.subjectAlternativeNames = sans.ToArray(); + + string response = _api.RenewReissueCSR(certificateId, csr, certRequest, isRenew); + return JsonConvert.DeserializeObject(response); + } + + + + + + #endregion Private Methods } } \ No newline at end of file From 4ea69c36b2ec00805ebc864de334ba6580ab0831 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Mon, 17 Apr 2023 14:42:03 +0000 Subject: [PATCH 06/39] changes --- GoDaddy/GoDaddyCAProxy.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 9cea146..53069dd 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -38,7 +38,10 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); foreach (KeyValuePair configEntry in configProvider.CAConnectionData) - Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); + { + if (configEntry.Key != "ApiKey") + Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); + } ValidateParameters(configProvider.CAConnectionData, _connectionKeys); string apiUrl = configProvider.CAConnectionData["ApiUrl"].ToString(); From c5673e143ac0fd9caeff5a032155ea23be40320b Mon Sep 17 00:00:00 2001 From: kfadmin Date: Mon, 17 Apr 2023 14:45:21 +0000 Subject: [PATCH 07/39] changes --- CHANGELOG.md | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95f7897..c4322c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,30 @@ -v1.0.0: -- Original Version +v1.0.8 +- Improved logging + +v1.0.7 +- Improved logging + +v1.0.6 +- Code cleanup + +v1.0.4/1.0.5 +- Update nuget packages + +v1.0.3 +- Code cleanup, publish to github. + +v1.0.2 +- Remove PEM header before returning certificates during sync and enrollment v1.0.1 - Added support for 5 OV and 2 EV GoDaddy products - Added Renew/Reissue functionality -v1.0.2 -- Remove PEM header before returning certificates during sync and enrollment +v1.0.0: +- Original Version -v1.0.3 -- Code cleanup, publish to github. -v1.0.4/1.0.5 -- Update nuget packages + + -v1.0.6 -- Code cleanup -v1.0.7 -- Improved logging \ No newline at end of file From fc4541d072ab8d6630ecd5282c452a327d74da06 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Thu, 20 Apr 2023 17:18:26 +0000 Subject: [PATCH 08/39] changes --- GoDaddy/API/APIProcessor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 0f91af3..9d7e225 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -230,6 +230,10 @@ private string SubmitRequest(RestRequest request) try { response = client.Execute(request); + if (response.ResponseStatus == ResponseStatus.TimedOut) + { + throw new GoDaddyException("Request timed out "); + } } catch (Exception ex) { From 558a2ddf21347250ad485900ee3d720ba4eeefd2 Mon Sep 17 00:00:00 2001 From: Lee Fine <50836957+leefine02@users.noreply.github.com> Date: Fri, 21 Apr 2023 11:51:45 -0400 Subject: [PATCH 09/39] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4322c3..ad2a091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ v1.0.8 - Improved logging +- Improved error handling for API timeouts v1.0.7 - Improved logging From a41fadbf068057cf439af10ecd1f2ad6ebab42a3 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Fri, 21 Apr 2023 16:16:26 +0000 Subject: [PATCH 10/39] changes --- GoDaddy/API/APIProcessor.cs | 11 +++++++++-- GoDaddy/GoDaddyCAProxy.cs | 2 -- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 9d7e225..422abd2 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -32,7 +32,10 @@ internal class APIProcessor : LoggingClientBase private const string NO_CERTS_PURCHASED_REPL_MESSAGE = "Failed to create certificate order. This error often occurs if there are no certificates purchased to fulfill this enrollment request. " + "Please check your GoDaddy account to make sure you have the correct SSL certificate product purchased to cover this enrollment."; - public APIProcessor(string apiUrl, string apiKey, string shopperId) + private int NumberOfTimeOuts = 0; + + + public APIProcessor(string apiUrl, string apiKey, string shopperId) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -232,6 +235,7 @@ private string SubmitRequest(RestRequest request) response = client.Execute(request); if (response.ResponseStatus == ResponseStatus.TimedOut) { + NumberOfTimeOuts++; throw new GoDaddyException("Request timed out "); } } @@ -239,7 +243,10 @@ private string SubmitRequest(RestRequest request) { string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}").Replace(NO_CERTS_PURCHASED_MESSAGE, NO_CERTS_PURCHASED_REPL_MESSAGE); Logger.Error(exceptionMessage); - throw new GoDaddyException(exceptionMessage); + if (NumberOfTimeOuts > 5) + throw new Exception("Maximum timeouts of 5 exceeded. " + exceptionMessage); + else + throw new GoDaddyException(exceptionMessage); } Logger.Trace($"Response Status Code: {response.StatusCode}"); diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 53069dd..d9ce4a3 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -30,8 +30,6 @@ public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector new string[] { "SecondsBetweenEnrollmentRetries", "int" } }; - - #region Interface Methods public override void Initialize(ICAConnectorConfigProvider configProvider) { From 4ad28ea97ae02fac6ac5c0df42c8f2be10f634d7 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Tue, 2 May 2023 13:27:12 +0000 Subject: [PATCH 11/39] changes --- GoDaddy/GoDaddyCAProxy.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index d9ce4a3..79f8dbf 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -93,6 +93,8 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B do { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); + if (certificateAuthoritySyncInfo.OverallLastSync.HasValue) + certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); foreach (CertificateDetails certificate in certificates.certificates) { From 17d2e365069126188c27bcd656d1228e15a8a7e0 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Tue, 2 May 2023 16:45:20 +0000 Subject: [PATCH 12/39] changes --- GoDaddy/GoDaddyCAProxy.cs | 47 +++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 79f8dbf..d6486b3 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -15,13 +15,17 @@ using CAProxy.AnyGateway.Interfaces; using CAProxy.AnyGateway.Models; using CAProxy.Common; using CSS.Common; using CSS.Common.Logging; using Keyfactor.PKI; using Keyfactor.PKI.PEM; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using Keyfactor.AnyGateway.GoDaddy.API; using Keyfactor.AnyGateway.GoDaddy.Models; namespace Keyfactor.AnyGateway.GoDaddy { public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector { - private APIProcessor _api { get; set; } - private string _rootType { get; set; } - private int _syncPageSize { get; set; } - private int _enrollmentRetries { get; set; } - private int _secondsBetweenEnrollmentRetries { get; set; } - - private string[][] _connectionKeys = new string[][] { new string[] { "ApiUrl", "string" }, + private APIProcessor _api; + private string _rootType; + private int _syncPageSize; + private int _enrollmentRetries; + private int _secondsBetweenEnrollmentRetries; + private int _apiTimeoutinMilliseconds = 10000; + private int _numberOfCertDownloadAPIRetriesBeforeSkip = 2; + private int _numberOfAPITimeoutsBeforeSyncFailure = 2000; + private int _millisecondsBetweenCertDownloadAPICalls = 1000; + + private string[][] _connectionKeys = new string[][] { new string[] { "ApiUrl", "string" }, new string[] { "ApiKey", "string" }, new string[] { "ShopperId", "string" }, new string[] { "RootType", "string" }, @@ -50,7 +54,32 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) _enrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["EnrollmentRetries"]); _secondsBetweenEnrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"]); - _api = new APIProcessor(apiUrl, apiKey, shopperId); + //optional parameters + bool isInt; + int tempInt; + + if (configProvider.CAConnectionData.ContainsKey("ApiTimeoutinMilliseconds")) + { + isInt = int.TryParse(configProvider.CAConnectionData["ApiTimeoutinMilliseconds"].ToString(), out tempInt); + _apiTimeoutinMilliseconds = !isInt || tempInt < 2000 || tempInt > 100000 ? _apiTimeoutinMilliseconds : tempInt; + } + + isInt = int.TryParse(configProvider.CAConnectionData["NumberOfCertDownloadAPIRetriesBeforeSkip"].ToString(), out tempInt); + _numberOfCertDownloadAPIRetriesBeforeSkip = !isInt || tempInt < 2000 || tempInt > 100000 ? _numberOfCertDownloadAPIRetriesBeforeSkip : tempInt; + + isInt = int.TryParse(configProvider.CAConnectionData["MillisecondsBetweenCertDownloadAPICalls"].ToString(), out tempInt); + _millisecondsBetweenCertDownloadAPICalls = !isInt || tempInt < 2000 || tempInt > 100000 ? _millisecondsBetweenCertDownloadAPICalls : tempInt; + + isInt = int.TryParse(configProvider.CAConnectionData["NumberOfAPITimeoutsBeforeSyncFailure"].ToString(), out tempInt); + _numberOfAPITimeoutsBeforeSyncFailure = !isInt || tempInt < 2000 || tempInt > 100000 ? _numberOfAPITimeoutsBeforeSyncFailurec : tempInt; + + + private int { get; set; } + private int { get; set; } + private int { get; set; } + + + _api = new APIProcessor(apiUrl, apiKey, shopperId); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } @@ -93,7 +122,7 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B do { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); - if (certificateAuthoritySyncInfo.OverallLastSync.HasValue) + if (!certificateAuthoritySyncInfo.DoFullSync && certificateAuthoritySyncInfo.OverallLastSync.HasValue) certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); foreach (CertificateDetails certificate in certificates.certificates) From 782c6eebe8fe07ec8d3454b8adb3ef802b8cb0bc Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Tue, 2 May 2023 19:44:50 +0000 Subject: [PATCH 13/39] changes --- GoDaddy/GoDaddyCAProxy.cs | 100 +++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index d6486b3..a1b6de8 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -17,21 +17,41 @@ public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector { private APIProcessor _api; private string _rootType; - private int _syncPageSize; - private int _enrollmentRetries; - private int _secondsBetweenEnrollmentRetries; - private int _apiTimeoutinMilliseconds = 10000; - private int _numberOfCertDownloadAPIRetriesBeforeSkip = 2; - private int _numberOfAPITimeoutsBeforeSyncFailure = 2000; - private int _millisecondsBetweenCertDownloadAPICalls = 1000; + + private int _syncPageSize = 50; + private const int SYNC_PAGE_SIZE_MIN = 10; + private const int SYNC_PAGE_SIZE_MAX = 1000; + + private int _enrollmentRetries = 2; + private const int ENROLLMENT_RETRIES_MIN = 0; + private const int ENROLLMENT_RETRIES_MAX = 5; + + private int _secondsBetweenEnrollmentRetries = 5; + private const int SECONDS_BETWEEN_ENROLLMENT_RETRIES_MIN = 2; + private const int SECONDS_BETWEEN_ENROLLMENT_RETRIES_MAX = 20; + + private int _apiTimeoutInSeconds = 20; + private const int API_TIMEOUT_IN_SECONDS_MIN = 10; + private const int API_TIMEOUT_IN_SECONDS_MAX = 100; + + private int _numberOfCertDownloadRetriesBeforeSkip = 2; + private const int NUMBER_OF_CERT_DOWNLOAD_RETRIES_BEFORE_SKIP_MIN = 0; + private const int NUMBER_OF_CERT_DOWNLOAD_RETRIES_BEFORE_SKIP_MAX = 10; + + private int _numberOfTimeoutsBeforeSyncFailure = 100; + private const int NUMBER_OF_TIMEOUTS_BEFORE_SYNC_FAILURE_MIN = 0; + private const int NUMBER_OF_TIMEOUTS_BEFORE_SYNC_FAILURE_MAX = 5000; + + private int _millisecondsBetweenCertDownloads = 1000; + private const int MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MIN = 0; + private const int MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MAX = 1000; + private string[][] _connectionKeys = new string[][] { new string[] { "ApiUrl", "string" }, new string[] { "ApiKey", "string" }, new string[] { "ShopperId", "string" }, new string[] { "RootType", "string" }, - new string[] { "SyncPageSize", "int" }, - new string[] { "EnrollmentRetries", "int" }, - new string[] { "SecondsBetweenEnrollmentRetries", "int" } }; + new string[] { "SyncPageSize", "int" } }; #region Interface Methods @@ -50,6 +70,7 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) string apiKey = configProvider.CAConnectionData["ApiKey"].ToString(); string shopperId = configProvider.CAConnectionData["ShopperId"].ToString(); _rootType = configProvider.CAConnectionData["RootType"].ToString(); + _syncPageSize = Convert.ToInt32(configProvider.CAConnectionData["SyncPageSize"]); _enrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["EnrollmentRetries"]); _secondsBetweenEnrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"]); @@ -58,28 +79,49 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) bool isInt; int tempInt; - if (configProvider.CAConnectionData.ContainsKey("ApiTimeoutinMilliseconds")) + if (configProvider.CAConnectionData.ContainsKey("SyncPageSize")) + { + isInt = int.TryParse(configProvider.CAConnectionData["SyncPageSize"].ToString(), out tempInt); + _syncPageSize = !isInt || tempInt < SYNC_PAGE_SIZE_MIN || tempInt > SYNC_PAGE_SIZE_MAX ? _syncPageSize : tempInt; + } + + if (configProvider.CAConnectionData.ContainsKey("EnrollmentRetries")) + { + isInt = int.TryParse(configProvider.CAConnectionData["EnrollmentRetries"].ToString(), out tempInt); + _enrollmentRetries = !isInt || tempInt < ENROLLMENT_RETRIES_MIN || tempInt > ENROLLMENT_RETRIES_MAX ? _enrollmentRetries : tempInt; + } + + if (configProvider.CAConnectionData.ContainsKey("SecondsBetweenEnrollmentRetries")) + { + isInt = int.TryParse(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"].ToString(), out tempInt); + _secondsBetweenEnrollmentRetries = !isInt || tempInt < ENROLLMENT_RETRIES_MIN || tempInt > ENROLLMENT_RETRIES_MAX ? _secondsBetweenEnrollmentRetries : tempInt; + } + + if (configProvider.CAConnectionData.ContainsKey("ApiTimeoutinSeconds")) { - isInt = int.TryParse(configProvider.CAConnectionData["ApiTimeoutinMilliseconds"].ToString(), out tempInt); - _apiTimeoutinMilliseconds = !isInt || tempInt < 2000 || tempInt > 100000 ? _apiTimeoutinMilliseconds : tempInt; + isInt = int.TryParse(configProvider.CAConnectionData["ApiTimeoutinSeconds"].ToString(), out tempInt); + _apiTimeoutInSeconds = !isInt || tempInt < API_TIMEOUT_IN_SECONDS_MIN || tempInt > API_TIMEOUT_IN_SECONDS_MAX ? _apiTimeoutInSeconds : tempInt; } - isInt = int.TryParse(configProvider.CAConnectionData["NumberOfCertDownloadAPIRetriesBeforeSkip"].ToString(), out tempInt); - _numberOfCertDownloadAPIRetriesBeforeSkip = !isInt || tempInt < 2000 || tempInt > 100000 ? _numberOfCertDownloadAPIRetriesBeforeSkip : tempInt; - - isInt = int.TryParse(configProvider.CAConnectionData["MillisecondsBetweenCertDownloadAPICalls"].ToString(), out tempInt); - _millisecondsBetweenCertDownloadAPICalls = !isInt || tempInt < 2000 || tempInt > 100000 ? _millisecondsBetweenCertDownloadAPICalls : tempInt; - - isInt = int.TryParse(configProvider.CAConnectionData["NumberOfAPITimeoutsBeforeSyncFailure"].ToString(), out tempInt); - _numberOfAPITimeoutsBeforeSyncFailure = !isInt || tempInt < 2000 || tempInt > 100000 ? _numberOfAPITimeoutsBeforeSyncFailurec : tempInt; - - - private int { get; set; } - private int { get; set; } - private int { get; set; } - - - _api = new APIProcessor(apiUrl, apiKey, shopperId); + if (configProvider.CAConnectionData.ContainsKey("NumberOfCertDownloadRetriesBeforeSkip")) + { + isInt = int.TryParse(configProvider.CAConnectionData["NumberOfCertDownloadRetriesBeforeSkip"].ToString(), out tempInt); + _numberOfCertDownloadRetriesBeforeSkip = !isInt || tempInt < NUMBER_OF_CERT_DOWNLOAD_RETRIES_BEFORE_SKIP_MIN || tempInt > NUMBER_OF_CERT_DOWNLOAD_RETRIES_BEFORE_SKIP_MAX ? _numberOfCertDownloadRetriesBeforeSkip : tempInt; + } + + if (configProvider.CAConnectionData.ContainsKey("NumberOfTimeoutsBeforeSyncFailure")) + { + isInt = int.TryParse(configProvider.CAConnectionData["NumberOfTimeoutsBeforeSyncFailure"].ToString(), out tempInt); + _numberOfTimeoutsBeforeSyncFailure = !isInt || tempInt < NUMBER_OF_TIMEOUTS_BEFORE_SYNC_FAILURE_MIN || tempInt > NUMBER_OF_TIMEOUTS_BEFORE_SYNC_FAILURE_MAX ? _numberOfTimeoutsBeforeSyncFailure : tempInt; + } + + if (configProvider.CAConnectionData.ContainsKey("MillisecondsBetweenCertDownloads")) + { + isInt = int.TryParse(configProvider.CAConnectionData["MillisecondsBetweenCertDownloads"].ToString(), out tempInt); + _millisecondsBetweenCertDownloads = !isInt || tempInt < MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MIN || tempInt > MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MAX ? _millisecondsBetweenCertDownloads : tempInt; + } + + _api = new APIProcessor(apiUrl, apiKey, shopperId); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } From 1ae576c6d88f2224960858f027ed7d84ef539c6f Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Wed, 3 May 2023 13:08:41 +0000 Subject: [PATCH 14/39] changes --- GoDaddy/API/APIProcessor.cs | 4 +++- GoDaddy/GoDaddyCAProxy.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 422abd2..f9d4cab 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -26,6 +26,7 @@ internal class APIProcessor : LoggingClientBase private string ApiUrl { get; set; } private string ApiKey { get; set; } private string ShopperId { get; set; } + private int Timeout { get; set; } private const string NO_CERTS_PURCHASED_MESSAGE = "Failed to create certificate order"; @@ -35,13 +36,14 @@ internal class APIProcessor : LoggingClientBase private int NumberOfTimeOuts = 0; - public APIProcessor(string apiUrl, string apiKey, string shopperId) + public APIProcessor(string apiUrl, string apiKey, string shopperId, int timeout) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); ApiUrl = apiUrl; ApiKey = apiKey; ShopperId = shopperId; + Timeout = timeout; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index a1b6de8..7b9e33d 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -121,7 +121,7 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) _millisecondsBetweenCertDownloads = !isInt || tempInt < MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MIN || tempInt > MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MAX ? _millisecondsBetweenCertDownloads : tempInt; } - _api = new APIProcessor(apiUrl, apiKey, shopperId); + _api = new APIProcessor(apiUrl, apiKey, shopperId, _apiTimeoutInSeconds * 1000); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } From f6f5cc439f8ad5d2a08035b957bcbe9faa92573b Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Wed, 3 May 2023 14:54:59 +0000 Subject: [PATCH 15/39] changes --- GoDaddy/API/APIProcessor.cs | 53 ++++++++++++++++++++------ GoDaddy/API/GoDaddyTimeoutException.cs | 31 +++++++++++++++ GoDaddy/GoDaddy.csproj | 1 + GoDaddy/GoDaddyCAProxy.cs | 14 ++++--- 4 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 GoDaddy/API/GoDaddyTimeoutException.cs diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index f9d4cab..b29c9ce 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -27,8 +27,9 @@ internal class APIProcessor : LoggingClientBase private string ApiKey { get; set; } private string ShopperId { get; set; } private int Timeout { get; set; } + private int MaxNumberOfTimeouts { get; set; } - private const string NO_CERTS_PURCHASED_MESSAGE = "Failed to create certificate order"; + private const string NO_CERTS_PURCHASED_MESSAGE = "Failed to create certificate order"; private const string NO_CERTS_PURCHASED_REPL_MESSAGE = "Failed to create certificate order. This error often occurs if there are no certificates purchased to fulfill this enrollment request. " + "Please check your GoDaddy account to make sure you have the correct SSL certificate product purchased to cover this enrollment."; @@ -36,7 +37,7 @@ internal class APIProcessor : LoggingClientBase private int NumberOfTimeOuts = 0; - public APIProcessor(string apiUrl, string apiKey, string shopperId, int timeout) + public APIProcessor(string apiUrl, string apiKey, string shopperId, int timeout, int maxNumberOfTimeouts) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -44,6 +45,7 @@ public APIProcessor(string apiUrl, string apiKey, string shopperId, int timeout) ApiKey = apiKey; ShopperId = shopperId; Timeout = timeout; + MaxNumberOfTimeouts = maxNumberOfTimeouts; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } @@ -113,18 +115,39 @@ public string GetCertificate(string certificateId) return SubmitRequest(request); } - public string DownloadCertificate(string certificateId) + public string DownloadCertificate(string certificateId, int maxRetries) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - string rtnMessage = string.Empty; + string cert = string.Empty; string RESOURCE = $"v1/certificates/{certificateId}/download"; RestRequest request = new RestRequest(RESOURCE, Method.GET); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return SubmitRequest(request); + int retries = 0; + while (true) + { + try + { + cert = SubmitRequest(request); + break; + } + catch (GoDaddyTimeoutException ex) + { + retries++; + if (retries > maxRetries) + { + Logger.Error($"Maximum number of timeout retries of {maxRetries} exceeded for certificate {certificateId} retrieval. Certificate skipped."); + throw ex; + } + else + continue; + } + } + + return cert; } public void RevokeCertificate(string certificateId, POSTCertificateRevokeRequest.REASON reason) @@ -230,6 +253,7 @@ private string SubmitRequest(RestRequest request) IRestResponse response; RestClient client = new RestClient(ApiUrl); + client.Timeout = Timeout; request.AddHeader("Authorization", ApiKey); try @@ -238,17 +262,24 @@ private string SubmitRequest(RestRequest request) if (response.ResponseStatus == ResponseStatus.TimedOut) { NumberOfTimeOuts++; - throw new GoDaddyException("Request timed out "); + throw new GoDaddyTimeoutException("Request timed out "); } } catch (Exception ex) { string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}").Replace(NO_CERTS_PURCHASED_MESSAGE, NO_CERTS_PURCHASED_REPL_MESSAGE); Logger.Error(exceptionMessage); - if (NumberOfTimeOuts > 5) - throw new Exception("Maximum timeouts of 5 exceeded. " + exceptionMessage); - else - throw new GoDaddyException(exceptionMessage); + if (NumberOfTimeOuts >= MaxNumberOfTimeouts) + { + string msg = $"Maximum timeouts of {MaxNumberOfTimeouts} exceeded. " + exceptionMessage; + Logger.Error(msg); + throw new Exception(msg); + } + else + { + Logger.Debug(exceptionMessage); + throw new GoDaddyTimeoutException(exceptionMessage); + } } Logger.Trace($"Response Status Code: {response.StatusCode}"); @@ -264,7 +295,7 @@ private string SubmitRequest(RestRequest request) APIError error = JsonConvert.DeserializeObject(response.Content); errorMessage = $"{error.code}: {error.message}"; } - catch (JsonReaderException ex) + catch (JsonReaderException) { errorMessage = response.Content; } diff --git a/GoDaddy/API/GoDaddyTimeoutException.cs b/GoDaddy/API/GoDaddyTimeoutException.cs new file mode 100644 index 0000000..826c9a8 --- /dev/null +++ b/GoDaddy/API/GoDaddyTimeoutException.cs @@ -0,0 +1,31 @@ +// Copyright 2021 Keyfactor +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Keyfactor.AnyGateway.GoDaddy.API +{ + class GoDaddyTimeoutException : GoDaddyException + { + public GoDaddyTimeoutException(string message) : base(message) + { } + + public GoDaddyTimeoutException(string message, Exception ex) : base(message, ex) + { } + } +} diff --git a/GoDaddy/GoDaddy.csproj b/GoDaddy/GoDaddy.csproj index 4b54af6..3c7d66b 100644 --- a/GoDaddy/GoDaddy.csproj +++ b/GoDaddy/GoDaddy.csproj @@ -145,6 +145,7 @@ + diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 7b9e33d..dc49e39 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -121,7 +121,7 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) _millisecondsBetweenCertDownloads = !isInt || tempInt < MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MIN || tempInt > MILLISECONDS_BETWEEN_CERT_DOWNLOADS_MAX ? _millisecondsBetweenCertDownloads : tempInt; } - _api = new APIProcessor(apiUrl, apiKey, shopperId, _apiTimeoutInSeconds * 1000); + _api = new APIProcessor(apiUrl, apiKey, shopperId, _apiTimeoutInSeconds * 1000, _numberOfTimeoutsBeforeSyncFailure); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } @@ -169,10 +169,10 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B foreach (CertificateDetails certificate in certificates.certificates) { - Thread.Sleep(1000); + Thread.Sleep(_millisecondsBetweenCertDownloads); try { - string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId)).pems.certificate); + string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate); CertificateStatusEnum certStatus = CertificateStatusEnum.ISSUED; if (!Enum.TryParse(certificate.status, out certStatus)) certStatus = CertificateStatusEnum.CANCELED; @@ -292,7 +292,7 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe if (certStatus == CertificateStatusEnum.ISSUED) break; } - catch (Exception exc) { string errMsg = $"Error retrieving certificate defails for ID {enrollmentResponse.certificateId}:\n{LogHandler.FlattenException(exc)}"; if (i + 1 < _enrollmentRetries) + catch (Exception exc) { string errMsg = $"Error retrieving certificate fails for ID {enrollmentResponse.certificateId}:\n{LogHandler.FlattenException(exc)}"; if (i + 1 < _enrollmentRetries) { errMsg += $"\nRetrying... (Attempt {i + 1} of {_enrollmentRetries})"; } else @@ -303,7 +303,9 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe Thread.Sleep(_secondsBetweenEnrollmentRetries * 1000); } - string pemCertificate = certStatus == CertificateStatusEnum.ISSUED ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId)).pems.certificate) : string.Empty; + string pemCertificate = certStatus == CertificateStatusEnum.ISSUED + ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate) + : string.Empty; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); @@ -328,7 +330,7 @@ public override CAConnectorCertificate GetSingleRecord(string caRequestID) string issuedCert = string.Empty; if (certStatus == CertificateStatusEnum.ISSUED || certStatus == CertificateStatusEnum.REVOKED || certStatus == CertificateStatusEnum.EXPIRED) { - issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID)).pems.certificate); + issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate); } Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); From 98589e0b5d1ad3ed7917e11e681f2174e39b01d3 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Wed, 3 May 2023 15:08:30 +0000 Subject: [PATCH 16/39] changes --- GoDaddy/API/APIProcessor.cs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index b29c9ce..84d87db 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -139,7 +139,7 @@ public string DownloadCertificate(string certificateId, int maxRetries) retries++; if (retries > maxRetries) { - Logger.Error($"Maximum number of timeout retries of {maxRetries} exceeded for certificate {certificateId} retrieval. Certificate skipped."); + Logger.Warn($"Maximum number of timeout retries of {maxRetries} exceeded for certificate {certificateId} retrieval. Certificate skipped."); throw ex; } else @@ -250,7 +250,7 @@ private string SubmitRequest(RestRequest request) Logger.Trace($"Request Resource: {request.Resource}"); Logger.Trace($"Request Method: {request.Method.ToString()}"); - IRestResponse response; + IRestResponse response = null; RestClient client = new RestClient(ApiUrl); client.Timeout = Timeout; @@ -261,26 +261,28 @@ private string SubmitRequest(RestRequest request) response = client.Execute(request); if (response.ResponseStatus == ResponseStatus.TimedOut) { - NumberOfTimeOuts++; - throw new GoDaddyTimeoutException("Request timed out "); + string msg = "Request timed out. "; + NumberOfTimeOuts++; + + if (NumberOfTimeOuts >= MaxNumberOfTimeouts) + { + msg += $"Maximum timeouts of {MaxNumberOfTimeouts} exceeded. "; + throw new Exception(msg); + } + else + { + Logger.Debug(msg); + throw new GoDaddyTimeoutException(msg); + } } } + catch (GoDaddyTimeoutException ex) { throw ex; } catch (Exception ex) { string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}").Replace(NO_CERTS_PURCHASED_MESSAGE, NO_CERTS_PURCHASED_REPL_MESSAGE); Logger.Error(exceptionMessage); - if (NumberOfTimeOuts >= MaxNumberOfTimeouts) - { - string msg = $"Maximum timeouts of {MaxNumberOfTimeouts} exceeded. " + exceptionMessage; - Logger.Error(msg); - throw new Exception(msg); - } - else - { - Logger.Debug(exceptionMessage); - throw new GoDaddyTimeoutException(exceptionMessage); - } } + Logger.Trace($"Response Status Code: {response.StatusCode}"); if (response.StatusCode != System.Net.HttpStatusCode.OK && From d8cdbdcdda5187ad149090e963e95113f21b9d74 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Wed, 3 May 2023 16:19:34 +0000 Subject: [PATCH 17/39] changes --- GoDaddy/API/APIProcessor.cs | 7 ++++++- GoDaddy/GoDaddyCAProxy.cs | 33 ++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 84d87db..603e64c 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -115,7 +115,7 @@ public string GetCertificate(string certificateId) return SubmitRequest(request); } - public string DownloadCertificate(string certificateId, int maxRetries) + public string DownloadCertificate(string certificateId, int maxRetries, out int numberOfTimeouts, out int durationInMilliseconds) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -131,7 +131,11 @@ public string DownloadCertificate(string certificateId, int maxRetries) { try { + DateTime before = DateTime.Now; cert = SubmitRequest(request); + DateTime after = DateTime.Now; + durationInMilliseconds = after.Subtract(before).Milliseconds; + break; } catch (GoDaddyTimeoutException ex) @@ -147,6 +151,7 @@ public string DownloadCertificate(string certificateId, int maxRetries) } } + numberOfTimeouts = retries; return cert; } diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index dc49e39..298c75f 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -161,18 +161,27 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B int pageNumber = 1; bool wasLastPage = false; - do - { + int totalNumberOfCertsFound = 0; + int totalNumberOfCertsRetrieved = 0; + int totalNumberOfTimeouts = 0; + int totalDurationApiCallsInMilliseconds = 0; + do + { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); if (!certificateAuthoritySyncInfo.DoFullSync && certificateAuthoritySyncInfo.OverallLastSync.HasValue) certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); foreach (CertificateDetails certificate in certificates.certificates) { + totalNumberOfCertsFound++; Thread.Sleep(_millisecondsBetweenCertDownloads); + try { - string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate); + string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId, _numberOfCertDownloadRetriesBeforeSkip, out int numberOfTimeouts, out int durationApiCallInMilliseconds)).pems.certificate); + totalNumberOfTimeouts += numberOfTimeouts; + totalDurationApiCallsInMilliseconds += durationApiCallInMilliseconds; + CertificateStatusEnum certStatus = CertificateStatusEnum.ISSUED; if (!Enum.TryParse(certificate.status, out certStatus)) certStatus = CertificateStatusEnum.CANCELED; @@ -189,8 +198,13 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B SubmissionDate = certificate.createdAt, ProductID = certificate.type }); + + totalNumberOfCertsRetrieved++; + } + catch (GoDaddyException) + { + totalNumberOfTimeouts += _numberOfCertDownloadRetriesBeforeSkip + 1; } - catch (GoDaddyException) { } } wasLastPage = certificates.pagination.previous == certificates.pagination.last; @@ -199,7 +213,12 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B blockingBuffer.CompleteAdding(); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + string syncStats = "SYNC STATISTICS:" + System.Environment.NewLine; + syncStats += $" Total Certificates Found: {totalNumberOfCertsFound.ToString()} + System.Environment.NewLine"; + syncStats += $" Total Certificates Successfully Retrived: {totalNumberOfCertsRetrieved.ToString()} + System.Environment.NewLine"; + syncStats += $" Total Number of GoDaddy Timeouts When Attempting to Retrieve Certificates: {totalNumberOfTimeouts.ToString()} + System.Environment.NewLine"; + syncStats += $" Average Time in Milliseconds For Each Successful GoDaddy Certificate Retrieval API Call: {(totalDurationApiCallsInMilliseconds/totalNumberOfCertsRetrieved).ToString()} + System.Environment.NewLine"; + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } [Obsolete] @@ -304,7 +323,7 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe } string pemCertificate = certStatus == CertificateStatusEnum.ISSUED - ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate) + ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId, _numberOfCertDownloadRetriesBeforeSkip, out int x, out int y)).pems.certificate) : string.Empty; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); @@ -330,7 +349,7 @@ public override CAConnectorCertificate GetSingleRecord(string caRequestID) string issuedCert = string.Empty; if (certStatus == CertificateStatusEnum.ISSUED || certStatus == CertificateStatusEnum.REVOKED || certStatus == CertificateStatusEnum.EXPIRED) { - issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate); + issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID, _numberOfCertDownloadRetriesBeforeSkip, out int x, out int y)).pems.certificate); } Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); From 5064293165dfeb48ce9dd3f66a2a7016802832dc Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 4 May 2023 12:48:48 +0000 Subject: [PATCH 18/39] changes --- GoDaddy/GoDaddyCAProxy.cs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 298c75f..022d5bc 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -31,7 +31,7 @@ public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector private const int SECONDS_BETWEEN_ENROLLMENT_RETRIES_MAX = 20; private int _apiTimeoutInSeconds = 20; - private const int API_TIMEOUT_IN_SECONDS_MIN = 10; + private const int API_TIMEOUT_IN_SECONDS_MIN = 2; private const int API_TIMEOUT_IN_SECONDS_MAX = 100; private int _numberOfCertDownloadRetriesBeforeSkip = 2; @@ -155,8 +155,9 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B public override void Synchronize(ICertificateDataReader certificateDataReader, BlockingCollection blockingBuffer, CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, CancellationToken cancelToken) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + DateTime? overallLastSync = new DateTime(2020, 11, 11); - string customerId = JsonConvert.DeserializeObject(_api.GetCustomerId()).customerId; + string customerId = JsonConvert.DeserializeObject(_api.GetCustomerId()).customerId; int pageNumber = 1; bool wasLastPage = false; @@ -169,9 +170,10 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); if (!certificateAuthoritySyncInfo.DoFullSync && certificateAuthoritySyncInfo.OverallLastSync.HasValue) - certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); + certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > overallLastSync.Value.AddDays(-1)).ToList(); + //certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); - foreach (CertificateDetails certificate in certificates.certificates) + foreach (CertificateDetails certificate in certificates.certificates) { totalNumberOfCertsFound++; Thread.Sleep(_millisecondsBetweenCertDownloads); @@ -214,11 +216,15 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B blockingBuffer.CompleteAdding(); string syncStats = "SYNC STATISTICS:" + System.Environment.NewLine; - syncStats += $" Total Certificates Found: {totalNumberOfCertsFound.ToString()} + System.Environment.NewLine"; - syncStats += $" Total Certificates Successfully Retrived: {totalNumberOfCertsRetrieved.ToString()} + System.Environment.NewLine"; - syncStats += $" Total Number of GoDaddy Timeouts When Attempting to Retrieve Certificates: {totalNumberOfTimeouts.ToString()} + System.Environment.NewLine"; - syncStats += $" Average Time in Milliseconds For Each Successful GoDaddy Certificate Retrieval API Call: {(totalDurationApiCallsInMilliseconds/totalNumberOfCertsRetrieved).ToString()} + System.Environment.NewLine"; - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + syncStats += $" Total Certificates Found: {totalNumberOfCertsFound.ToString()}" + System.Environment.NewLine; + syncStats += $" Total Certificates Successfully Retrived: {totalNumberOfCertsRetrieved.ToString()}" + System.Environment.NewLine; + syncStats += $" Total Number of GoDaddy Timeouts When Attempting to Retrieve Certificates: {totalNumberOfTimeouts.ToString()}" + System.Environment.NewLine; + + int avgDurationApiCallsInMilliseconds = totalNumberOfCertsRetrieved == 0 ? 0 : (totalDurationApiCallsInMilliseconds / totalNumberOfCertsRetrieved); + syncStats += $" Average Time in Milliseconds For Each Successful GoDaddy Certificate Retrieval API Call: {avgDurationApiCallsInMilliseconds.ToString()}" + System.Environment.NewLine; + + Logger.Debug(syncStats); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } [Obsolete] From e84d4d6e871558391a378841241200579a5b2e65 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 4 May 2023 20:53:24 +0000 Subject: [PATCH 19/39] changes --- GoDaddy/API/APIProcessor.cs | 29 +++++++++++------ GoDaddy/API/GoDaddyMaxTimeoutException.cs | 27 ++++++++++++++++ GoDaddy/API/GoDaddyTimeoutException.cs | 4 --- GoDaddy/GoDaddy.csproj | 1 + GoDaddy/GoDaddyCAProxy.cs | 39 ++++++++++------------- 5 files changed, 63 insertions(+), 37 deletions(-) create mode 100644 GoDaddy/API/GoDaddyMaxTimeoutException.cs diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 603e64c..5b84561 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -34,7 +34,10 @@ internal class APIProcessor : LoggingClientBase private const string NO_CERTS_PURCHASED_REPL_MESSAGE = "Failed to create certificate order. This error often occurs if there are no certificates purchased to fulfill this enrollment request. " + "Please check your GoDaddy account to make sure you have the correct SSL certificate product purchased to cover this enrollment."; - private int NumberOfTimeOuts = 0; + + internal int TotalNumberOfTimeouts { get; set; } = 0; + + internal int TotalDurationOfDownloadApiCallsInMilliseconds { get; set; } = 0; public APIProcessor(string apiUrl, string apiKey, string shopperId, int timeout, int maxNumberOfTimeouts) @@ -46,6 +49,7 @@ public APIProcessor(string apiUrl, string apiKey, string shopperId, int timeout, ShopperId = shopperId; Timeout = timeout; MaxNumberOfTimeouts = maxNumberOfTimeouts; + TotalNumberOfTimeouts = 0; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } @@ -115,7 +119,7 @@ public string GetCertificate(string certificateId) return SubmitRequest(request); } - public string DownloadCertificate(string certificateId, int maxRetries, out int numberOfTimeouts, out int durationInMilliseconds) + public string DownloadCertificate(string certificateId, int maxRetries) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -134,7 +138,7 @@ public string DownloadCertificate(string certificateId, int maxRetries, out int DateTime before = DateTime.Now; cert = SubmitRequest(request); DateTime after = DateTime.Now; - durationInMilliseconds = after.Subtract(before).Milliseconds; + TotalDurationOfDownloadApiCallsInMilliseconds += after.Subtract(before).Milliseconds; break; } @@ -151,7 +155,6 @@ public string DownloadCertificate(string certificateId, int maxRetries, out int } } - numberOfTimeouts = retries; return cert; } @@ -258,8 +261,10 @@ private string SubmitRequest(RestRequest request) IRestResponse response = null; RestClient client = new RestClient(ApiUrl); - client.Timeout = Timeout; - request.AddHeader("Authorization", ApiKey); + client.Timeout = request.Resource.ToLower().Contains("download") ? 470 : 20000; + + if (!request.Parameters.Exists(p => p.Name == "Authorization")) + request.AddHeader("Authorization", ApiKey); try { @@ -267,12 +272,12 @@ private string SubmitRequest(RestRequest request) if (response.ResponseStatus == ResponseStatus.TimedOut) { string msg = "Request timed out. "; - NumberOfTimeOuts++; + TotalNumberOfTimeouts++; - if (NumberOfTimeOuts >= MaxNumberOfTimeouts) + if (TotalNumberOfTimeouts >= MaxNumberOfTimeouts) { msg += $"Maximum timeouts of {MaxNumberOfTimeouts} exceeded. "; - throw new Exception(msg); + throw new GoDaddyMaxTimeoutException(msg); } else { @@ -286,6 +291,7 @@ private string SubmitRequest(RestRequest request) { string exceptionMessage = GoDaddyException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}").Replace(NO_CERTS_PURCHASED_MESSAGE, NO_CERTS_PURCHASED_REPL_MESSAGE); Logger.Error(exceptionMessage); + throw ex; } Logger.Trace($"Response Status Code: {response.StatusCode}"); @@ -300,7 +306,10 @@ private string SubmitRequest(RestRequest request) try { APIError error = JsonConvert.DeserializeObject(response.Content); - errorMessage = $"{error.code}: {error.message}"; + if (error == null) + errorMessage = "No error message returned."; + else + errorMessage = $"{error.code}: {error.message}"; } catch (JsonReaderException) { diff --git a/GoDaddy/API/GoDaddyMaxTimeoutException.cs b/GoDaddy/API/GoDaddyMaxTimeoutException.cs new file mode 100644 index 0000000..2b1add1 --- /dev/null +++ b/GoDaddy/API/GoDaddyMaxTimeoutException.cs @@ -0,0 +1,27 @@ +// Copyright 2021 Keyfactor +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace Keyfactor.AnyGateway.GoDaddy.API +{ + class GoDaddyMaxTimeoutException : GoDaddyException + { + public GoDaddyMaxTimeoutException(string message) : base(message) + { } + + public GoDaddyMaxTimeoutException(string message, Exception ex) : base(message, ex) + { } + } +} diff --git a/GoDaddy/API/GoDaddyTimeoutException.cs b/GoDaddy/API/GoDaddyTimeoutException.cs index 826c9a8..b656275 100644 --- a/GoDaddy/API/GoDaddyTimeoutException.cs +++ b/GoDaddy/API/GoDaddyTimeoutException.cs @@ -13,10 +13,6 @@ // limitations under the License. using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Keyfactor.AnyGateway.GoDaddy.API { diff --git a/GoDaddy/GoDaddy.csproj b/GoDaddy/GoDaddy.csproj index 3c7d66b..8c849e6 100644 --- a/GoDaddy/GoDaddy.csproj +++ b/GoDaddy/GoDaddy.csproj @@ -145,6 +145,7 @@ + diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 022d5bc..277bf86 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -59,10 +59,11 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Logger.Trace("GATEWAY CONFIG SETTINGS:"); foreach (KeyValuePair configEntry in configProvider.CAConnectionData) { - if (configEntry.Key != "ApiKey") - Logger.Trace($"{configEntry.Key}: {configEntry.Value}"); + if (configEntry.Key.ToLower() != "apikey") + Logger.Trace($" {configEntry.Key}: {configEntry.Value}"); } ValidateParameters(configProvider.CAConnectionData, _connectionKeys); @@ -71,10 +72,6 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) string shopperId = configProvider.CAConnectionData["ShopperId"].ToString(); _rootType = configProvider.CAConnectionData["RootType"].ToString(); - _syncPageSize = Convert.ToInt32(configProvider.CAConnectionData["SyncPageSize"]); - _enrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["EnrollmentRetries"]); - _secondsBetweenEnrollmentRetries = Convert.ToInt32(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"]); - //optional parameters bool isInt; int tempInt; @@ -94,7 +91,7 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) if (configProvider.CAConnectionData.ContainsKey("SecondsBetweenEnrollmentRetries")) { isInt = int.TryParse(configProvider.CAConnectionData["SecondsBetweenEnrollmentRetries"].ToString(), out tempInt); - _secondsBetweenEnrollmentRetries = !isInt || tempInt < ENROLLMENT_RETRIES_MIN || tempInt > ENROLLMENT_RETRIES_MAX ? _secondsBetweenEnrollmentRetries : tempInt; + _secondsBetweenEnrollmentRetries = !isInt || tempInt < SECONDS_BETWEEN_ENROLLMENT_RETRIES_MIN || tempInt > SECONDS_BETWEEN_ENROLLMENT_RETRIES_MAX ? _secondsBetweenEnrollmentRetries : tempInt; } if (configProvider.CAConnectionData.ContainsKey("ApiTimeoutinSeconds")) @@ -164,8 +161,8 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B int totalNumberOfCertsFound = 0; int totalNumberOfCertsRetrieved = 0; - int totalNumberOfTimeouts = 0; - int totalDurationApiCallsInMilliseconds = 0; + _api.TotalNumberOfTimeouts = 0; + _api.TotalDurationOfDownloadApiCallsInMilliseconds = 0; do { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); @@ -180,9 +177,7 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B try { - string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId, _numberOfCertDownloadRetriesBeforeSkip, out int numberOfTimeouts, out int durationApiCallInMilliseconds)).pems.certificate); - totalNumberOfTimeouts += numberOfTimeouts; - totalDurationApiCallsInMilliseconds += durationApiCallInMilliseconds; + string issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(certificate.certificateId, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate); CertificateStatusEnum certStatus = CertificateStatusEnum.ISSUED; if (!Enum.TryParse(certificate.status, out certStatus)) @@ -203,10 +198,13 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B totalNumberOfCertsRetrieved++; } - catch (GoDaddyException) + catch (GoDaddyMaxTimeoutException) { - totalNumberOfTimeouts += _numberOfCertDownloadRetriesBeforeSkip + 1; + Logger.Error($"Sync failed due to maximum timeouts of {_numberOfTimeoutsBeforeSyncFailure.ToString()} being reached."); + return; } + catch (GoDaddyTimeoutException) { } + catch (Exception) { } } wasLastPage = certificates.pagination.previous == certificates.pagination.last; @@ -218,9 +216,9 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B string syncStats = "SYNC STATISTICS:" + System.Environment.NewLine; syncStats += $" Total Certificates Found: {totalNumberOfCertsFound.ToString()}" + System.Environment.NewLine; syncStats += $" Total Certificates Successfully Retrived: {totalNumberOfCertsRetrieved.ToString()}" + System.Environment.NewLine; - syncStats += $" Total Number of GoDaddy Timeouts When Attempting to Retrieve Certificates: {totalNumberOfTimeouts.ToString()}" + System.Environment.NewLine; + syncStats += $" Total Number of GoDaddy Timeouts When Attempting to Retrieve Certificates: {_api.TotalNumberOfTimeouts.ToString()}" + System.Environment.NewLine; - int avgDurationApiCallsInMilliseconds = totalNumberOfCertsRetrieved == 0 ? 0 : (totalDurationApiCallsInMilliseconds / totalNumberOfCertsRetrieved); + int avgDurationApiCallsInMilliseconds = totalNumberOfCertsRetrieved == 0 ? 0 : (_api.TotalDurationOfDownloadApiCallsInMilliseconds / totalNumberOfCertsRetrieved); syncStats += $" Average Time in Milliseconds For Each Successful GoDaddy Certificate Retrieval API Call: {avgDurationApiCallsInMilliseconds.ToString()}" + System.Environment.NewLine; Logger.Debug(syncStats); @@ -329,7 +327,7 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe } string pemCertificate = certStatus == CertificateStatusEnum.ISSUED - ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId, _numberOfCertDownloadRetriesBeforeSkip, out int x, out int y)).pems.certificate) + ? RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(enrollmentResponse.certificateId, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate) : string.Empty; Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); @@ -355,7 +353,7 @@ public override CAConnectorCertificate GetSingleRecord(string caRequestID) string issuedCert = string.Empty; if (certStatus == CertificateStatusEnum.ISSUED || certStatus == CertificateStatusEnum.REVOKED || certStatus == CertificateStatusEnum.EXPIRED) { - issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID, _numberOfCertDownloadRetriesBeforeSkip, out int x, out int y)).pems.certificate); + issuedCert = RemovePEMHeader(JsonConvert.DeserializeObject(_api.DownloadCertificate(caRequestID, _numberOfCertDownloadRetriesBeforeSkip)).pems.certificate); } Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); @@ -399,11 +397,6 @@ public override void ValidateProductInfo(EnrollmentProductInfo productInfo, Dict } - - - - - #endregion Interface Methods #region Private Methods From befb55a731e5dffae4a7ddc8e9339ff35d05961b Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Fri, 5 May 2023 13:58:14 +0000 Subject: [PATCH 20/39] changes --- GoDaddy/API/APIProcessor.cs | 2 +- GoDaddy/GoDaddyCAProxy.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 5b84561..b63e78f 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -261,7 +261,7 @@ private string SubmitRequest(RestRequest request) IRestResponse response = null; RestClient client = new RestClient(ApiUrl); - client.Timeout = request.Resource.ToLower().Contains("download") ? 470 : 20000; + client.Timeout = Timeout; if (!request.Parameters.Exists(p => p.Name == "Authorization")) request.AddHeader("Authorization", ApiKey); diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 277bf86..99e90ab 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -167,8 +167,7 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B { GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); if (!certificateAuthoritySyncInfo.DoFullSync && certificateAuthoritySyncInfo.OverallLastSync.HasValue) - certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > overallLastSync.Value.AddDays(-1)).ToList(); - //certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); + certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); foreach (CertificateDetails certificate in certificates.certificates) { @@ -215,13 +214,13 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B string syncStats = "SYNC STATISTICS:" + System.Environment.NewLine; syncStats += $" Total Certificates Found: {totalNumberOfCertsFound.ToString()}" + System.Environment.NewLine; - syncStats += $" Total Certificates Successfully Retrived: {totalNumberOfCertsRetrieved.ToString()}" + System.Environment.NewLine; + syncStats += $" Total Certificates Successfully Retrieved: {totalNumberOfCertsRetrieved.ToString()}" + System.Environment.NewLine; syncStats += $" Total Number of GoDaddy Timeouts When Attempting to Retrieve Certificates: {_api.TotalNumberOfTimeouts.ToString()}" + System.Environment.NewLine; int avgDurationApiCallsInMilliseconds = totalNumberOfCertsRetrieved == 0 ? 0 : (_api.TotalDurationOfDownloadApiCallsInMilliseconds / totalNumberOfCertsRetrieved); syncStats += $" Average Time in Milliseconds For Each Successful GoDaddy Certificate Retrieval API Call: {avgDurationApiCallsInMilliseconds.ToString()}" + System.Environment.NewLine; - Logger.Debug(syncStats); + Logger.Info(syncStats); Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } From b57b3f5462286f1a7ef2d7d4667ee60372de1251 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Fri, 5 May 2023 14:33:38 +0000 Subject: [PATCH 21/39] changes --- CHANGELOG.md | 6 ++++++ readme_source.md | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2a091..5d031c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v1.1.0 +- Added partial sync functionality +- Added four new optional settings to Gateway config - ApiTimeoutinSeconds, NumberOfCertDownloadRetriesBeforeSkip, NumberOfTimeoutsBeforeSyncFailure, MillisecondsBetweenCertDownloads +- Added logic for certificate download retries for timeouts based on new settings above +- Added additional sync statistics logging for each sync showing number of certificate retrievals, downloads, and any API timeout counts + v1.0.8 - Improved logging - Improved error handling for API timeouts diff --git a/readme_source.md b/readme_source.md index 92165f8..23463d4 100644 --- a/readme_source.md +++ b/readme_source.md @@ -154,17 +154,44 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho // One of four values based on the CA chain enrolled certificates should be validated against - GODADDY_SHA_1, GODADDY_SHA_2, // STARTFIELD_SHA1, or STARTFIELD_SHA2 "RootType": "GODADDY_SHA_2", + + + // The following 7 settings are all optional. They each have a: 1) default value, 2) minimum allowed value, and + // 3) maximum allowed value. If any value is missing or outside the min/max allowed range, the default value will be used + + // The SyncPageSize represents the number of certificates that will be returned for each GoDaddy "get certificates" API call during a // "sync" operation. The API call will be repeated in batches of this number until all cerificates are retrieved from the GoDady CA. // GoDaddy has no imposed limit on the number of certificates that can be returned, but due to the amount of data being returned for // each call, this number should be set to something reasonable, 50-500. - "SyncPageSize": "50", + "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 + + // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully enroll a certificate (defined as a certificate // being ISSUED or PENDING_ISSUANCE) against the GoDaddy CA before returning an error. - "EnrollmentRetries": "2", + "EnrollmentRetries": "2", //Default=2, Minimum=0, Maximum=5 + + // SecondsBetweenEnrollmentRetries is the amount of time an Enroll operation will wait between enrollment requests against the GoDaddy // CA if the previous attempt did not produce a certificate with a status of ISSUED or PENDING_ISSUANCE. - "SecondsBetweenEnrollmentRetries": "5" + "SecondsBetweenEnrollmentRetries": "5", //Default=5, Minimum=2, Maximum=20 + + + // ApiTimeoutInSeconds is the amount of time in seconds that a GoDaddy API request will wait before the call times out, producing a timeout error. + "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 + + + // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval of any individual certificate will be retried before + // that individual certificate is skipped if the GoDaddy API download request times out. + "NumberOfCertDownloadRetriesBeforeSkip": "2", //Default=2, Minimum=0, Maximum=10 + + + // MillisecondsBetweenCertDownloads is amount of time a sync operation will wait between GoDaddy API download requests. This is necessary because + // GoDaddy places a 60 API request per minute limit on most accounts. After that 60 limit has been reached, GoDaddy will begin returning + // TOO_MANY_REQUEST errors. A value of "1000" (1 second between requests) is recommended, but this is configurable in case an individual account + // allows a higher number of requests. + "MillisecondsBetweenCertDownloads": "1000" //Default=1000, Minimum=0, Maximum=1000 + }, /*Information to register the Gateway for client connections.*/ "GatewayRegistration":{ From 1d35a61dc22aa520cc8f3cbbe2b7989e4a6babf6 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 5 May 2023 14:34:19 +0000 Subject: [PATCH 22/39] Update generated README --- README.md | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0d13285..ac1b79b 100644 --- a/README.md +++ b/README.md @@ -179,17 +179,44 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho // One of four values based on the CA chain enrolled certificates should be validated against - GODADDY_SHA_1, GODADDY_SHA_2, // STARTFIELD_SHA1, or STARTFIELD_SHA2 "RootType": "GODADDY_SHA_2", + + + // The following 7 settings are all optional. They each have a: 1) default value, 2) minimum allowed value, and + // 3) maximum allowed value. If any value is missing or outside the min/max allowed range, the default value will be used + + // The SyncPageSize represents the number of certificates that will be returned for each GoDaddy "get certificates" API call during a // "sync" operation. The API call will be repeated in batches of this number until all cerificates are retrieved from the GoDady CA. // GoDaddy has no imposed limit on the number of certificates that can be returned, but due to the amount of data being returned for // each call, this number should be set to something reasonable, 50-500. - "SyncPageSize": "50", + "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 + + // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully enroll a certificate (defined as a certificate // being ISSUED or PENDING_ISSUANCE) against the GoDaddy CA before returning an error. - "EnrollmentRetries": "2", + "EnrollmentRetries": "2", //Default=2, Minimum=0, Maximum=5 + + // SecondsBetweenEnrollmentRetries is the amount of time an Enroll operation will wait between enrollment requests against the GoDaddy // CA if the previous attempt did not produce a certificate with a status of ISSUED or PENDING_ISSUANCE. - "SecondsBetweenEnrollmentRetries": "5" + "SecondsBetweenEnrollmentRetries": "5", //Default=5, Minimum=2, Maximum=20 + + + // ApiTimeoutInSeconds is the amount of time in seconds that a GoDaddy API request will wait before the call times out, producing a timeout error. + "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 + + + // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval of any individual certificate will be retried before + // that individual certificate is skipped if the GoDaddy API download request times out. + "NumberOfCertDownloadRetriesBeforeSkip": "2", //Default=2, Minimum=0, Maximum=10 + + + // MillisecondsBetweenCertDownloads is amount of time a sync operation will wait between GoDaddy API download requests. This is necessary because + // GoDaddy places a 60 API request per minute limit on most accounts. After that 60 limit has been reached, GoDaddy will begin returning + // TOO_MANY_REQUEST errors. A value of "1000" (1 second between requests) is recommended, but this is configurable in case an individual account + // allows a higher number of requests. + "MillisecondsBetweenCertDownloads": "1000" //Default=1000, Minimum=0, Maximum=1000 + }, /*Information to register the Gateway for client connections.*/ "GatewayRegistration":{ From 0469c54bb58e742c0f0e6eba8b631a1a0444c14f Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Fri, 5 May 2023 16:03:04 +0000 Subject: [PATCH 23/39] changes --- readme_source.md | 56 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/readme_source.md b/readme_source.md index 23463d4..0ba12fb 100644 --- a/readme_source.md +++ b/readme_source.md @@ -144,52 +144,64 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho },*/ /*Information necessary to authenticate to the CA.*/ "CAConnection":{ - // Base URL for GoDaddy API calls. This value should probably not need to change from what is shown below + // Base URL for GoDaddy API calls. This value should probably not need to change + // from what is shown below "APIUrl": "https://api.ote-godaddy.com", - // The ShopperId is the "Customer #" found by selecting the pulldown on the top right of the GoDaddy portal home page - // after signing in using the account being used for the Gateway + // The ShopperId is the "Customer #" found by selecting the pulldown on the top + // right of the GoDaddy portal home page after signing in using the account + // being used for the Gateway "ShopperId": "9999999999", // The APIKey is the GoDaddy API Key and secret mentioned in "Prerequisites" "APIKey": "sso-key {large string value API Key}:{large string value API Secret}", - // One of four values based on the CA chain enrolled certificates should be validated against - GODADDY_SHA_1, GODADDY_SHA_2, - // STARTFIELD_SHA1, or STARTFIELD_SHA2 + // One of four values based on the CA chain enrolled certificates should be + // validated against - GODADDY_SHA_1, GODADDY_SHA_2, STARTFIELD_SHA1, or STARTFIELD_SHA2 "RootType": "GODADDY_SHA_2", - // The following 7 settings are all optional. They each have a: 1) default value, 2) minimum allowed value, and - // 3) maximum allowed value. If any value is missing or outside the min/max allowed range, the default value will be used + // The following 7 settings are all optional. They each have a: 1) default value, + // 2) minimum allowed value, and 3) maximum allowed value. If any value is missing + // or outside the min/max allowed range, the default value will be used - // The SyncPageSize represents the number of certificates that will be returned for each GoDaddy "get certificates" API call during a - // "sync" operation. The API call will be repeated in batches of this number until all cerificates are retrieved from the GoDady CA. - // GoDaddy has no imposed limit on the number of certificates that can be returned, but due to the amount of data being returned for - // each call, this number should be set to something reasonable, 50-500. + // The SyncPageSize represents the number of certificates that will be returned + // for each GoDaddy "get certificates" API call during a "sync" operation. + // The API call will be repeated in batches of this number until all cerificates + // are retrieved from the GoDady CA. GoDaddy has no imposed limit on the number + // of certificates that can be returned, but due to the amount of data being returned + // for each call, this number should be set to something reasonable, 50-500.for each call. "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 - // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully enroll a certificate (defined as a certificate - // being ISSUED or PENDING_ISSUANCE) against the GoDaddy CA before returning an error. + // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully + // enroll a certificate (defined as a certificate being ISSUED or PENDING_ISSUANCE) + // against the GoDaddy CA before returning an error. "EnrollmentRetries": "2", //Default=2, Minimum=0, Maximum=5 - // SecondsBetweenEnrollmentRetries is the amount of time an Enroll operation will wait between enrollment requests against the GoDaddy - // CA if the previous attempt did not produce a certificate with a status of ISSUED or PENDING_ISSUANCE. + // SecondsBetweenEnrollmentRetries is the amount of time an Enroll operation will wait + // between enrollment requests against the GoDaddy CA if the previous attempt did not + // produce a certificate with a status of ISSUED or PENDING_ISSUANCE. "SecondsBetweenEnrollmentRetries": "5", //Default=5, Minimum=2, Maximum=20 - // ApiTimeoutInSeconds is the amount of time in seconds that a GoDaddy API request will wait before the call times out, producing a timeout error. + // ApiTimeoutInSeconds is the amount of time in seconds that a GoDaddy API request + // will wait before the call times out, producing a timeout error. "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 - // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval of any individual certificate will be retried before - // that individual certificate is skipped if the GoDaddy API download request times out. + // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval + // of any individual certificate will be retried before that individual certificate is + // skipped if the GoDaddy API download request times out. "NumberOfCertDownloadRetriesBeforeSkip": "2", //Default=2, Minimum=0, Maximum=10 - // MillisecondsBetweenCertDownloads is amount of time a sync operation will wait between GoDaddy API download requests. This is necessary because - // GoDaddy places a 60 API request per minute limit on most accounts. After that 60 limit has been reached, GoDaddy will begin returning - // TOO_MANY_REQUEST errors. A value of "1000" (1 second between requests) is recommended, but this is configurable in case an individual account - // allows a higher number of requests. + // MillisecondsBetweenCertDownloads is the amount of time, in milliseconds a sync + // operation will wait between GoDaddy API download requests. This is necessary + // because GoDaddy places a 60 API request per minute limit on most accounts. + // After that 60 limit has been reached, GoDaddy will begin returning + // TOO_MANY_REQUEST errors. A value of "1000" (1 second between requests) is + // recommended, but this is configurable in case an individual account allows a + // higher number of requests. "MillisecondsBetweenCertDownloads": "1000" //Default=1000, Minimum=0, Maximum=1000 }, From fd8e894f6aa6689f8515bf3dd6074fd6e5ca96f4 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 5 May 2023 16:04:20 +0000 Subject: [PATCH 24/39] Update generated README --- README.md | 56 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ac1b79b..faa16af 100644 --- a/README.md +++ b/README.md @@ -169,52 +169,64 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho },*/ /*Information necessary to authenticate to the CA.*/ "CAConnection":{ - // Base URL for GoDaddy API calls. This value should probably not need to change from what is shown below + // Base URL for GoDaddy API calls. This value should probably not need to change + // from what is shown below "APIUrl": "https://api.ote-godaddy.com", - // The ShopperId is the "Customer #" found by selecting the pulldown on the top right of the GoDaddy portal home page - // after signing in using the account being used for the Gateway + // The ShopperId is the "Customer #" found by selecting the pulldown on the top + // right of the GoDaddy portal home page after signing in using the account + // being used for the Gateway "ShopperId": "9999999999", // The APIKey is the GoDaddy API Key and secret mentioned in "Prerequisites" "APIKey": "sso-key {large string value API Key}:{large string value API Secret}", - // One of four values based on the CA chain enrolled certificates should be validated against - GODADDY_SHA_1, GODADDY_SHA_2, - // STARTFIELD_SHA1, or STARTFIELD_SHA2 + // One of four values based on the CA chain enrolled certificates should be + // validated against - GODADDY_SHA_1, GODADDY_SHA_2, STARTFIELD_SHA1, or STARTFIELD_SHA2 "RootType": "GODADDY_SHA_2", - // The following 7 settings are all optional. They each have a: 1) default value, 2) minimum allowed value, and - // 3) maximum allowed value. If any value is missing or outside the min/max allowed range, the default value will be used + // The following 7 settings are all optional. They each have a: 1) default value, + // 2) minimum allowed value, and 3) maximum allowed value. If any value is missing + // or outside the min/max allowed range, the default value will be used - // The SyncPageSize represents the number of certificates that will be returned for each GoDaddy "get certificates" API call during a - // "sync" operation. The API call will be repeated in batches of this number until all cerificates are retrieved from the GoDady CA. - // GoDaddy has no imposed limit on the number of certificates that can be returned, but due to the amount of data being returned for - // each call, this number should be set to something reasonable, 50-500. + // The SyncPageSize represents the number of certificates that will be returned + // for each GoDaddy "get certificates" API call during a "sync" operation. + // The API call will be repeated in batches of this number until all cerificates + // are retrieved from the GoDady CA. GoDaddy has no imposed limit on the number + // of certificates that can be returned, but due to the amount of data being returned + // for each call, this number should be set to something reasonable, 50-500.for each call. "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 - // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully enroll a certificate (defined as a certificate - // being ISSUED or PENDING_ISSUANCE) against the GoDaddy CA before returning an error. + // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully + // enroll a certificate (defined as a certificate being ISSUED or PENDING_ISSUANCE) + // against the GoDaddy CA before returning an error. "EnrollmentRetries": "2", //Default=2, Minimum=0, Maximum=5 - // SecondsBetweenEnrollmentRetries is the amount of time an Enroll operation will wait between enrollment requests against the GoDaddy - // CA if the previous attempt did not produce a certificate with a status of ISSUED or PENDING_ISSUANCE. + // SecondsBetweenEnrollmentRetries is the amount of time an Enroll operation will wait + // between enrollment requests against the GoDaddy CA if the previous attempt did not + // produce a certificate with a status of ISSUED or PENDING_ISSUANCE. "SecondsBetweenEnrollmentRetries": "5", //Default=5, Minimum=2, Maximum=20 - // ApiTimeoutInSeconds is the amount of time in seconds that a GoDaddy API request will wait before the call times out, producing a timeout error. + // ApiTimeoutInSeconds is the amount of time in seconds that a GoDaddy API request + // will wait before the call times out, producing a timeout error. "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 - // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval of any individual certificate will be retried before - // that individual certificate is skipped if the GoDaddy API download request times out. + // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval + // of any individual certificate will be retried before that individual certificate is + // skipped if the GoDaddy API download request times out. "NumberOfCertDownloadRetriesBeforeSkip": "2", //Default=2, Minimum=0, Maximum=10 - // MillisecondsBetweenCertDownloads is amount of time a sync operation will wait between GoDaddy API download requests. This is necessary because - // GoDaddy places a 60 API request per minute limit on most accounts. After that 60 limit has been reached, GoDaddy will begin returning - // TOO_MANY_REQUEST errors. A value of "1000" (1 second between requests) is recommended, but this is configurable in case an individual account - // allows a higher number of requests. + // MillisecondsBetweenCertDownloads is the amount of time, in milliseconds a sync + // operation will wait between GoDaddy API download requests. This is necessary + // because GoDaddy places a 60 API request per minute limit on most accounts. + // After that 60 limit has been reached, GoDaddy will begin returning + // TOO_MANY_REQUEST errors. A value of "1000" (1 second between requests) is + // recommended, but this is configurable in case an individual account allows a + // higher number of requests. "MillisecondsBetweenCertDownloads": "1000" //Default=1000, Minimum=0, Maximum=1000 }, From 0dc6e0fff1f75fc8c3eef352c5513a9f1f1ff459 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Fri, 5 May 2023 17:07:03 +0000 Subject: [PATCH 25/39] changes --- readme_source.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme_source.md b/readme_source.md index 0ba12fb..3aa63d7 100644 --- a/readme_source.md +++ b/readme_source.md @@ -195,6 +195,11 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "NumberOfCertDownloadRetriesBeforeSkip": "2", //Default=2, Minimum=0, Maximum=10 + // NumberOfTimeoutsBeforeSyncFailure is the total number of timeouts all GoDaddy + // API requests can return during a sync before the sync will fail with an error + "NumberOfTimeoutsBeforeSyncFailure": "2", //Default=100, Minimum=0, Maximum=5000 + + // MillisecondsBetweenCertDownloads is the amount of time, in milliseconds a sync // operation will wait between GoDaddy API download requests. This is necessary // because GoDaddy places a 60 API request per minute limit on most accounts. From 24baecf5f0a637f615bcddb179ed89b4936cf9b7 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 5 May 2023 17:07:56 +0000 Subject: [PATCH 26/39] Update generated README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index faa16af..cbf17c2 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,11 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "NumberOfCertDownloadRetriesBeforeSkip": "2", //Default=2, Minimum=0, Maximum=10 + // NumberOfTimeoutsBeforeSyncFailure is the total number of timeouts all GoDaddy + // API requests can return during a sync before the sync will fail with an error + "NumberOfTimeoutsBeforeSyncFailure": "2", //Default=100, Minimum=0, Maximum=5000 + + // MillisecondsBetweenCertDownloads is the amount of time, in milliseconds a sync // operation will wait between GoDaddy API download requests. This is necessary // because GoDaddy places a 60 API request per minute limit on most accounts. From e75951b920619b0a6fd83882c1aa897f6e6907f3 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Mon, 8 May 2023 16:59:53 +0000 Subject: [PATCH 27/39] changes --- CHANGELOG.md | 3 ++- GoDaddy/API/APIProcessor.cs | 33 +++++++++++++++++++++++++++++++-- GoDaddy/GoDaddyCAProxy.cs | 33 ++++++++++++++++++++++++++++++--- readme_source.md | 5 +++++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d031c1..aa69eb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ v1.1.0 - Added partial sync functionality -- Added four new optional settings to Gateway config - ApiTimeoutinSeconds, NumberOfCertDownloadRetriesBeforeSkip, NumberOfTimeoutsBeforeSyncFailure, MillisecondsBetweenCertDownloads +- Added five new optional settings to Gateway config - ApiTimeoutinSeconds, NumberOfCertPageRetrievalRetriesBeforeFailure, NumberOfCertDownloadRetriesBeforeSkip, + NumberOfTimeoutsBeforeSyncFailure, MillisecondsBetweenCertDownloads - Added logic for certificate download retries for timeouts based on new settings above - Added additional sync statistics logging for each sync showing number of certificate retrievals, downloads, and any API timeout counts diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index b63e78f..0a0f7fa 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -18,6 +18,8 @@ using Newtonsoft.Json; using RestSharp; using System; +using Org.BouncyCastle.Ocsp; +using System.Runtime.ConstrainedExecution; namespace Keyfactor.AnyGateway.GoDaddy.API { @@ -91,7 +93,7 @@ public string RenewReissueCSR(string certificateId, string csr, POSTCertificateR return SubmitRequest(request); } - public string GetCertificates(string customerId, int pageNumber, int pageSize) + public string GetCertificates(string customerId, int pageNumber, int pageSize, int maxRetries) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); @@ -102,7 +104,29 @@ public string GetCertificates(string customerId, int pageNumber, int pageSize) Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return SubmitRequest(request); + int retries = 0; + while (true) + { + try + { + rtnMessage = SubmitRequest(request); + break; + } + catch (GoDaddyTimeoutException ex) + { + retries++; + if (retries > maxRetries) + { + string msg = $"Maximum number of timeout retries of {maxRetries} exceeded for certificate page retrieval."; + Logger.Error(msg); + throw new GoDaddyMaxTimeoutException(msg); + } + else + continue; + } + } + + return rtnMessage; } public string GetCertificate(string certificateId) @@ -256,6 +280,11 @@ private string SubmitRequest(RestRequest request) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); Logger.Trace($"Request Resource: {request.Resource}"); + foreach (Parameter parameter in request.Parameters) + { + if (parameter.Name.ToLower() != "authorization") + Logger.Trace($"{parameter.Name}: {parameter.Value.ToString()}"); + } Logger.Trace($"Request Method: {request.Method.ToString()}"); IRestResponse response = null; diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index 99e90ab..f4bd4ca 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -34,6 +34,10 @@ public class GoDaddyCAProxy : CAProxy.AnyGateway.BaseCAConnector private const int API_TIMEOUT_IN_SECONDS_MIN = 2; private const int API_TIMEOUT_IN_SECONDS_MAX = 100; + private int _numberOfCertPageRetrievalRetriesBeforeFailure = 2; + private const int NUMBER_OF_CERT_PAGE_RETRIEVAL_RETRIES_BEFORE_FAILURE_MIN = 0; + private const int NUMBER_OF_CERT_PAGE_RETRIEVAL_RETRIES_BEFORE_FAILURE_MAX = 10; + private int _numberOfCertDownloadRetriesBeforeSkip = 2; private const int NUMBER_OF_CERT_DOWNLOAD_RETRIES_BEFORE_SKIP_MIN = 0; private const int NUMBER_OF_CERT_DOWNLOAD_RETRIES_BEFORE_SKIP_MAX = 10; @@ -59,7 +63,12 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - Logger.Trace("GATEWAY CONFIG SETTINGS:"); + Logger.Info($"Keyfactor Gateway Version: {System.Reflection.Assembly.GetCallingAssembly().GetName().Version.ToString()}"); + List assemblies = System.AppDomain.CurrentDomain.GetAssemblies().Where(p => p.FullName.ToLower().Contains("godaddy")).ToList(); + if (assemblies.Count == 1) + Logger.Info($"GoDaddy Gateway Version: {assemblies[0].FullName}"); + + Logger.Trace("GATEWAY CONFIG SETTINGS:"); foreach (KeyValuePair configEntry in configProvider.CAConnectionData) { if (configEntry.Key.ToLower() != "apikey") @@ -100,6 +109,12 @@ public override void Initialize(ICAConnectorConfigProvider configProvider) _apiTimeoutInSeconds = !isInt || tempInt < API_TIMEOUT_IN_SECONDS_MIN || tempInt > API_TIMEOUT_IN_SECONDS_MAX ? _apiTimeoutInSeconds : tempInt; } + if (configProvider.CAConnectionData.ContainsKey("NumberOfCertPageRetrievalRetriesBeforeFailure")) + { + isInt = int.TryParse(configProvider.CAConnectionData["NumberOfCertPageRetrievalRetriesBeforeFailure"].ToString(), out tempInt); + _numberOfCertPageRetrievalRetriesBeforeFailure = !isInt || tempInt < NUMBER_OF_CERT_PAGE_RETRIEVAL_RETRIES_BEFORE_FAILURE_MIN || tempInt > NUMBER_OF_CERT_PAGE_RETRIEVAL_RETRIES_BEFORE_FAILURE_MAX ? _numberOfCertPageRetrievalRetriesBeforeFailure : tempInt; + } + if (configProvider.CAConnectionData.ContainsKey("NumberOfCertDownloadRetriesBeforeSkip")) { isInt = int.TryParse(configProvider.CAConnectionData["NumberOfCertDownloadRetriesBeforeSkip"].ToString(), out tempInt); @@ -165,11 +180,23 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B _api.TotalDurationOfDownloadApiCallsInMilliseconds = 0; do { - GETCertificatesDetailsResponse certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize)); + GETCertificatesDetailsResponse certificates = new GETCertificatesDetailsResponse(); + + try + { + certificates = JsonConvert.DeserializeObject(_api.GetCertificates(customerId, pageNumber, _syncPageSize, _numberOfCertPageRetrievalRetriesBeforeFailure)); + } + catch (GoDaddyMaxTimeoutException) + { + Logger.Error($"Sync failed due to maximum timeouts of {_numberOfCertPageRetrievalRetriesBeforeFailure.ToString()} being reached for certificate page retrieval."); + return; + } + catch (GoDaddyTimeoutException) { } + if (!certificateAuthoritySyncInfo.DoFullSync && certificateAuthoritySyncInfo.OverallLastSync.HasValue) certificates.certificates = certificates.certificates.Where(p => p.completedAt.HasValue && p.completedAt.Value > certificateAuthoritySyncInfo.OverallLastSync.Value.AddDays(-1)).ToList(); - foreach (CertificateDetails certificate in certificates.certificates) + foreach (CertificateDetails certificate in certificates.certificates) { totalNumberOfCertsFound++; Thread.Sleep(_millisecondsBetweenCertDownloads); diff --git a/readme_source.md b/readme_source.md index 3aa63d7..c5f6c7e 100644 --- a/readme_source.md +++ b/readme_source.md @@ -189,6 +189,11 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 + // NumberOfCertPageRetrievalRetriesBeforeFailure is the number of times during a sync the retrieval + // of an individual page of certificates will be retried after a timeout before the sync will fail + "NumberOfCertPageRetrievalRetriesBeforeFailure": "2", //Default=2, Minimum=0, Maximum=10 + + // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval // of any individual certificate will be retried before that individual certificate is // skipped if the GoDaddy API download request times out. From 0a4103d961dbebb281d268f61233553592af50b1 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Mon, 8 May 2023 17:00:43 +0000 Subject: [PATCH 28/39] Update generated README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index cbf17c2..ba05ed4 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,11 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 + // NumberOfCertPageRetrievalRetriesBeforeFailure is the number of times during a sync the retrieval + // of an individual page of certificates will be retried after a timeout before the sync will fail + "NumberOfCertPageRetrievalRetriesBeforeFailure": "2", //Default=2, Minimum=0, Maximum=10 + + // NumberOfCertDownloadRetriesBeforeSkip is the number of times during a sync the retrieval // of any individual certificate will be retried before that individual certificate is // skipped if the GoDaddy API download request times out. From 8563ceca1b525e2cb57735e96e311d3f9f1ec5b3 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Mon, 8 May 2023 17:07:32 +0000 Subject: [PATCH 29/39] commit --- readme_source.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/readme_source.md b/readme_source.md index c5f6c7e..172360a 100644 --- a/readme_source.md +++ b/readme_source.md @@ -189,8 +189,9 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 - // NumberOfCertPageRetrievalRetriesBeforeFailure is the number of times during a sync the retrieval - // of an individual page of certificates will be retried after a timeout before the sync will fail + // NumberOfCertPageRetrievalRetriesBeforeFailure is the number of times during a sync + // the retrieval of an individual page of certificates will be retried after a + // timeout before the sync will fail "NumberOfCertPageRetrievalRetriesBeforeFailure": "2", //Default=2, Minimum=0, Maximum=10 From 021218a2f547afe3937ce10672b528c8f2b2e237 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Mon, 8 May 2023 17:08:24 +0000 Subject: [PATCH 30/39] Update generated README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba05ed4..cc194c6 100644 --- a/README.md +++ b/README.md @@ -214,8 +214,9 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "ApiTimeoutInSeconds": "20", //Default=20, Minimum=2, Maximum=100 - // NumberOfCertPageRetrievalRetriesBeforeFailure is the number of times during a sync the retrieval - // of an individual page of certificates will be retried after a timeout before the sync will fail + // NumberOfCertPageRetrievalRetriesBeforeFailure is the number of times during a sync + // the retrieval of an individual page of certificates will be retried after a + // timeout before the sync will fail "NumberOfCertPageRetrievalRetriesBeforeFailure": "2", //Default=2, Minimum=0, Maximum=10 From 388fe515ac71803990d15caa586e101498cbda74 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Mon, 8 May 2023 17:16:06 +0000 Subject: [PATCH 31/39] changes --- readme_source.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme_source.md b/readme_source.md index 172360a..f0fe09c 100644 --- a/readme_source.md +++ b/readme_source.md @@ -158,18 +158,18 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "RootType": "GODADDY_SHA_2", - // The following 7 settings are all optional. They each have a: 1) default value, - // 2) minimum allowed value, and 3) maximum allowed value. If any value is missing - // or outside the min/max allowed range, the default value will be used - - // The SyncPageSize represents the number of certificates that will be returned // for each GoDaddy "get certificates" API call during a "sync" operation. // The API call will be repeated in batches of this number until all cerificates // are retrieved from the GoDady CA. GoDaddy has no imposed limit on the number // of certificates that can be returned, but due to the amount of data being returned // for each call, this number should be set to something reasonable, 50-500.for each call. - "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 + "SyncPageSize": "50", + + + // The following 7 settings are all optional. They each have a: 1) default value, + // 2) minimum allowed value, and 3) maximum allowed value. If any value is missing + // or outside the min/max allowed range, the default value will be used // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully From 857bcf9f4e62d0ab4b21bd65d5859ed3b14e4183 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Mon, 8 May 2023 17:18:45 +0000 Subject: [PATCH 32/39] Update generated README --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cc194c6..76b9b6a 100644 --- a/README.md +++ b/README.md @@ -183,18 +183,18 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho "RootType": "GODADDY_SHA_2", - // The following 7 settings are all optional. They each have a: 1) default value, - // 2) minimum allowed value, and 3) maximum allowed value. If any value is missing - // or outside the min/max allowed range, the default value will be used - - // The SyncPageSize represents the number of certificates that will be returned // for each GoDaddy "get certificates" API call during a "sync" operation. // The API call will be repeated in batches of this number until all cerificates // are retrieved from the GoDady CA. GoDaddy has no imposed limit on the number // of certificates that can be returned, but due to the amount of data being returned // for each call, this number should be set to something reasonable, 50-500.for each call. - "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 + "SyncPageSize": "50", + + + // The following 7 settings are all optional. They each have a: 1) default value, + // 2) minimum allowed value, and 3) maximum allowed value. If any value is missing + // or outside the min/max allowed range, the default value will be used // EnrollmentRetries is the number of tries an Enroll operation will attempt to successfully From fd8ba211c9ab31cd45506110876660a2a9f8663e Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Mon, 8 May 2023 17:28:35 +0000 Subject: [PATCH 33/39] changes --- readme_source.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme_source.md b/readme_source.md index f0fe09c..d0ee545 100644 --- a/readme_source.md +++ b/readme_source.md @@ -163,8 +163,8 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho // The API call will be repeated in batches of this number until all cerificates // are retrieved from the GoDady CA. GoDaddy has no imposed limit on the number // of certificates that can be returned, but due to the amount of data being returned - // for each call, this number should be set to something reasonable, 50-500.for each call. - "SyncPageSize": "50", + // for each call, certificate data may need to be returned in batches. + "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 // The following 7 settings are all optional. They each have a: 1) default value, From d34859d5e7f0461c695d589fda6a23ed46b04e1a Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Mon, 8 May 2023 17:29:17 +0000 Subject: [PATCH 34/39] Update generated README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 76b9b6a..1a127ed 100644 --- a/README.md +++ b/README.md @@ -188,8 +188,8 @@ After installing the Keyfactor AnyGateway service (see Prerequisites), there sho // The API call will be repeated in batches of this number until all cerificates // are retrieved from the GoDady CA. GoDaddy has no imposed limit on the number // of certificates that can be returned, but due to the amount of data being returned - // for each call, this number should be set to something reasonable, 50-500.for each call. - "SyncPageSize": "50", + // for each call, certificate data may need to be returned in batches. + "SyncPageSize": "50", //Default=50, Minimum=10, Maximum=1000 // The following 7 settings are all optional. They each have a: 1) default value, From 78f3cbaa1e82b405081e00c26482a7501994d9df Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Wed, 10 May 2023 12:32:17 +0000 Subject: [PATCH 35/39] changes --- GoDaddy/GoDaddyCAProxy.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GoDaddy/GoDaddyCAProxy.cs b/GoDaddy/GoDaddyCAProxy.cs index f4bd4ca..a7ed9dd 100644 --- a/GoDaddy/GoDaddyCAProxy.cs +++ b/GoDaddy/GoDaddyCAProxy.cs @@ -180,7 +180,8 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, B _api.TotalDurationOfDownloadApiCallsInMilliseconds = 0; do { - GETCertificatesDetailsResponse certificates = new GETCertificatesDetailsResponse(); + Thread.Sleep(_millisecondsBetweenCertDownloads); + GETCertificatesDetailsResponse certificates = new GETCertificatesDetailsResponse(); try { From fbb45f4f032a7d29804b6b80e03e732a4907c2c2 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 11 May 2023 16:23:50 +0000 Subject: [PATCH 36/39] changes --- GoDaddy/API/APIProcessor.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index 0a0f7fa..a3d1c57 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -298,7 +298,10 @@ private string SubmitRequest(RestRequest request) try { response = client.Execute(request); - if (response.ResponseStatus == ResponseStatus.TimedOut) + Logger.Trace($"Http Status Code: {response.StatusCode}"); + Logger.Trace($"Response Status: {response.ResponseStatus}"); + + if (response.ResponseStatus == ResponseStatus.TimedOut || response.StatusCode == 0) { string msg = "Request timed out. "; TotalNumberOfTimeouts++; @@ -323,8 +326,6 @@ private string SubmitRequest(RestRequest request) throw ex; } - Logger.Trace($"Response Status Code: {response.StatusCode}"); - if (response.StatusCode != System.Net.HttpStatusCode.OK && response.StatusCode != System.Net.HttpStatusCode.Accepted && response.StatusCode != System.Net.HttpStatusCode.Created && From 86da9e687fae237d5152836ece5c3c804f942083 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Tue, 16 May 2023 16:23:50 +0000 Subject: [PATCH 37/39] changes --- GoDaddy/API/APIProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GoDaddy/API/APIProcessor.cs b/GoDaddy/API/APIProcessor.cs index a3d1c57..74db08c 100644 --- a/GoDaddy/API/APIProcessor.cs +++ b/GoDaddy/API/APIProcessor.cs @@ -346,7 +346,7 @@ private string SubmitRequest(RestRequest request) errorMessage = response.Content; } - string exceptionMessage = $"Error processing {request.Resource}: {errorMessage}"; + string exceptionMessage = $"Error processing {request.Resource}: {errorMessage.Replace(NO_CERTS_PURCHASED_MESSAGE, NO_CERTS_PURCHASED_REPL_MESSAGE)}"; Logger.Error(exceptionMessage); throw new GoDaddyException(exceptionMessage); } From 7e22a0a735aa55d4bbcff4b7db33ad9ad888858f Mon Sep 17 00:00:00 2001 From: Lee Fine <50836957+leefine02@users.noreply.github.com> Date: Fri, 19 May 2023 12:47:22 -0400 Subject: [PATCH 38/39] Update readme_source.md --- readme_source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme_source.md b/readme_source.md index d0ee545..5a48062 100644 --- a/readme_source.md +++ b/readme_source.md @@ -24,7 +24,7 @@ GoDaddy supports the following certificate products: # Getting Started ### Prerequsites -To begin, you must have the AnyGateway Service installed and operational before attempting to configure the GoDaddy AnyGateway plugin. **INSTALLATION INSTRUCTIONS LINK** +To begin, you must have the AnyGateway Service installed and operational before attempting to configure the GoDaddy AnyGateway plugin. A production GoDaddy account must be set up that will be associated with the gateway and an API Key/Secret created. For more information on how to create an API Key, follow the instructions [here](https://developer.godaddy.com/keys). From 05aab956bc02a85b82b13bdde825366895471c53 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 19 May 2023 16:48:03 +0000 Subject: [PATCH 39/39] Update generated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a127ed..917f2bf 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ GoDaddy supports the following certificate products: # Getting Started ### Prerequsites -To begin, you must have the AnyGateway Service installed and operational before attempting to configure the GoDaddy AnyGateway plugin. **INSTALLATION INSTRUCTIONS LINK** +To begin, you must have the AnyGateway Service installed and operational before attempting to configure the GoDaddy AnyGateway plugin. A production GoDaddy account must be set up that will be associated with the gateway and an API Key/Secret created. For more information on how to create an API Key, follow the instructions [here](https://developer.godaddy.com/keys).