From 02e5fb196c4f2a4d1ae65a8da93e7ea8734744e2 Mon Sep 17 00:00:00 2001 From: vasil Date: Tue, 20 Dec 2022 20:43:30 -0600 Subject: [PATCH 1/5] add support for mtls certificates --- mtls_certificates.go | 135 ++++++++++++++++++++++ mtls_certificates_test.go | 236 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 mtls_certificates.go create mode 100644 mtls_certificates_test.go diff --git a/mtls_certificates.go b/mtls_certificates.go new file mode 100644 index 00000000000..fb264c6ebc1 --- /dev/null +++ b/mtls_certificates.go @@ -0,0 +1,135 @@ +package cloudflare + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" +) + +// MTLSAssociationDetails represents the metadata for an existing association between a user-uploaded mTLS certificate and a Cloudflare service. +type MTLSAssociationDetails struct { + Service string `json:"service"` + Status string `json:"status"` +} + +// MTLSAssociationResponse represents the response from the retrieval endpoint for mTLS certificate associations. +type MTLSAssociationResponse struct { + Response + Result []MTLSAssociationDetails `json:"result"` +} + +// MTLSCertificateDetails represents the metadata for a user-uploaded mTLS certificate. +type MTLSCertificateDetails struct { + ID string `json:"id"` + Name string `json:"name"` + Issuer string `json:"issuer"` + Signature string `json:"signature"` + SerialNumber string `json:"serial_number"` + Certificates string `json:"certificates"` + CA bool `json:"ca"` + UploadedOn time.Time `json:"uploaded_on"` + UpdatedAt time.Time `json:"updated_at"` + ExpiresOn time.Time `json:"expires_on"` +} + +// MTLSCertificateResponse represents the response from endpoints relating to retrieving, creating, and deleting an mTLS certificate. +type MTLSCertificateResponse struct { + Response + Result MTLSCertificateDetails `json:"result"` +} + +// MTLSCertificatesResponse represents the response from the mTLS certificate list endpoint. +type MTLSCertificatesResponse struct { + Response + Result []MTLSCertificateDetails `json:"result"` +} + +// MTLSCertificateParams represents the data related to the mTLS certificate being uploaded. Name is an optional field. +type MTLSCertificateParams struct { + Name string `json:"name"` + Certificates string `json:"certificates"` + PrivateKey string `json:"private_key"` + CA bool `json:"ca"` +} + +// ListMTLSCertificates returns a list of all user-uploaded mTLS certificates. +// +// API reference: https://api.cloudflare.com/#mtls-certificate-management-list-mtls-certificates +func (api *API) ListMTLSCertificates(ctx context.Context, accountID string) ([]MTLSCertificateDetails, error) { + uri := fmt.Sprintf("/accounts/%s/mtls_certificates", accountID) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return []MTLSCertificateDetails{}, err + } + var r MTLSCertificatesResponse + if err := json.Unmarshal(res, &r); err != nil { + return []MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r.Result, nil +} + +// GetMTLSCertificateDetails returns the metadata associated with a user-uploaded mTLS certificate. +// +// API reference: https://api.cloudflare.com/#mtls-certificate-management-get-mtls-certificate +func (api *API) GetMTLSCertificateDetails(ctx context.Context, accountID, certificateID string) (MTLSCertificateDetails, error) { + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", accountID, certificateID) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return MTLSCertificateDetails{}, err + } + var r MTLSCertificateResponse + if err := json.Unmarshal(res, &r); err != nil { + return MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r.Result, nil +} + +// ListMTLSCertificateAssociations returns a list of all existing associations between the mTLS certificate and Cloudflare services. +// +// API reference: https://api.cloudflare.com/#mtls-certificate-management-list-mtls-certificate-associations +func (api *API) ListMTLSCertificateAssociations(ctx context.Context, accountID, certificateID string) ([]MTLSAssociationDetails, error) { + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s/associations", accountID, certificateID) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return []MTLSAssociationDetails{}, err + } + var r MTLSAssociationResponse + if err := json.Unmarshal(res, &r); err != nil { + return []MTLSAssociationDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r.Result, nil +} + +// UploadMTLSCertificate will upload the provided certificate for use with mTLS enabled Cloudflare services. +// +// API reference: https://api.cloudflare.com/#mtls-certificate-management-upload-mtls-certificate +func (api *API) UploadMTLSCertificate(ctx context.Context, accountID string, params MTLSCertificateParams) (MTLSCertificateDetails, error) { + uri := fmt.Sprintf("/accounts/%s/mtls_certificates", accountID) + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) + if err != nil { + return MTLSCertificateDetails{}, err + } + var r MTLSCertificateResponse + if err := json.Unmarshal(res, &r); err != nil { + return MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r.Result, nil +} + +// DeleteMTLSCertificate will delete the specified mTLS certificate. +// +// API reference: https://api.cloudflare.com/#mtls-certificate-management-delete-mtls-certificate +func (api *API) DeleteMTLSCertificate(ctx context.Context, accountID, certificateID string) (MTLSCertificateDetails, error) { + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", accountID, certificateID) + res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) + if err != nil { + return MTLSCertificateDetails{}, err + } + var r MTLSCertificateResponse + if err := json.Unmarshal(res, &r); err != nil { + return MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r.Result, nil +} diff --git a/mtls_certificates_test.go b/mtls_certificates_test.go new file mode 100644 index 00000000000..390e37cb0bd --- /dev/null +++ b/mtls_certificates_test.go @@ -0,0 +1,236 @@ +package cloudflare + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestGetMTLSCertificate(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + "name": "example_ca_cert_5", + "issuer": "O=Example Inc.,L=California,ST=San Francisco,C=US", + "signature": "SHA256WithRSA", + "serial_number": "235217144297995885180570755458463043449861756659", + "certificates": "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + "ca": true, + "uploaded_on": "2022-11-22T17:32:30.467938Z", + "expires_on": "2122-10-29T16:59:47Z" + } + }`) + } + + mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates/2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", handler) + expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") + uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") + want := MTLSCertificateDetails{ + ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + Name: "example_ca_cert_5", + Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", + Signature: "SHA256WithRSA", + SerialNumber: "235217144297995885180570755458463043449861756659", + Certificates: "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + CA: true, + UploadedOn: uploadedOn, + ExpiresOn: expiresOn, + } + + actual, err := client.GetMTLSCertificateDetails(context.Background(), "01a7362d577a6c3019a474fd6f485823", "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestListMTLSCertificates(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": [ + { + "id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + "name": "example_ca_cert_5", + "issuer": "O=Example Inc.,L=California,ST=San Francisco,C=US", + "signature": "SHA256WithRSA", + "serial_number": "235217144297995885180570755458463043449861756659", + "certificates": "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + "ca": true, + "uploaded_on": "2022-11-22T17:32:30.467938Z", + "expires_on": "2122-10-29T16:59:47Z" + } + ] + }`) + } + + mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates", handler) + expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") + uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") + want := []MTLSCertificateDetails{ + { + ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + Name: "example_ca_cert_5", + Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", + Signature: "SHA256WithRSA", + SerialNumber: "235217144297995885180570755458463043449861756659", + Certificates: "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + CA: true, + UploadedOn: uploadedOn, + ExpiresOn: expiresOn, + }, + } + + actual, err := client.ListMTLSCertificates(context.Background(), "01a7362d577a6c3019a474fd6f485823") + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestListCertificateAssociations(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": [ + { + "service": "gateway", + "status": "pending_deployment" + } + ] + }`) + } + + mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates/2458ce5a-0c35-4c7f-82c7-8e9487d3ff60/associations", handler) + want := []MTLSAssociationDetails{ + { + Service: "gateway", + Status: "pending_deployment", + }, + } + + actual, err := client.ListMTLSCertificateAssociations(context.Background(), "01a7362d577a6c3019a474fd6f485823", "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestUploadMTLSCertificate(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + "name": "example_ca_cert_5", + "issuer": "O=Example Inc.,L=California,ST=San Francisco,C=US", + "signature": "SHA256WithRSA", + "serial_number": "235217144297995885180570755458463043449861756659", + "certificates": "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + "ca": true, + "uploaded_on": "2022-11-22T17:32:30.467938Z", + "updated_at": "2022-11-22T17:32:30.467938Z", + "expires_on": "2122-10-29T16:59:47Z" + } + }`) + } + + mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates", handler) + expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") + uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") + want := MTLSCertificateDetails{ + ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + Name: "example_ca_cert_5", + Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", + Signature: "SHA256WithRSA", + SerialNumber: "235217144297995885180570755458463043449861756659", + Certificates: "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + CA: true, + UploadedOn: uploadedOn, + UpdatedAt: uploadedOn, + ExpiresOn: expiresOn, + } + + cert := MTLSCertificateParams{ + Name: "example_ca_cert_5", + Certificates: "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEXDkcICRU3XBv9hiiPnBWIjgTQyowmVFxDr11mONgZB/cMYjE/OvQjvnpwNcOaSK16MOpAjNbELKRx2lZiVJaLRDCccqCxXwP/CrdRChcqGzo7mbNksMlcidrErb0LlEBKLFC2QjRmRKqB+YOs4TD8WsZu2S667A2fZmjRlaqOxFi1h62ee0P+TLU628UC/nl41JifSt5Evt7hMDHakemdwZblNYr2p6T3NQjdhjYXTtP4UmOGJBhJ7i7Kicg3d3CIgdTMbggSeGWqjndr4ldVnD96FN3cVT5uDFsn2CJXTFgdeBWoUnMS4VnUZzPWGf4vSBXC8qV7Ls+w46yT7T1AgMBAAECggEAQZnp/oqCeNPOR6l5S2L+1tfx0gWjZ78hJVteUpZ0iHSK7F6kKeOxyOird7vUXV0kmo+cJq+0hp0Ke4eam640FCpwKfYoSQ4/R3vgujGWJnaihCN5tv5sMet0XeJPuz5qE7ALoKCvwI6aXLHs20aAeZIDTQJ9QbGSGnJVzOWn+JDTidIgZpN57RpXfSAwnJPTQK/PN8i5z108hsaDOdEgGmxYZ7kYqMqzX20KXmth58LDfPixs5JGtS60iiKC/wOcGzkB2/AdTSojR76oEU77cANP/3zO25NG//whUdYlW0t0d7PgXxIeJe+xgYnamDQJx3qonVyt4H77ha0ObRAj9QKBgQDicZr+VTwFMnELP3a+FXGnjehRiuS1i7MXGKxNweCD+dFlML0FplSQS8Ro2n+d8lu8BBXGx0qm6VXu8Rhn7TAUL6q+PCgfarzxfIhacb/TZCqfieIHsMlVBfhV5HCXnk+kis0tuC/PRArcWTwDHJUJXkBhvkUsNswvQzavDPI7KwKBgQDd/WgLkj7A3X5fgIHZH/GbDSBiXwzKb+rF4ZCT2XFgG/OAW7vapfcX/w+v+5lBLyrocmOAS3PGGAhM5T3HLnUCQfnK4qgps1Lqibkc9Tmnsn60LanUjuUMsYv/zSw70tozbzhJ0pioEpWfRxRZBztO2Rr8Ntm7h6Fk701EXGNAXwKBgQCD1xsjy2J3sCerIdcz0u5qXLAPkeuZW+34m4/ucdwTWwc0gEz9lhsULFj9p4G351zLuiEnq+7mAWLcDJlmIO3mQt6JhiLiL9Y0T4pgBmxmWqKKYtAsJB0EmMY+1BNN44mBRqMxZFTJu1cLdhT/xstrOeoIPqytknYNanfTMZlzIwKBgHrLXe5oq0XMP8dcMneEcAUwsaU4pr6kQd3L9EmUkl5zl7J9C+DaxWAEuwzBw/iGutlxzRB+rD/7szu14wJ29EqXbDGKRzMp+se5/yfBjm7xEZ1hVPw7PwBShfqt57X/4Ktq7lwHnmH6RcGhc+P7WBc5iO/S94YAdIp8xOT3pf9JAoGAE0QkqJUY+5Mgr+fBO0VNV72ZoPveGpW+De59uhKAOnu1zljQCUtk59m6+DXfm0tNYKtawa5n8iN71Zh+s62xXSt3pYi1Y5CCCmv8Y4BhwIcPwXKk3zEvLgSHVTpC0bayA9aSO4bbZgVXa5w+Z0w/vvfp9DWo1IS3EnQRrz6WMYA=\n-----END PRIVATE KEY-----", + CA: true, + } + actual, err := client.UploadMTLSCertificate(context.Background(), "01a7362d577a6c3019a474fd6f485823", cert) + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestDeleteMTLSCertificate(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + "name": "example_ca_cert_5", + "issuer": "O=Example Inc.,L=California,ST=San Francisco,C=US", + "signature": "SHA256WithRSA", + "serial_number": "235217144297995885180570755458463043449861756659", + "certificates": "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + "ca": true, + "uploaded_on": "2022-11-22T17:32:30.467938Z", + "expires_on": "2122-10-29T16:59:47Z" + } + }`) + } + + mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates/2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", handler) + expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") + uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") + want := MTLSCertificateDetails{ + ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + Name: "example_ca_cert_5", + Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", + Signature: "SHA256WithRSA", + SerialNumber: "235217144297995885180570755458463043449861756659", + Certificates: "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", + CA: true, + UploadedOn: uploadedOn, + ExpiresOn: expiresOn, + } + + actual, err := client.DeleteMTLSCertificate(context.Background(), "01a7362d577a6c3019a474fd6f485823", "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} From 54b0448e0d939a676e855afe9b0c1813f519be45 Mon Sep 17 00:00:00 2001 From: vasil Date: Wed, 21 Dec 2022 13:24:51 -0600 Subject: [PATCH 2/5] add mTLS certificate store to list of supported features in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 311bea03d7e..988d1a3cace 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ The current feature list includes: - [x] [Load Balancing](https://blog.cloudflare.com/introducing-load-balancing-intelligent-failover-with-cloudflare/) - [x] [Logpush Jobs](https://developers.cloudflare.com/logs/logpush/) - [x] Magic Transit / Magic WAN +- [x] mTLS Certificate Store - [x] Notifications - [ ] Organization Administration - [x] [Origin CA](https://blog.cloudflare.com/universal-ssl-encryption-all-the-way-to-the-origin-for-free/) From 06a1da1ecbd3f28fa5cf04403708c4685dba6e08 Mon Sep 17 00:00:00 2001 From: vasil Date: Thu, 22 Dec 2022 09:39:17 -0600 Subject: [PATCH 3/5] updated function signatures and added input validation --- mtls_certificates.go | 89 +++++++++++++++++++++++++++++++-------- mtls_certificates_test.go | 21 ++++++--- 2 files changed, 86 insertions(+), 24 deletions(-) diff --git a/mtls_certificates.go b/mtls_certificates.go index fb264c6ebc1..ca20eb75f92 100644 --- a/mtls_certificates.go +++ b/mtls_certificates.go @@ -3,6 +3,7 @@ package cloudflare import ( "context" "encoding/json" + "errors" "fmt" "net/http" "time" @@ -43,38 +44,67 @@ type MTLSCertificateResponse struct { // MTLSCertificatesResponse represents the response from the mTLS certificate list endpoint. type MTLSCertificatesResponse struct { Response - Result []MTLSCertificateDetails `json:"result"` + Result []MTLSCertificateDetails `json:"result"` + ResultInfo `json:"result_info"` } // MTLSCertificateParams represents the data related to the mTLS certificate being uploaded. Name is an optional field. -type MTLSCertificateParams struct { +type CreateMTLSCertificateParams struct { Name string `json:"name"` Certificates string `json:"certificates"` PrivateKey string `json:"private_key"` CA bool `json:"ca"` } +type ListMTLSCertificatesParams struct { + PaginationOptions + Limit int `url:"limit,omitempty"` + Offset int `url:"offset,omitempty"` + Name string `url:"name,omitempty"` + CA bool `url:"ca,omitempty"` +} + +var ( + ErrMissingCertificateID = errors.New("missing required certificate ID") +) + // ListMTLSCertificates returns a list of all user-uploaded mTLS certificates. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-list-mtls-certificates -func (api *API) ListMTLSCertificates(ctx context.Context, accountID string) ([]MTLSCertificateDetails, error) { - uri := fmt.Sprintf("/accounts/%s/mtls_certificates", accountID) - res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) +func (api *API) ListMTLSCertificates(ctx context.Context, rc *ResourceContainer, params ListMTLSCertificatesParams) ([]MTLSCertificateDetails, ResultInfo, error) { + switch { + case rc.Level != AccountRouteLevel: + return []MTLSCertificateDetails{}, ResultInfo{}, ErrRequiredAccountLevelResourceContainer + case rc.Identifier == "": + return []MTLSCertificateDetails{}, ResultInfo{}, ErrMissingAccountID + } + + uri := fmt.Sprintf("/accounts/%s/mtls_certificates", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, params) if err != nil { - return []MTLSCertificateDetails{}, err + return []MTLSCertificateDetails{}, ResultInfo{}, err } var r MTLSCertificatesResponse if err := json.Unmarshal(res, &r); err != nil { - return []MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return []MTLSCertificateDetails{}, ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } - return r.Result, nil + return r.Result, r.ResultInfo, err } // GetMTLSCertificateDetails returns the metadata associated with a user-uploaded mTLS certificate. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-get-mtls-certificate -func (api *API) GetMTLSCertificateDetails(ctx context.Context, accountID, certificateID string) (MTLSCertificateDetails, error) { - uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", accountID, certificateID) +func (api *API) GetMTLSCertificateDetails(ctx context.Context, rc *ResourceContainer, certificateID string) (MTLSCertificateDetails, error) { + switch { + case rc.Level != AccountRouteLevel: + return MTLSCertificateDetails{}, ErrRequiredAccountLevelResourceContainer + case rc.Identifier == "": + return MTLSCertificateDetails{}, ErrMissingAccountID + case certificateID == "": + return MTLSCertificateDetails{}, ErrMissingCertificateID + } + + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", rc.Identifier, certificateID) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return MTLSCertificateDetails{}, err @@ -89,8 +119,17 @@ func (api *API) GetMTLSCertificateDetails(ctx context.Context, accountID, certif // ListMTLSCertificateAssociations returns a list of all existing associations between the mTLS certificate and Cloudflare services. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-list-mtls-certificate-associations -func (api *API) ListMTLSCertificateAssociations(ctx context.Context, accountID, certificateID string) ([]MTLSAssociationDetails, error) { - uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s/associations", accountID, certificateID) +func (api *API) ListMTLSCertificateAssociations(ctx context.Context, rc *ResourceContainer, certificateID string) ([]MTLSAssociationDetails, error) { + switch { + case rc.Level != AccountRouteLevel: + return []MTLSAssociationDetails{}, ErrRequiredAccountLevelResourceContainer + case rc.Identifier == "": + return []MTLSAssociationDetails{}, ErrMissingAccountID + case certificateID == "": + return []MTLSAssociationDetails{}, ErrMissingCertificateID + } + + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s/associations", rc.Identifier, certificateID) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return []MTLSAssociationDetails{}, err @@ -102,11 +141,18 @@ func (api *API) ListMTLSCertificateAssociations(ctx context.Context, accountID, return r.Result, nil } -// UploadMTLSCertificate will upload the provided certificate for use with mTLS enabled Cloudflare services. +// CreateMTLSCertificate will create the provided certificate for use with mTLS enabled Cloudflare services. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-upload-mtls-certificate -func (api *API) UploadMTLSCertificate(ctx context.Context, accountID string, params MTLSCertificateParams) (MTLSCertificateDetails, error) { - uri := fmt.Sprintf("/accounts/%s/mtls_certificates", accountID) +func (api *API) CreateMTLSCertificate(ctx context.Context, rc *ResourceContainer, params CreateMTLSCertificateParams) (MTLSCertificateDetails, error) { + switch { + case rc.Level != AccountRouteLevel: + return MTLSCertificateDetails{}, ErrRequiredAccountLevelResourceContainer + case rc.Identifier == "": + return MTLSCertificateDetails{}, ErrMissingAccountID + } + + uri := fmt.Sprintf("/accounts/%s/mtls_certificates", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) if err != nil { return MTLSCertificateDetails{}, err @@ -121,8 +167,17 @@ func (api *API) UploadMTLSCertificate(ctx context.Context, accountID string, par // DeleteMTLSCertificate will delete the specified mTLS certificate. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-delete-mtls-certificate -func (api *API) DeleteMTLSCertificate(ctx context.Context, accountID, certificateID string) (MTLSCertificateDetails, error) { - uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", accountID, certificateID) +func (api *API) DeleteMTLSCertificate(ctx context.Context, rc *ResourceContainer, certificateID string) (MTLSCertificateDetails, error) { + switch { + case rc.Level != AccountRouteLevel: + return MTLSCertificateDetails{}, ErrRequiredAccountLevelResourceContainer + case rc.Identifier == "": + return MTLSCertificateDetails{}, ErrMissingAccountID + case certificateID == "": + return MTLSCertificateDetails{}, ErrMissingCertificateID + } + + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", rc.Identifier, certificateID) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) if err != nil { return MTLSCertificateDetails{}, err diff --git a/mtls_certificates_test.go b/mtls_certificates_test.go index 390e37cb0bd..30156d0ef43 100644 --- a/mtls_certificates_test.go +++ b/mtls_certificates_test.go @@ -49,7 +49,7 @@ func TestGetMTLSCertificate(t *testing.T) { ExpiresOn: expiresOn, } - actual, err := client.GetMTLSCertificateDetails(context.Background(), "01a7362d577a6c3019a474fd6f485823", "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + actual, err := client.GetMTLSCertificateDetails(context.Background(), AccountIdentifier(testAccountID), "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") if assert.NoError(t, err) { assert.Equal(t, want, actual) } @@ -77,7 +77,14 @@ func TestListMTLSCertificates(t *testing.T) { "uploaded_on": "2022-11-22T17:32:30.467938Z", "expires_on": "2122-10-29T16:59:47Z" } - ] + ], + "result_info": { + "page": 1, + "per_page": 50, + "count": 1, + "total_count": 1, + "total_pages": 1 + } }`) } @@ -98,7 +105,7 @@ func TestListMTLSCertificates(t *testing.T) { }, } - actual, err := client.ListMTLSCertificates(context.Background(), "01a7362d577a6c3019a474fd6f485823") + actual, _, err := client.ListMTLSCertificates(context.Background(), AccountIdentifier(testAccountID), ListMTLSCertificatesParams{}) if assert.NoError(t, err) { assert.Equal(t, want, actual) } @@ -131,7 +138,7 @@ func TestListCertificateAssociations(t *testing.T) { }, } - actual, err := client.ListMTLSCertificateAssociations(context.Background(), "01a7362d577a6c3019a474fd6f485823", "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + actual, err := client.ListMTLSCertificateAssociations(context.Background(), AccountIdentifier(testAccountID), "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") if assert.NoError(t, err) { assert.Equal(t, want, actual) } @@ -178,13 +185,13 @@ func TestUploadMTLSCertificate(t *testing.T) { ExpiresOn: expiresOn, } - cert := MTLSCertificateParams{ + cert := CreateMTLSCertificateParams{ Name: "example_ca_cert_5", Certificates: "-----BEGIN CERTIFICATE-----\nMIIDmDCCAoCgAwIBAgIUKTOAZNjcXVZRj4oQt0SHsl1c1vMwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjAgFw0yMjExMjIxNjU5NDdaGA8yMTIyMTAyOTE2NTk0N1owUTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDVNhbiBGcmFuY2lzY28xEzARBgNVBAcMCkNhbGlmb3JuaWExFTATBgNVBAoMDEV4YW1wbGUgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRcORwgJFTdcG/2GKI+cFYiOBNDKjCZUXEOvXWY42BkH9wxiMT869CO+enA1w5pIrXow6kCM1sQspHHaVmJUlotEMJxyoLFfA/8Kt1EKFyobOjuZs2SwyVyJ2sStvQuUQEosULZCNGZEqoH5g6zhMPxaxm7ZLrrsDZ9maNGVqo7EWLWHrZ57Q/5MtTrbxQL+eXjUmJ9K3kS+3uEwMdqR6Z3BluU1ivanpPc1CN2GNhdO0/hSY4YkGEnuLsqJyDd3cIiB1MxuCBJ4ZaqOd2viV1WcP3oU3dxVPm4MWyfYIldMWB14FahScxLhWdRnM9YZ/i9IFcLypXsuz7DjrJPtPUCAwEAAaNmMGQwHQYDVR0OBBYEFP5JzLUawNF+c3AXsYTEWHh7z2czMB8GA1UdIwQYMBaAFP5JzLUawNF+c3AXsYTEWHh7z2czMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc+Be7NDhpE09y7hLPZGRPl1cSKBw4RI0XIv6rlbSTFs5EebpTGjhx/whNxwEZhB9HZ7111Oa1YlT8xkI9DshB78mjAHCKBAJ76moK8tkG0aqdYpJ4ZcJTVBB7l98Rvgc7zfTii7WemTy72deBbSeiEtXavm4EF0mWjHhQ5Nxpnp00Bqn5g1x8CyTDypgmugnep+xG+iFzNmTdsz7WI9T/7kDMXqB7M/FPWBORyS98OJqNDswCLF8bIZYwUBEe+bRHFomoShMzaC3tvim7WCb16noDkSTMlfKO4pnvKhpcVdSgwcruATV7y+W+Lvmz2OT/Gui4JhqeoTewsxndhDDE\n-----END CERTIFICATE-----", PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEXDkcICRU3XBv9hiiPnBWIjgTQyowmVFxDr11mONgZB/cMYjE/OvQjvnpwNcOaSK16MOpAjNbELKRx2lZiVJaLRDCccqCxXwP/CrdRChcqGzo7mbNksMlcidrErb0LlEBKLFC2QjRmRKqB+YOs4TD8WsZu2S667A2fZmjRlaqOxFi1h62ee0P+TLU628UC/nl41JifSt5Evt7hMDHakemdwZblNYr2p6T3NQjdhjYXTtP4UmOGJBhJ7i7Kicg3d3CIgdTMbggSeGWqjndr4ldVnD96FN3cVT5uDFsn2CJXTFgdeBWoUnMS4VnUZzPWGf4vSBXC8qV7Ls+w46yT7T1AgMBAAECggEAQZnp/oqCeNPOR6l5S2L+1tfx0gWjZ78hJVteUpZ0iHSK7F6kKeOxyOird7vUXV0kmo+cJq+0hp0Ke4eam640FCpwKfYoSQ4/R3vgujGWJnaihCN5tv5sMet0XeJPuz5qE7ALoKCvwI6aXLHs20aAeZIDTQJ9QbGSGnJVzOWn+JDTidIgZpN57RpXfSAwnJPTQK/PN8i5z108hsaDOdEgGmxYZ7kYqMqzX20KXmth58LDfPixs5JGtS60iiKC/wOcGzkB2/AdTSojR76oEU77cANP/3zO25NG//whUdYlW0t0d7PgXxIeJe+xgYnamDQJx3qonVyt4H77ha0ObRAj9QKBgQDicZr+VTwFMnELP3a+FXGnjehRiuS1i7MXGKxNweCD+dFlML0FplSQS8Ro2n+d8lu8BBXGx0qm6VXu8Rhn7TAUL6q+PCgfarzxfIhacb/TZCqfieIHsMlVBfhV5HCXnk+kis0tuC/PRArcWTwDHJUJXkBhvkUsNswvQzavDPI7KwKBgQDd/WgLkj7A3X5fgIHZH/GbDSBiXwzKb+rF4ZCT2XFgG/OAW7vapfcX/w+v+5lBLyrocmOAS3PGGAhM5T3HLnUCQfnK4qgps1Lqibkc9Tmnsn60LanUjuUMsYv/zSw70tozbzhJ0pioEpWfRxRZBztO2Rr8Ntm7h6Fk701EXGNAXwKBgQCD1xsjy2J3sCerIdcz0u5qXLAPkeuZW+34m4/ucdwTWwc0gEz9lhsULFj9p4G351zLuiEnq+7mAWLcDJlmIO3mQt6JhiLiL9Y0T4pgBmxmWqKKYtAsJB0EmMY+1BNN44mBRqMxZFTJu1cLdhT/xstrOeoIPqytknYNanfTMZlzIwKBgHrLXe5oq0XMP8dcMneEcAUwsaU4pr6kQd3L9EmUkl5zl7J9C+DaxWAEuwzBw/iGutlxzRB+rD/7szu14wJ29EqXbDGKRzMp+se5/yfBjm7xEZ1hVPw7PwBShfqt57X/4Ktq7lwHnmH6RcGhc+P7WBc5iO/S94YAdIp8xOT3pf9JAoGAE0QkqJUY+5Mgr+fBO0VNV72ZoPveGpW+De59uhKAOnu1zljQCUtk59m6+DXfm0tNYKtawa5n8iN71Zh+s62xXSt3pYi1Y5CCCmv8Y4BhwIcPwXKk3zEvLgSHVTpC0bayA9aSO4bbZgVXa5w+Z0w/vvfp9DWo1IS3EnQRrz6WMYA=\n-----END PRIVATE KEY-----", CA: true, } - actual, err := client.UploadMTLSCertificate(context.Background(), "01a7362d577a6c3019a474fd6f485823", cert) + actual, err := client.CreateMTLSCertificate(context.Background(), AccountIdentifier(testAccountID), cert) if assert.NoError(t, err) { assert.Equal(t, want, actual) } @@ -229,7 +236,7 @@ func TestDeleteMTLSCertificate(t *testing.T) { ExpiresOn: expiresOn, } - actual, err := client.DeleteMTLSCertificate(context.Background(), "01a7362d577a6c3019a474fd6f485823", "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + actual, err := client.DeleteMTLSCertificate(context.Background(), AccountIdentifier(testAccountID), "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") if assert.NoError(t, err) { assert.Equal(t, want, actual) } From 7467300bfbb395becc7df3f007b2e52e213abb2d Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 28 Dec 2022 13:05:03 +1100 Subject: [PATCH 4/5] mtls_certificate: update struct names --- mtls_certificates.go | 146 ++++++++++++++++++++++---------------- mtls_certificates_test.go | 16 +++-- 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/mtls_certificates.go b/mtls_certificates.go index ca20eb75f92..5d92bd2dd52 100644 --- a/mtls_certificates.go +++ b/mtls_certificates.go @@ -9,20 +9,23 @@ import ( "time" ) -// MTLSAssociationDetails represents the metadata for an existing association between a user-uploaded mTLS certificate and a Cloudflare service. -type MTLSAssociationDetails struct { +// MTLSAssociation represents the metadata for an existing association +// between a user-uploaded mTLS certificate and a Cloudflare service. +type MTLSAssociation struct { Service string `json:"service"` Status string `json:"status"` } -// MTLSAssociationResponse represents the response from the retrieval endpoint for mTLS certificate associations. +// MTLSAssociationResponse represents the response from the retrieval endpoint +// for mTLS certificate associations. type MTLSAssociationResponse struct { Response - Result []MTLSAssociationDetails `json:"result"` + Result []MTLSAssociation `json:"result"` } -// MTLSCertificateDetails represents the metadata for a user-uploaded mTLS certificate. -type MTLSCertificateDetails struct { +// MTLSCertificate represents the metadata for a user-uploaded mTLS +// certificate. +type MTLSCertificate struct { ID string `json:"id"` Name string `json:"name"` Issuer string `json:"issuer"` @@ -35,20 +38,23 @@ type MTLSCertificateDetails struct { ExpiresOn time.Time `json:"expires_on"` } -// MTLSCertificateResponse represents the response from endpoints relating to retrieving, creating, and deleting an mTLS certificate. +// MTLSCertificateResponse represents the response from endpoints relating to +// retrieving, creating, and deleting an mTLS certificate. type MTLSCertificateResponse struct { Response - Result MTLSCertificateDetails `json:"result"` + Result MTLSCertificate `json:"result"` } -// MTLSCertificatesResponse represents the response from the mTLS certificate list endpoint. +// MTLSCertificatesResponse represents the response from the mTLS certificate +// list endpoint. type MTLSCertificatesResponse struct { Response - Result []MTLSCertificateDetails `json:"result"` + Result []MTLSCertificate `json:"result"` ResultInfo `json:"result_info"` } -// MTLSCertificateParams represents the data related to the mTLS certificate being uploaded. Name is an optional field. +// MTLSCertificateParams represents the data related to the mTLS certificate +// being uploaded. Name is an optional field. type CreateMTLSCertificateParams struct { Name string `json:"name"` Certificates string `json:"certificates"` @@ -64,6 +70,10 @@ type ListMTLSCertificatesParams struct { CA bool `url:"ca,omitempty"` } +type ListMTLSCertificateAssociationsParams struct { + CertificateID string +} + var ( ErrMissingCertificateID = errors.New("missing required certificate ID") ) @@ -71,95 +81,106 @@ var ( // ListMTLSCertificates returns a list of all user-uploaded mTLS certificates. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-list-mtls-certificates -func (api *API) ListMTLSCertificates(ctx context.Context, rc *ResourceContainer, params ListMTLSCertificatesParams) ([]MTLSCertificateDetails, ResultInfo, error) { - switch { - case rc.Level != AccountRouteLevel: - return []MTLSCertificateDetails{}, ResultInfo{}, ErrRequiredAccountLevelResourceContainer - case rc.Identifier == "": - return []MTLSCertificateDetails{}, ResultInfo{}, ErrMissingAccountID +func (api *API) ListMTLSCertificates(ctx context.Context, rc *ResourceContainer, params ListMTLSCertificatesParams) ([]MTLSCertificate, ResultInfo, error) { + if rc.Level != AccountRouteLevel { + return []MTLSCertificate{}, ResultInfo{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return []MTLSCertificate{}, ResultInfo{}, ErrMissingAccountID } uri := fmt.Sprintf("/accounts/%s/mtls_certificates", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, params) if err != nil { - return []MTLSCertificateDetails{}, ResultInfo{}, err + return []MTLSCertificate{}, ResultInfo{}, err } var r MTLSCertificatesResponse if err := json.Unmarshal(res, &r); err != nil { - return []MTLSCertificateDetails{}, ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return []MTLSCertificate{}, ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } return r.Result, r.ResultInfo, err } -// GetMTLSCertificateDetails returns the metadata associated with a user-uploaded mTLS certificate. +// GetMTLSCertificate returns the metadata associated with a user-uploaded mTLS +// certificate. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-get-mtls-certificate -func (api *API) GetMTLSCertificateDetails(ctx context.Context, rc *ResourceContainer, certificateID string) (MTLSCertificateDetails, error) { - switch { - case rc.Level != AccountRouteLevel: - return MTLSCertificateDetails{}, ErrRequiredAccountLevelResourceContainer - case rc.Identifier == "": - return MTLSCertificateDetails{}, ErrMissingAccountID - case certificateID == "": - return MTLSCertificateDetails{}, ErrMissingCertificateID +func (api *API) GetMTLSCertificate(ctx context.Context, rc *ResourceContainer, certificateID string) (MTLSCertificate, error) { + if rc.Level != AccountRouteLevel { + return MTLSCertificate{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return MTLSCertificate{}, ErrMissingAccountID + } + + if certificateID == "" { + return MTLSCertificate{}, ErrMissingCertificateID } uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", rc.Identifier, certificateID) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { - return MTLSCertificateDetails{}, err + return MTLSCertificate{}, err } var r MTLSCertificateResponse if err := json.Unmarshal(res, &r); err != nil { - return MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return MTLSCertificate{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } return r.Result, nil } -// ListMTLSCertificateAssociations returns a list of all existing associations between the mTLS certificate and Cloudflare services. +// ListMTLSCertificateAssociations returns a list of all existing associations +// between the mTLS certificate and Cloudflare services. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-list-mtls-certificate-associations -func (api *API) ListMTLSCertificateAssociations(ctx context.Context, rc *ResourceContainer, certificateID string) ([]MTLSAssociationDetails, error) { - switch { - case rc.Level != AccountRouteLevel: - return []MTLSAssociationDetails{}, ErrRequiredAccountLevelResourceContainer - case rc.Identifier == "": - return []MTLSAssociationDetails{}, ErrMissingAccountID - case certificateID == "": - return []MTLSAssociationDetails{}, ErrMissingCertificateID +func (api *API) ListMTLSCertificateAssociations(ctx context.Context, rc *ResourceContainer, params ListMTLSCertificateAssociationsParams) ([]MTLSAssociation, error) { + if rc.Level != AccountRouteLevel { + return []MTLSAssociation{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return []MTLSAssociation{}, ErrMissingAccountID + } + + if params.CertificateID == "" { + return []MTLSAssociation{}, ErrMissingCertificateID } - uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s/associations", rc.Identifier, certificateID) + uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s/associations", rc.Identifier, params.CertificateID) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { - return []MTLSAssociationDetails{}, err + return []MTLSAssociation{}, err } var r MTLSAssociationResponse if err := json.Unmarshal(res, &r); err != nil { - return []MTLSAssociationDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return []MTLSAssociation{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } return r.Result, nil } -// CreateMTLSCertificate will create the provided certificate for use with mTLS enabled Cloudflare services. +// CreateMTLSCertificate will create the provided certificate for use with mTLS +// enabled Cloudflare services. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-upload-mtls-certificate -func (api *API) CreateMTLSCertificate(ctx context.Context, rc *ResourceContainer, params CreateMTLSCertificateParams) (MTLSCertificateDetails, error) { - switch { - case rc.Level != AccountRouteLevel: - return MTLSCertificateDetails{}, ErrRequiredAccountLevelResourceContainer - case rc.Identifier == "": - return MTLSCertificateDetails{}, ErrMissingAccountID +func (api *API) CreateMTLSCertificate(ctx context.Context, rc *ResourceContainer, params CreateMTLSCertificateParams) (MTLSCertificate, error) { + if rc.Level != AccountRouteLevel { + return MTLSCertificate{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return MTLSCertificate{}, ErrMissingAccountID } uri := fmt.Sprintf("/accounts/%s/mtls_certificates", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) if err != nil { - return MTLSCertificateDetails{}, err + return MTLSCertificate{}, err } var r MTLSCertificateResponse if err := json.Unmarshal(res, &r); err != nil { - return MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return MTLSCertificate{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } return r.Result, nil } @@ -167,24 +188,27 @@ func (api *API) CreateMTLSCertificate(ctx context.Context, rc *ResourceContainer // DeleteMTLSCertificate will delete the specified mTLS certificate. // // API reference: https://api.cloudflare.com/#mtls-certificate-management-delete-mtls-certificate -func (api *API) DeleteMTLSCertificate(ctx context.Context, rc *ResourceContainer, certificateID string) (MTLSCertificateDetails, error) { - switch { - case rc.Level != AccountRouteLevel: - return MTLSCertificateDetails{}, ErrRequiredAccountLevelResourceContainer - case rc.Identifier == "": - return MTLSCertificateDetails{}, ErrMissingAccountID - case certificateID == "": - return MTLSCertificateDetails{}, ErrMissingCertificateID +func (api *API) DeleteMTLSCertificate(ctx context.Context, rc *ResourceContainer, certificateID string) (MTLSCertificate, error) { + if rc.Level != AccountRouteLevel { + return MTLSCertificate{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return MTLSCertificate{}, ErrMissingAccountID + } + + if certificateID == "" { + return MTLSCertificate{}, ErrMissingCertificateID } uri := fmt.Sprintf("/accounts/%s/mtls_certificates/%s", rc.Identifier, certificateID) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) if err != nil { - return MTLSCertificateDetails{}, err + return MTLSCertificate{}, err } var r MTLSCertificateResponse if err := json.Unmarshal(res, &r); err != nil { - return MTLSCertificateDetails{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return MTLSCertificate{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } return r.Result, nil } diff --git a/mtls_certificates_test.go b/mtls_certificates_test.go index 30156d0ef43..2652eae7b06 100644 --- a/mtls_certificates_test.go +++ b/mtls_certificates_test.go @@ -37,7 +37,7 @@ func TestGetMTLSCertificate(t *testing.T) { mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates/2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", handler) expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") - want := MTLSCertificateDetails{ + want := MTLSCertificate{ ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", Name: "example_ca_cert_5", Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", @@ -49,7 +49,7 @@ func TestGetMTLSCertificate(t *testing.T) { ExpiresOn: expiresOn, } - actual, err := client.GetMTLSCertificateDetails(context.Background(), AccountIdentifier(testAccountID), "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + actual, err := client.GetMTLSCertificate(context.Background(), AccountIdentifier(testAccountID), "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") if assert.NoError(t, err) { assert.Equal(t, want, actual) } @@ -91,7 +91,7 @@ func TestListMTLSCertificates(t *testing.T) { mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates", handler) expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") - want := []MTLSCertificateDetails{ + want := []MTLSCertificate{ { ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", Name: "example_ca_cert_5", @@ -131,14 +131,16 @@ func TestListCertificateAssociations(t *testing.T) { } mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates/2458ce5a-0c35-4c7f-82c7-8e9487d3ff60/associations", handler) - want := []MTLSAssociationDetails{ + want := []MTLSAssociation{ { Service: "gateway", Status: "pending_deployment", }, } - actual, err := client.ListMTLSCertificateAssociations(context.Background(), AccountIdentifier(testAccountID), "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60") + actual, err := client.ListMTLSCertificateAssociations(context.Background(), AccountIdentifier(testAccountID), ListMTLSCertificateAssociationsParams{ + CertificateID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", + }) if assert.NoError(t, err) { assert.Equal(t, want, actual) } @@ -172,7 +174,7 @@ func TestUploadMTLSCertificate(t *testing.T) { mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates", handler) expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") - want := MTLSCertificateDetails{ + want := MTLSCertificate{ ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", Name: "example_ca_cert_5", Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", @@ -224,7 +226,7 @@ func TestDeleteMTLSCertificate(t *testing.T) { mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/mtls_certificates/2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", handler) expiresOn, _ := time.Parse(time.RFC3339, "2122-10-29T16:59:47Z") uploadedOn, _ := time.Parse(time.RFC3339, "2022-11-22T17:32:30.467938Z") - want := MTLSCertificateDetails{ + want := MTLSCertificate{ ID: "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60", Name: "example_ca_cert_5", Issuer: "O=Example Inc.,L=California,ST=San Francisco,C=US", From 857104a925d8cd07fae9fc141a8f1f9069c1c571 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 28 Dec 2022 13:07:36 +1100 Subject: [PATCH 5/5] add CHANGELOG entry --- .changelog/1150.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/1150.txt diff --git a/.changelog/1150.txt b/.changelog/1150.txt new file mode 100644 index 00000000000..ef7d48cd3c6 --- /dev/null +++ b/.changelog/1150.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +mtls_certificate: add support for managing mTLS certificates and assocations +```