From a1b7589d8003b277138d18d830793edece22a876 Mon Sep 17 00:00:00 2001 From: David Galey Date: Tue, 30 Jun 2026 13:47:20 -0400 Subject: [PATCH 1/2] add product ID filter to sync --- .../API/ListCertificateOrders.cs | 11 +++- .../CertCentralCAPlugin.cs | 61 +++++++++---------- .../CertCentralConfig.cs | 15 +++++ .../Client/CertCentralClient.cs | 5 +- digicert-certcentral-caplugin/Constants.cs | 1 + 5 files changed, 57 insertions(+), 36 deletions(-) diff --git a/digicert-certcentral-caplugin/API/ListCertificateOrders.cs b/digicert-certcentral-caplugin/API/ListCertificateOrders.cs index 7a62f6d..73714c8 100644 --- a/digicert-certcentral-caplugin/API/ListCertificateOrders.cs +++ b/digicert-certcentral-caplugin/API/ListCertificateOrders.cs @@ -29,7 +29,8 @@ public ListCertificateOrdersRequest(bool ignoreExpired = false) public bool ignoreExpired { get; set; } public int expiredWindow { get; set; } = 0; - public string divID { get; set; } = string.Empty; + public List divIDs { get; set; } = new List(); + public List productIDs { get; set; } = new List(); public new string BuildParameters() { @@ -38,9 +39,13 @@ public ListCertificateOrdersRequest(bool ignoreExpired = false) sbParamters.Append("limit=").Append(this.limit.ToString()); sbParamters.Append("&offset=").Append(HttpUtility.UrlEncode(this.offset.ToString())); - if (!string.IsNullOrEmpty(divID)) + foreach (string divID in this.divIDs) { - sbParamters.Append("&filters[container_id]=").Append(this.divID); + sbParamters.Append("&filters[container_id]=").Append(divID); + } + foreach (string productID in productIDs) + { + sbParamters.Append("&filters[product_name_id]=").Append(productID); } if (ignoreExpired) { diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index c71a6a2..0830e09 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -476,6 +476,13 @@ public Dictionary GetCAConnectorAnnotations() DefaultValue = "", Type = "String" }, + [CertCentralConstants.Config.SYNC_PROD_FILTER] = new PropertyConfigInfo() + { + Comments = "If you list one or more Product IDs here (comma-separated), the sync process will filter records to only return orders of those product types. Leave empty to sync all products.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, [CertCentralConstants.Config.FILTER_EXPIRED] = new PropertyConfigInfo() { Comments = "If set to 'true', syncing will apply a filter to not return orders that are expired for longer than specified in SyncExpirationDays.", @@ -834,12 +841,17 @@ public async Task Synchronize(BlockingCollection blockin caList.ForEach(c => c.ToUpper()); - List divFilters = null; + List divFilters = new List(); if (!string.IsNullOrEmpty(_config.SyncDivisionFilter)) { - divFilters = new List(); divFilters.AddRange(_config.SyncDivisionFilter.Split(',')); } + List productFilters = new List(); + if (!string.IsNullOrEmpty(_config.SyncProductFilter)) + { + _logger.LogTrace($"Sync Products: {_config.SyncProductFilter}"); + productFilters = _config.SyncProducts; + } if (fullSync) { @@ -857,37 +869,20 @@ public async Task Synchronize(BlockingCollection blockin long starttime = time; _logger.LogDebug($"SYNC: Starting sync at time {time}"); List allOrders = new List(); - if (divFilters != null) + + ListCertificateOrdersResponse ordersResponse = client.ListAllCertificateOrders(ignoreExpired, expiredWindow, divFilters, productFilters); + if (ordersResponse.Status == CertCentralBaseResponse.StatusType.ERROR) { - foreach (string div in divFilters) - { - ListCertificateOrdersResponse ordersResponse = client.ListAllCertificateOrders(ignoreExpired, expiredWindow, div); - if (ordersResponse.Status == CertCentralBaseResponse.StatusType.ERROR) - { - Error error = ordersResponse.Errors[0]; - _logger.LogError("Error in listing all certificate orders"); - throw new Exception($"DigiCert CertCentral web service returned {error.code} - {error.message} when retrieving all rows"); - } - else - { - allOrders.AddRange(ordersResponse.orders); - } - } + Error error = ordersResponse.Errors[0]; + _logger.LogError("Error in listing all certificate orders"); + throw new Exception($"DigiCert CertCentral web service returned {error.code} - {error.message} when retrieving all rows"); } else { - ListCertificateOrdersResponse ordersResponse = client.ListAllCertificateOrders(ignoreExpired, expiredWindow, null); - if (ordersResponse.Status == CertCentralBaseResponse.StatusType.ERROR) - { - Error error = ordersResponse.Errors[0]; - _logger.LogError("Error in listing all certificate orders"); - throw new Exception($"DigiCert CertCentral web service returned {error.code} - {error.message} when retrieving all rows"); - } - else - { - allOrders.AddRange(ordersResponse.orders); - } + allOrders.AddRange(ordersResponse.orders); } + + _logger.LogDebug($"SYNC: Found {allOrders.Count} records"); foreach (var orderDetails in allOrders) { @@ -897,7 +892,7 @@ public async Task Synchronize(BlockingCollection blockin cancelToken.ThrowIfCancellationRequested(); string caReqId = orderDetails.id + "-" + orderDetails.certificate.id; _logger.LogDebug($"SYNC: Retrieving certs for order id {orderDetails.id}"); - orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters); + orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters, productFilters); if (orderCerts == null || orderCerts.Count == 0) { continue; @@ -939,7 +934,7 @@ public async Task Synchronize(BlockingCollection blockin { cancelToken.ThrowIfCancellationRequested(); string caReqId = order.order_id + "-" + order.certificate_id; - orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters); + orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters, productFilters); if (orderCerts == null || orderCerts.Count > 0) { continue; @@ -1639,7 +1634,7 @@ string FormatSyncDate(DateTime? syncTime) /// /// /// - private List GetAllConnectorCertsForOrder(string caRequestID, List caFilterIds, List divIds) + private List GetAllConnectorCertsForOrder(string caRequestID, List caFilterIds, List divIds, List productIds) { _logger.MethodEntry(LogLevel.Trace); // Split ca request id into order and cert id @@ -1662,6 +1657,10 @@ private List GetAllConnectorCertsForOrder(string caReque _logger.LogTrace($"Found order ID {orderId} that does not match Division filter. Division ID: {orderResponse.container.Id.ToString()} Skipping..."); return null; } + if (productIds != null && productIds.Count > 0 && !productIds.Contains(orderResponse.product.name_id.ToString())) + { + _logger.LogTrace($"Found order ID {orderId} that does not match Product filter. Product ID: {orderResponse.product.name_id.ToString()} Skipping..."); + } var orderCerts = GetAllCertsForOrder(orderId); diff --git a/digicert-certcentral-caplugin/CertCentralConfig.cs b/digicert-certcentral-caplugin/CertCentralConfig.cs index fa3b354..6909c2e 100644 --- a/digicert-certcentral-caplugin/CertCentralConfig.cs +++ b/digicert-certcentral-caplugin/CertCentralConfig.cs @@ -33,6 +33,21 @@ public List SyncCAs } } } + public string SyncProductFilter { get; set; } + public List SyncProducts + { + get + { + if (!string.IsNullOrEmpty(SyncProductFilter)) + { + return SyncProductFilter.Split(",").ToList(); + } + else + { + return new List(); + } + } + } public bool? FilterExpiredOrders { get; set; } public int? SyncExpirationDays { get; set; } diff --git a/digicert-certcentral-caplugin/Client/CertCentralClient.cs b/digicert-certcentral-caplugin/Client/CertCentralClient.cs index fd9af77..753f54f 100644 --- a/digicert-certcentral-caplugin/Client/CertCentralClient.cs +++ b/digicert-certcentral-caplugin/Client/CertCentralClient.cs @@ -523,7 +523,7 @@ public DownloadCertificateByFormatResponse DownloadCertificateByFormat(DownloadC return dlCertificateRequestResponse; } - public ListCertificateOrdersResponse ListAllCertificateOrders(bool ignoreExpired = false, int expiredWindow = 0, string divId = "") + public ListCertificateOrdersResponse ListAllCertificateOrders(bool ignoreExpired, int expiredWindow, List divIds, List productIds) { int batch = 1000; ListCertificateOrdersResponse totalResponse = new ListCertificateOrdersResponse(); @@ -536,7 +536,8 @@ public ListCertificateOrdersResponse ListAllCertificateOrders(bool ignoreExpired offset = totalResponse.orders.Count, ignoreExpired = ignoreExpired, expiredWindow = expiredWindow, - divID = divId + divIDs = divIds, + productIDs = productIds }; CertCentralResponse response = Request(request, request.BuildParameters()); diff --git a/digicert-certcentral-caplugin/Constants.cs b/digicert-certcentral-caplugin/Constants.cs index 183a7cd..19fe860 100644 --- a/digicert-certcentral-caplugin/Constants.cs +++ b/digicert-certcentral-caplugin/Constants.cs @@ -30,6 +30,7 @@ public class Config public const string ENABLED = "Enabled"; public const string SYNC_CA_FILTER = "SyncCAFilter"; public const string SYNC_DIV_FILTER = "SyncDivisionFilter"; + public const string SYNC_PROD_FILTER = "SyncProductFilter"; public const string FILTER_EXPIRED = "FilterExpiredOrders"; public const string SYNC_EXPIRATION_DAYS = "SyncExpirationDays"; public const string CERT_TYPE = "CertType"; From babebc35eeb27e2d87ae561aae2b0056c23af018 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Tue, 30 Jun 2026 17:48:47 +0000 Subject: [PATCH 2/2] Update generated docs --- README.md | 1 + integration-manifest.json | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 6929905..4918513 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ An API Key within your Digicert account that has the necessary permissions to en * **RevokeCertificateOnly** - Default DigiCert behavior on revocation requests is to revoke the entire order. If this value is changed to 'true', revocation requests will instead just revoke the individual certificate. * **SyncCAFilter** - If you list one or more CA IDs here (comma-separated), the sync process will only sync records from those CAs. If you want to sync all CA IDs, leave this field empty. * **SyncDivisionFilter** - If you list one or more Divison IDs (also known as Container IDs) here (comma-separated), the sync process will filter records to only return orders from those divisions. If you want to sync all divisions, leave this field empty. Note that this has no relationship to the value of the DivisionId config field. + * **SyncProductFilter** - If you list one or more Product IDs here (comma-separated), the sync process will filter records to only return orders of those product types. Leave empty to sync all products. * **FilterExpiredOrders** - If set to 'true', syncing will apply a filter to not return orders that are expired for longer than specified in SyncExpirationDays. * **SyncExpirationDays** - If FilterExpiredOrders is set to true, this setting determines how many days in the past to still return expired orders. For example, a value of 30 means the sync will return any certs that expired within the past 30 days. A value of 0 means the sync will not return any certs that expired before the current day. This value is ignored if FilterExpiredOrders is false. * **Enabled** - Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available. diff --git a/integration-manifest.json b/integration-manifest.json index a854d2f..8cad8e9 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -38,6 +38,10 @@ "name": "SyncDivisionFilter", "description": "If you list one or more Divison IDs (also known as Container IDs) here (comma-separated), the sync process will filter records to only return orders from those divisions. If you want to sync all divisions, leave this field empty. Note that this has no relationship to the value of the DivisionId config field." }, + { + "name": "SyncProductFilter", + "description": "If you list one or more Product IDs here (comma-separated), the sync process will filter records to only return orders of those product types. Leave empty to sync all products." + }, { "name": "FilterExpiredOrders", "description": "If set to 'true', syncing will apply a filter to not return orders that are expired for longer than specified in SyncExpirationDays."