From fbbcca38cf5e5aed96b2f8e854a4c6f698833a70 Mon Sep 17 00:00:00 2001 From: jonxir <55785643+jonxir@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:14:03 +0100 Subject: [PATCH] Solved Issue by checking existent SSL certificates on site creation (#477) --- incapsula/client.go | 18 +++++++++++++- incapsula/client_site.go | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/incapsula/client.go b/incapsula/client.go index 610d3725..b8638e46 100644 --- a/incapsula/client.go +++ b/incapsula/client.go @@ -118,6 +118,20 @@ func (c *Client) PostFormWithHeaders(url string, data url.Values, operation stri return c.executeRequest(req) } +func (c *Client) GetWithHeaders(url string, queryParams url.Values, operation string) (*http.Response, error) { + reqURL := url + if len(queryParams) > 0 { + reqURL = fmt.Sprintf("%s?%s", url, queryParams.Encode()) + } + req, err := http.NewRequest(http.MethodGet, reqURL, nil) + if err != nil { + return nil, fmt.Errorf("Error preparing request: %s", err) + } + + SetHeaders(c, req, contentTypeApplicationJson, operation, nil) + return c.executeRequest(req) +} + func (c *Client) DoJsonRequestWithCustomHeaders(method string, url string, data []byte, headers map[string]string, operation string) (*http.Response, error) { req, err := PrepareJsonRequest(method, url, data) if err != nil { @@ -179,7 +193,9 @@ func PrepareJsonRequest(method string, url string, data []byte) (*http.Request, } func SetHeaders(c *Client, req *http.Request, contentType string, operation string, customHeaders map[string]string) { - req.Header.Set("Content-Type", contentType) + if req.Method != http.MethodGet { + req.Header.Set("Content-Type", contentType) + } req.Header.Set("x-api-id", c.config.APIID) req.Header.Set("x-api-key", c.config.APIKey) req.Header.Set("x-tf-provider-ver", c.providerVersion) diff --git a/incapsula/client_site.go b/incapsula/client_site.go index e9edeb57..dabb5afa 100644 --- a/incapsula/client_site.go +++ b/incapsula/client_site.go @@ -13,6 +13,7 @@ const endpointSiteAdd = "sites/add" const endpointSiteStatus = "sites/status" const endpointSiteUpdate = "sites/configure" const endpointSiteDelete = "sites/delete" +const endpointCertDetails = "certificates-ui/v3/certificates" // SiteAddResponse contains the relevant site information when adding an Incapsula managed site type SiteAddResponse struct { @@ -210,6 +211,21 @@ type SiteStatusResponse struct { } `json:"debug_info"` } +// SAN contains the relevant status information when parsing the SANs +type SAN struct { + Status string `json:"status"` +} + +// DataItem contains the relevant SAN information when parsing the data +type DataItem struct { + Sans []SAN `json:"sans"` +} + +// Response contains the relevant data from the response when checking for SSL certificates +type Response struct { + Data []DataItem `json:"data"` +} + // AddSite adds a site to be managed by Incapsula func (c *Client) AddSite(domain, refID, sendSiteSetupEmails, siteIP, forceSSL string, accountID int, nakedDomainSan bool, wildcarSan bool, logsAccountId string) (*SiteAddResponse, error) { log.Printf("[INFO] Adding Incapsula site for domain: %s (account ID %d)\n", domain, accountID) @@ -331,6 +347,42 @@ func (c *Client) UpdateSite(siteID, param, value string) (*SiteUpdateResponse, e // Look at the response status code from Incapsula if siteUpdateResponse.Res != 0 { + if siteUpdateResponse.Res == 1 && param == "domain_validation" { // Domain Validation parameter can throw code 1 when reusing wildcard certificate + //Get request for SSL certificate check on site + reqURL := fmt.Sprintf("%s/%s", c.config.BaseURLAPI, endpointCertDetails) + queryParams := url.Values{} + queryParams.Add("extSiteId", siteID) + + resp, err := c.GetWithHeaders(reqURL, queryParams, UpdateSite) + + if err != nil { + return nil, fmt.Errorf("Error checking certificate on site_id: %s: %s", siteID, err) + } + + // Read the body + defer resp.Body.Close() + responseBody, err := ioutil.ReadAll(resp.Body) + + // Dump JSON + log.Printf("[DEBUG] Incapsula check certificate JSON response: %s\n", string(responseBody)) + + // Parse the JSON + var response Response + err = json.Unmarshal([]byte(responseBody), &response) + if err != nil { + return nil, fmt.Errorf("Error parsing check certificate JSON response for siteID %s: %s", siteID, err) + } + + // Check all SANs to verify if there's an active certificate already + for _, dataItem := range response.Data { + for _, san := range dataItem.Sans { + if san.Status != "PENDING_USER_ACTION" { + // There's an active certificate, avoiding internal error + return &siteUpdateResponse, nil + } + } + } + } return nil, fmt.Errorf("Error from Incapsula service when updating site for siteID %s: %s", siteID, string(responseBody)) }