dnscontrol/pkg/cloudflare-go/waf_test.go
Tom Limoncelli 7fd6a74e0c
CLOUDFLAREAPI: CF_REDIRECT/CF_TEMP_REDIRECT should dtrt using Single Redirects (#3002)
Co-authored-by: Josh Zhang <jzhang1@stackoverflow.com>
2024-06-18 17:38:50 -04:00

794 lines
21 KiB
Go

package cloudflare
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
)
func TestListWAFPackages(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rule-packages-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"id": "a25a9a7e9c00afc1fb2e0245519d725b",
"name": "WordPress rules",
"description": "Common WordPress exploit protections",
"detection_mode": "traditional",
"zone_id": "023e105f4ecef8ad9ca31a8372d0c353",
"status": "active"
}
],
"result_info": {
"page": 1,
"per_page": 20,
"count": 1,
"total_count": 1
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages", handler)
want := []WAFPackage{
{
ID: "a25a9a7e9c00afc1fb2e0245519d725b",
Name: "WordPress rules",
Description: "Common WordPress exploit protections",
ZoneID: "023e105f4ecef8ad9ca31a8372d0c353",
DetectionMode: "traditional",
Sensitivity: "",
ActionMode: "",
},
}
d, err := client.ListWAFPackages(context.Background(), testZoneID)
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFRules(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestListWAFPackagesMultiplePages(t *testing.T) {
setup()
defer teardown()
page := 1
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
reqURI, err := url.ParseRequestURI(r.RequestURI)
assert.NoError(t, err)
query, err := url.ParseQuery(reqURI.RawQuery)
assert.NoError(t, err)
assert.Equal(t, query, url.Values{"page": []string{strconv.Itoa(page)}, "per_page": []string{"100"}})
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"id": "fake_id_number_%[1]d",
"name": "Fake rule name %[1]d",
"description": "Fake rule description %[1]d",
"detection_mode": "traditional",
"zone_id": "%[2]s",
"status": "active"
}
],
"result_info": {
"page": %[1]d,
"per_page": 1,
"total_pages": 2,
"count": 1,
"total_count": 2
}
}`, page, testZoneID)
page++
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages", handler)
want := []WAFPackage{
{
ID: "fake_id_number_1",
Name: "Fake rule name 1",
Description: "Fake rule description 1",
ZoneID: testZoneID,
DetectionMode: "traditional",
Sensitivity: "",
ActionMode: "",
},
{
ID: "fake_id_number_2",
Name: "Fake rule name 2",
Description: "Fake rule description 2",
ZoneID: testZoneID,
DetectionMode: "traditional",
Sensitivity: "",
ActionMode: "",
},
}
d, err := client.ListWAFPackages(context.Background(), testZoneID)
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFRules(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestWAFPackage(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rule-packages-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result":
{
"id": "a25a9a7e9c00afc1fb2e0245519d725b",
"name": "WordPress rules",
"description": "Common WordPress exploit protections",
"detection_mode": "traditional",
"zone_id": "023e105f4ecef8ad9ca31a8372d0c353",
"status": "active"
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b", handler)
want := WAFPackage{
ID: "a25a9a7e9c00afc1fb2e0245519d725b",
Name: "WordPress rules",
Description: "Common WordPress exploit protections",
ZoneID: "023e105f4ecef8ad9ca31a8372d0c353",
DetectionMode: "traditional",
Sensitivity: "",
ActionMode: "",
}
d, err := client.WAFPackage(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.WAFPackage(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestUpdateWAFPackage(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method)
body, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}
defer r.Body.Close()
assert.Equal(t, `{"sensitivity":"high","action_mode":"challenge"}`, string(body), "Expected body '{\"sensitivity\":\"high\",\"action_mode\":\"challenge\"}', got %s", string(body))
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rules-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "a25a9a7e9c00afc1fb2e0245519d725b",
"name": "OWASP ModSecurity Core Rule Set",
"description": "Covers OWASP Top 10 vulnerabilities, and more.",
"detection_mode": "anomaly",
"zone_id": "023e105f4ecef8ad9ca31a8372d0c353",
"status": "active",
"sensitivity": "high",
"action_mode": "challenge"
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b", handler)
want := WAFPackage{
ID: "a25a9a7e9c00afc1fb2e0245519d725b",
Name: "OWASP ModSecurity Core Rule Set",
Description: "Covers OWASP Top 10 vulnerabilities, and more.",
ZoneID: "023e105f4ecef8ad9ca31a8372d0c353",
DetectionMode: "anomaly",
Sensitivity: "high",
ActionMode: "challenge",
}
d, err := client.UpdateWAFPackage(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b", WAFPackageOptions{Sensitivity: "high", ActionMode: "challenge"})
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
}
func TestListWAFGroups(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rule-groups-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"id": "de677e5818985db1285d0e80225f06e5",
"name": "Project Honey Pot",
"description": "Group designed to protect against IP addresses that are a threat and typically used to launch DDoS attacks",
"rules_count": 10,
"modified_rules_count": 2,
"package_id": "a25a9a7e9c00afc1fb2e0245519d725b",
"mode": "on",
"allowed_modes": [
"on",
"off"
]
}
],
"result_info": {
"page": 1,
"per_page": 20,
"count": 1,
"total_count": 1
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b/groups", handler)
want := []WAFGroup{
{
ID: "de677e5818985db1285d0e80225f06e5",
Name: "Project Honey Pot",
Description: "Group designed to protect against IP addresses that are a threat and typically used to launch DDoS attacks",
RulesCount: 10,
ModifiedRulesCount: 2,
PackageID: "a25a9a7e9c00afc1fb2e0245519d725b",
Mode: "on",
AllowedModes: []string{"on", "off"},
},
}
d, err := client.ListWAFGroups(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFGroups(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestListWAFGroupsMultiplePages(t *testing.T) {
setup()
defer teardown()
packageID := "efgh456"
page := 1
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
reqURI, err := url.ParseRequestURI(r.RequestURI)
assert.NoError(t, err)
query, err := url.ParseQuery(reqURI.RawQuery)
assert.NoError(t, err)
assert.Equal(t, query, url.Values{"page": []string{strconv.Itoa(page)}, "per_page": []string{"100"}})
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"id": "fake_group_id_%[1]d",
"name": "Fake Group Name %[1]d",
"description": "Fake Group Description %[1]d",
"rules_count": 1%[1]d,
"modified_rules_count": %[1]d,
"package_id": "%[2]s",
"mode": "on",
"allowed_modes": [
"on",
"off"
]
}
],
"result_info": {
"page": %[1]d,
"per_page": 1,
"total_pages": 2,
"count": 1,
"total_count": 2
}
}`, page, packageID)
page++
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/"+packageID+"/groups", handler)
want := []WAFGroup{
{
ID: "fake_group_id_1",
Name: "Fake Group Name 1",
Description: "Fake Group Description 1",
RulesCount: 11,
ModifiedRulesCount: 1,
PackageID: packageID,
Mode: "on",
AllowedModes: []string{"on", "off"},
},
{
ID: "fake_group_id_2",
Name: "Fake Group Name 2",
Description: "Fake Group Description 2",
RulesCount: 12,
ModifiedRulesCount: 2,
PackageID: packageID,
Mode: "on",
AllowedModes: []string{"on", "off"},
},
}
d, err := client.ListWAFGroups(context.Background(), testZoneID, packageID)
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFGroups(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestWAFGroup(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rule-groups-rule-group-details
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "de677e5818985db1285d0e80225f06e5",
"name": "Project Honey Pot",
"description": "Group designed to protect against IP addresses that are a threat and typically used to launch DDoS attacks",
"rules_count": 10,
"modified_rules_count": 2,
"package_id": "a25a9a7e9c00afc1fb2e0245519d725b",
"mode": "on",
"allowed_modes": [
"on",
"off"
]
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b/groups/de677e5818985db1285d0e80225f06e5", handler)
want := WAFGroup{
ID: "de677e5818985db1285d0e80225f06e5",
Name: "Project Honey Pot",
Description: "Group designed to protect against IP addresses that are a threat and typically used to launch DDoS attacks",
RulesCount: 10,
ModifiedRulesCount: 2,
PackageID: "a25a9a7e9c00afc1fb2e0245519d725b",
Mode: "on",
AllowedModes: []string{"on", "off"},
}
d, err := client.WAFGroup(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b", "de677e5818985db1285d0e80225f06e5")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.WAFGroup(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b", "123")
assert.Error(t, err)
}
func TestUpdateWAFGroup(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method)
body, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}
defer r.Body.Close()
assert.Equal(t, `{"mode":"on"}`, string(body), "Expected body '{\"mode\":\"on\"}', got %s", string(body))
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rule-groups-edit-rule-group
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "de677e5818985db1285d0e80225f06e5",
"name": "Project Honey Pot",
"description": "Group designed to protect against IP addresses that are a threat and typically used to launch DDoS attacks",
"rules_count": 10,
"modified_rules_count": 2,
"package_id": "a25a9a7e9c00afc1fb2e0245519d725b",
"mode": "on",
"allowed_modes": [
"on",
"off"
]
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b/groups/de677e5818985db1285d0e80225f06e5", handler)
want := WAFGroup{
ID: "de677e5818985db1285d0e80225f06e5",
Name: "Project Honey Pot",
Description: "Group designed to protect against IP addresses that are a threat and typically used to launch DDoS attacks",
RulesCount: 10,
ModifiedRulesCount: 2,
PackageID: "a25a9a7e9c00afc1fb2e0245519d725b",
Mode: "on",
AllowedModes: []string{"on", "off"},
}
d, err := client.UpdateWAFGroup(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b", "de677e5818985db1285d0e80225f06e5", "on")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
}
func TestListWAFRules(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rules-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"id": "f939de3be84e66e757adcdcb87908023",
"description": "SQL injection prevention for SELECT statements",
"priority": "5",
"group": {
"id": "de677e5818985db1285d0e80225f06e5",
"name": "Project Honey Pot"
},
"package_id": "a25a9a7e9c00afc1fb2e0245519d725b",
"allowed_modes": [
"on",
"off"
],
"mode": "on"
}
],
"result_info": {
"page": 1,
"per_page": 20,
"count": 1,
"total_count": 1
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b/rules", handler)
want := []WAFRule{
{
ID: "f939de3be84e66e757adcdcb87908023",
Description: "SQL injection prevention for SELECT statements",
Priority: "5",
PackageID: "a25a9a7e9c00afc1fb2e0245519d725b",
Group: struct {
ID string `json:"id"`
Name string `json:"name"`
}{
ID: "de677e5818985db1285d0e80225f06e5",
Name: "Project Honey Pot",
},
Mode: "on",
DefaultMode: "",
AllowedModes: []string{"on", "off"},
},
}
d, err := client.ListWAFRules(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFRules(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestListWAFRulesMultiplePages(t *testing.T) {
setup()
defer teardown()
packageID := "efgh456"
page := 1
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
reqURI, err := url.ParseRequestURI(r.RequestURI)
assert.NoError(t, err)
query, err := url.ParseQuery(reqURI.RawQuery)
assert.NoError(t, err)
assert.Equal(t, query, url.Values{"page": []string{strconv.Itoa(page)}, "per_page": []string{"100"}})
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"id": "fake_rule_id_%[1]d",
"description": "Fake Rule Description %[1]d",
"priority": "%[1]d",
"group": {
"id": "fake_group_id_%[1]d",
"name": "Fake Group Name %[1]d"
},
"package_id": "%[2]s",
"allowed_modes": [
"on",
"off"
],
"mode": "on"
}
],
"result_info": {
"page": %[1]d,
"per_page": 1,
"total_pages": 2,
"count": 1,
"total_count": 2
}
}`, page, packageID)
page++
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/"+packageID+"/rules", handler)
want := []WAFRule{
{
ID: "fake_rule_id_1",
Description: "Fake Rule Description 1",
Priority: "1",
PackageID: packageID,
Group: struct {
ID string `json:"id"`
Name string `json:"name"`
}{
ID: "fake_group_id_1",
Name: "Fake Group Name 1",
},
Mode: "on",
DefaultMode: "",
AllowedModes: []string{"on", "off"},
},
{
ID: "fake_rule_id_2",
Description: "Fake Rule Description 2",
Priority: "2",
PackageID: packageID,
Group: struct {
ID string `json:"id"`
Name string `json:"name"`
}{
ID: "fake_group_id_2",
Name: "Fake Group Name 2",
},
Mode: "on",
DefaultMode: "",
AllowedModes: []string{"on", "off"},
},
}
d, err := client.ListWAFRules(context.Background(), testZoneID, packageID)
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFRules(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestWAFRule(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rules-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "f939de3be84e66e757adcdcb87908023",
"description": "SQL injection prevention for SELECT statements",
"priority": "5",
"group": {
"id": "de677e5818985db1285d0e80225f06e5",
"name": "Project Honey Pot"
},
"package_id": "a25a9a7e9c00afc1fb2e0245519d725b",
"allowed_modes": [
"on",
"off"
],
"mode": "on"
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b/rules/f939de3be84e66e757adcdcb87908023", handler)
want := WAFRule{
ID: "f939de3be84e66e757adcdcb87908023",
Description: "SQL injection prevention for SELECT statements",
Priority: "5",
PackageID: "a25a9a7e9c00afc1fb2e0245519d725b",
Group: struct {
ID string `json:"id"`
Name string `json:"name"`
}{
ID: "de677e5818985db1285d0e80225f06e5",
Name: "Project Honey Pot",
},
Mode: "on",
DefaultMode: "",
AllowedModes: []string{"on", "off"},
}
d, err := client.WAFRule(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b", "f939de3be84e66e757adcdcb87908023")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFRules(context.Background(), testZoneID, "123")
assert.Error(t, err)
}
func TestUpdateWAFRule(t *testing.T) {
setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method)
body, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}
defer r.Body.Close()
assert.Equal(t, `{"mode":"on"}`, string(body), "Expected method '{\"mode\":\"on\"}', got %s", string(body))
w.Header().Set("content-type", "application/json")
// JSON data from: https://api.cloudflare.com/#waf-rules-properties
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "f939de3be84e66e757adcdcb87908023",
"description": "SQL injection prevention for SELECT statements",
"priority": "5",
"group": {
"id": "de677e5818985db1285d0e80225f06e5",
"name": "Project Honey Pot"
},
"package_id": "a25a9a7e9c00afc1fb2e0245519d725b",
"allowed_modes": [
"on",
"off"
],
"mode": "on"
}
}`)
}
mux.HandleFunc("/zones/"+testZoneID+"/firewall/waf/packages/a25a9a7e9c00afc1fb2e0245519d725b/rules/f939de3be84e66e757adcdcb87908023", handler)
want := WAFRule{
ID: "f939de3be84e66e757adcdcb87908023",
Description: "SQL injection prevention for SELECT statements",
Priority: "5",
PackageID: "a25a9a7e9c00afc1fb2e0245519d725b",
Group: struct {
ID string `json:"id"`
Name string `json:"name"`
}{
ID: "de677e5818985db1285d0e80225f06e5",
Name: "Project Honey Pot",
},
Mode: "on",
DefaultMode: "",
AllowedModes: []string{"on", "off"},
}
d, err := client.UpdateWAFRule(context.Background(), testZoneID, "a25a9a7e9c00afc1fb2e0245519d725b", "f939de3be84e66e757adcdcb87908023", "on")
if assert.NoError(t, err) {
assert.Equal(t, want, d)
}
_, err = client.ListWAFRules(context.Background(), testZoneID, "123")
assert.Error(t, err)
}