diff --git a/akamai/cache-client.go b/akamai/cache-client.go index 8759e81cc..dfccc9c13 100644 --- a/akamai/cache-client.go +++ b/akamai/cache-client.go @@ -21,17 +21,10 @@ import ( ) const ( - v2PurgePath = "/ccu/v2/queues/default" v3PurgePath = "/ccu/v3/delete/url/" timestampFormat = "20060102T15:04:05-0700" ) -type v2PurgeRequest struct { - Objects []string `json:"objects"` - Type string `json:"type"` - Action string `json:"action"` -} - type v3PurgeRequest struct { Objects []string `json:"objects"` } @@ -44,9 +37,7 @@ type purgeResponse struct { } // CachePurgeClient talks to the Akamai CCU REST API. It is safe to make concurrent -// purge requests. If the v3Network field is "" the legacy CCU v2 API is used. -// If the v3Network field is either "staging" or "production" then the CCU v3 -// API is used. +// purge requests. type CachePurgeClient struct { client *http.Client apiEndpoint string @@ -95,9 +86,8 @@ func NewCachePurgeClient( if err != nil { return nil, err } - // If there is a network provided, we're using the V3 API and the network - // string must be either "production" or "staging". - if v3Network != "" && v3Network != "production" && v3Network != "staging" { + // The network string must be either "production" or "staging". + if v3Network != "production" && v3Network != "staging" { return nil, fmt.Errorf( "Invalid CCU v3 network: %q. Must be \"staging\" or \"production\"", v3Network) } @@ -121,7 +111,7 @@ func NewCachePurgeClient( // Akamai uses a special authorization header to identify clients to their EdgeGrid // APIs, their docs (https://developer.akamai.com/introduction/Client_Auth.html) // provide a description of the required generation process. -func (cpc *CachePurgeClient) constructAuthHeader(request *http.Request, body []byte, apiPath string, nonce string) (string, error) { +func (cpc *CachePurgeClient) constructAuthHeader(body []byte, apiPath string, nonce string) (string, error) { // The akamai API is very time sensitive (recommending reliance on a stratum 2 // or better time source) and, although it doesn't say it anywhere, really wants // the timestamp to be in the UTC timezone for some reason. @@ -169,23 +159,11 @@ func signingKey(clientSecret string, timestamp string) []byte { // purge actually sends the individual requests to the Akamai endpoint and checks // if they are successful func (cpc *CachePurgeClient) purge(urls []string) error { - var purgeReq interface{} - var endpoint, purgePath string - if cpc.v3Network == "" { - purgeReq = v2PurgeRequest{ - Objects: urls, - Action: "remove", - Type: "arl", - } - purgePath = v2PurgePath - endpoint = fmt.Sprintf("%s%s", cpc.apiEndpoint, purgePath) - } else { - purgeReq = v3PurgeRequest{ - Objects: urls, - } - purgePath = v3PurgePath - endpoint = fmt.Sprintf("%s%s%s", cpc.apiEndpoint, purgePath, cpc.v3Network) + purgeReq := v3PurgeRequest{ + Objects: urls, } + endpoint := fmt.Sprintf("%s%s%s", cpc.apiEndpoint, v3PurgePath, cpc.v3Network) + reqJSON, err := json.Marshal(purgeReq) if err != nil { return errFatal(err.Error()) @@ -201,9 +179,8 @@ func (cpc *CachePurgeClient) purge(urls []string) error { // Create authorization header for request authHeader, err := cpc.constructAuthHeader( - req, reqJSON, - purgePath+cpc.v3Network, + v3PurgePath+cpc.v3Network, core.RandomString(16), ) if err != nil { diff --git a/akamai/cache-client_test.go b/akamai/cache-client_test.go index dd76f9244..3bc68fb74 100644 --- a/akamai/cache-client_test.go +++ b/akamai/cache-client_test.go @@ -1,7 +1,6 @@ package akamai import ( - "bytes" "encoding/json" "fmt" "io/ioutil" @@ -38,16 +37,8 @@ func TestConstructAuthHeader(t *testing.T) { test.AssertNotError(t, err, "Failed to parse timestamp") fc.Set(wantedTimestamp) - req, err := http.NewRequest( - "POST", - fmt.Sprintf("%s%s", cpc.apiEndpoint, v2PurgePath), - bytes.NewBuffer([]byte{0}), - ) - test.AssertNotError(t, err, "Failed to create request") - expectedHeader := "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=hXm4iCxtpN22m4cbZb4lVLW5rhX8Ca82vCFqXzSTPe4=" authHeader, err := cpc.constructAuthHeader( - req, []byte("datadatadatadatadatadatadatadata"), "/testapi/v1/t3", "nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", @@ -58,7 +49,6 @@ func TestConstructAuthHeader(t *testing.T) { type akamaiServer struct { responseCode int - v3 bool *httptest.Server } @@ -74,9 +64,7 @@ func (as *akamaiServer) sendResponse(w http.ResponseWriter, resp purgeResponse) } func (as *akamaiServer) akamaiHandler(w http.ResponseWriter, r *http.Request) { - // Enforce the request path based on the API version we're emulating - if (as.v3 == false && r.URL.Path != v2PurgePath) || - (as.v3 == true && !strings.HasPrefix(r.URL.Path, v3PurgePath)) { + if !strings.HasPrefix(r.URL.Path, v3PurgePath) { resp := purgeResponse{ HTTPStatus: http.StatusNotFound, Detail: fmt.Sprintf("Invalid path: %q", r.URL.Path), @@ -87,8 +75,6 @@ func (as *akamaiServer) akamaiHandler(w http.ResponseWriter, r *http.Request) { var req struct { Objects []string - Type string - Action string } body, err := ioutil.ReadAll(r.Body) if err != nil { @@ -104,17 +90,6 @@ func (as *akamaiServer) akamaiHandler(w http.ResponseWriter, r *http.Request) { return } - // Enforce that a V3 request is well formed and does not include the "Type" - // and "Action" fields used by the V2 api. - if as.v3 == true && (req.Type != "" || req.Action != "") { - resp := purgeResponse{ - HTTPStatus: http.StatusBadRequest, - Detail: fmt.Sprintf("Invalid request body: included V2 Type %q and Action %q\n", req.Type, req.Action), - } - as.sendResponse(w, resp) - return - } - err = json.Unmarshal(body, &req) if err != nil { fmt.Printf("Failed to unmarshal request body: %s\n", err) @@ -137,60 +112,19 @@ func (as *akamaiServer) akamaiHandler(w http.ResponseWriter, r *http.Request) { } as.sendResponse(w, resp) } -func newAkamaiServer(code int, v3 bool) *akamaiServer { +func newAkamaiServer(code int) *akamaiServer { m := http.NewServeMux() as := akamaiServer{ responseCode: code, - v3: v3, Server: httptest.NewServer(m), } m.HandleFunc("/", as.akamaiHandler) return &as } -// TestV2Purge tests the legacy CCU v2 Akamai API used when the v3Network -// parameter to NewCachePurgeClient is "". -func TestV2Purge(t *testing.T) { - log := blog.NewMock() - - as := newAkamaiServer(http.StatusCreated, false) - defer as.Close() - - client, err := NewCachePurgeClient( - as.URL, - "token", - "secret", - "accessToken", - "", - 3, - time.Second, - log, - metrics.NewNoopScope(), - ) - test.AssertNotError(t, err, "Failed to create CachePurgeClient") - fc := clock.NewFake() - client.clk = fc - - err = client.Purge([]string{"http://test.com"}) - test.AssertNotError(t, err, "Purge failed with 201 response") - - started := fc.Now() - as.responseCode = http.StatusInternalServerError - err = client.Purge([]string{"http://test.com"}) - test.AssertError(t, err, "Purge didn't fail with 400 response") - test.Assert(t, fc.Since(started) > (time.Second*4), "Retries should've taken at least 4.4 seconds") - - started = fc.Now() - as.responseCode = http.StatusCreated - err = client.Purge([]string{"http:/test.com"}) - test.AssertError(t, err, "Purge didn't fail with 403 response from malformed URL") - test.Assert(t, fc.Since(started) < time.Second, "Purge should've failed out immediately") -} - -// TestV3Purge tests the Akamai CCU v3 purge API by setting the v3Network -// parameter to "production". +// TestV3Purge tests the Akamai CCU v3 purge API func TestV3Purge(t *testing.T) { - as := newAkamaiServer(http.StatusCreated, true) + as := newAkamaiServer(http.StatusCreated) defer as.Close() // Client is a purge client with a "production" v3Network parameter @@ -275,7 +209,6 @@ func TestBigBatchPurge(t *testing.T) { m := http.NewServeMux() as := akamaiServer{ responseCode: http.StatusCreated, - v3: true, Server: httptest.NewUnstartedServer(m), } m.HandleFunc("/", as.akamaiHandler) diff --git a/cmd/config.go b/cmd/config.go index 2cddad4b9..2302d4464 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -172,13 +172,10 @@ type OCSPUpdaterConfig struct { OldestIssuedSCT ConfigDuration ParallelGenerateOCSPRequests int - AkamaiBaseURL string - AkamaiClientToken string - AkamaiClientSecret string - AkamaiAccessToken string - // When AkamaiV3Network is not provided, the Akamai CCU API v2 is used. When - // AkamaiV3Network is set to "staging" or "production" the Akamai CCU API v3 - // is used. + AkamaiBaseURL string + AkamaiClientToken string + AkamaiClientSecret string + AkamaiAccessToken string AkamaiV3Network string AkamaiPurgeRetries int AkamaiPurgeRetryBackoff ConfigDuration diff --git a/test/akamai-test-srv/main.go b/test/akamai-test-srv/main.go index 762a9611b..81758dad2 100644 --- a/test/akamai-test-srv/main.go +++ b/test/akamai-test-srv/main.go @@ -18,8 +18,6 @@ func main() { secret := flag.String("secret", "", "Akamai client secret") flag.Parse() - // v2 - v2Purges := [][]string{} v3Purges := [][]string{} mu := sync.Mutex{} @@ -27,9 +25,8 @@ func main() { mu.Lock() defer mu.Unlock() body, err := json.Marshal(struct { - V2 [][]string V3 [][]string - }{V2: v2Purges, V3: v3Purges}) + }{V3: v3Purges}) if err != nil { w.WriteHeader(http.StatusInternalServerError) return @@ -41,13 +38,11 @@ func main() { http.HandleFunc("/debug/reset-purges", func(w http.ResponseWriter, r *http.Request) { mu.Lock() defer mu.Unlock() - v2Purges, v3Purges = [][]string{}, [][]string{} + v3Purges = [][]string{} w.WriteHeader(http.StatusOK) return }) - // Since v2 and v3 APIs share a bunch of logic just mash them into a single - // handler. http.HandleFunc("/ccu/", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { w.WriteHeader(http.StatusMethodNotAllowed) @@ -58,8 +53,6 @@ func main() { defer mu.Unlock() var purgeRequest struct { Objects []string `json:"objects"` - Type string `json:"type"` - Action string `json:"action"` } body, err := ioutil.ReadAll(r.Body) if err != nil { @@ -77,21 +70,12 @@ func main() { fmt.Println("Can't unmarshal:", err) return } - if r.URL.Path == "/ccu/v2/queues/default" { - if purgeRequest.Type != "arl" || purgeRequest.Action != "remove" || len(purgeRequest.Objects) == 0 { - w.WriteHeader(http.StatusBadRequest) - fmt.Println("Bad parameters:", purgeRequest) - return - } - v2Purges = append(v2Purges, purgeRequest.Objects) - } else if r.URL.Path == "/ccu/v3/delete/url/staging" { - if len(purgeRequest.Objects) == 0 || purgeRequest.Type != "" || purgeRequest.Action != "" { - w.WriteHeader(http.StatusBadRequest) - fmt.Println("Bad parameters:", purgeRequest) - return - } - v3Purges = append(v3Purges, purgeRequest.Objects) + if len(purgeRequest.Objects) == 0 { + w.WriteHeader(http.StatusBadRequest) + fmt.Println("Bad parameters:", purgeRequest) + return } + v3Purges = append(v3Purges, purgeRequest.Objects) respObj := struct { PurgeID string diff --git a/test/config/ocsp-updater.json b/test/config/ocsp-updater.json index f48bb3e19..97f1137cb 100644 --- a/test/config/ocsp-updater.json +++ b/test/config/ocsp-updater.json @@ -21,6 +21,7 @@ "akamaiClientToken": "its-a-token", "akamaiClientSecret": "its-a-secret", "akamaiAccessToken": "idk-how-this-is-different-from-client-token-but-okay", + "akamaiV3Network": "staging", "tls": { "caCertFile": "test/grpc-creds/minica.pem", "certFile": "test/grpc-creds/ocsp-updater.boulder/cert.pem", diff --git a/test/helpers.py b/test/helpers.py index 74f771400..4a43d3977 100644 --- a/test/helpers.py +++ b/test/helpers.py @@ -115,14 +115,6 @@ def reset_akamai_purges(): def verify_akamai_purge(): response = requests.get("http://localhost:6789/debug/get-purges") purgeData = response.json() - if os.environ.get('BOULDER_CONFIG_DIR', '').startswith("test/config-next"): - if len(purgeData["V3"]) is not 1: - raise Exception("Unexpected number of Akamai v3 purges") - if len(purgeData["V2"]) is not 0: - raise Exception("Unexpected number of Akamai v2 purges") - else: - if len(purgeData["V2"]) is not 1: - raise Exception("Unexpected number of Akamai v2 purges") - if len(purgeData["V3"]) is not 0: - raise Exception("Unexpected number of Akamai v3 purges") + if len(purgeData["V3"]) is not 1: + raise Exception("Unexpected number of Akamai v3 purges") reset_akamai_purges()