Skip to content

Commit

Permalink
check methods at config load
Browse files Browse the repository at this point in the history
  • Loading branch information
Johannes Koch committed Mar 18, 2022
1 parent 6a2c606 commit 60ea2f6
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 12 deletions.
6 changes: 6 additions & 0 deletions config/configload/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ func refineEndpoints(definedBackends Backends, endpoints config.Endpoints, check

endpointContent := bodyToContent(endpoint.Remain)

if check && endpoint.AllowedMethods != nil && len(endpoint.AllowedMethods) > 0 {
if err = validMethods(endpoint.AllowedMethods, &endpointContent.Attributes["allowed_methods"].Range); err != nil {
return err
}
}

proxies := endpointContent.Blocks.OfType(proxy)
requests := endpointContent.Blocks.OfType(request)

Expand Down
6 changes: 6 additions & 0 deletions config/configload/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,12 @@ func LoadConfig(body hcl.Body, src []byte, filename string) (*config.Couper, err
apiConfig.Name = apiBlock.Labels[0]
}

if apiConfig.AllowedMethods != nil && len(apiConfig.AllowedMethods) > 0 {
if err = validMethods(apiConfig.AllowedMethods, &bodyToContent(apiConfig.Remain).Attributes["allowed_methods"].Range); err != nil {
return nil, err
}
}

err := refineEndpoints(definedBackends, apiConfig.Endpoints, true)
if err != nil {
return nil, err
Expand Down
19 changes: 19 additions & 0 deletions config/configload/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ package configload

import (
"fmt"
"regexp"

"github.com/hashicorp/hcl/v2"
)

// https://datatracker.ietf.org/doc/html/rfc7231#section-4
// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
var methodRegExp = regexp.MustCompile("^[!#$%&'*+\\-.\\^_`|~0-9a-zA-Z]+$")

func validLabelName(name string, hr *hcl.Range) error {
if !regexProxyRequestLabel.MatchString(name) {
return hcl.Diagnostics{&hcl.Diagnostic{
Expand Down Expand Up @@ -53,3 +58,17 @@ func verifyBodyAttributes(content *hcl.BodyContent) error {
}
return nil
}

func validMethods(methods []string, hr *hcl.Range) error {
for _, method := range methods {
if !methodRegExp.MatchString(method) {
return hcl.Diagnostics{&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "method contains invalid character(s)",
Subject: hr,
}}
}
}

return nil
}
10 changes: 0 additions & 10 deletions handler/middleware/allowed_methods.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package middleware

import (
"fmt"
"net/http"
"regexp"
"strings"
)

Expand All @@ -17,10 +15,6 @@ var defaultAllowedMethods = []string{
http.MethodOptions,
}

// https://datatracker.ietf.org/doc/html/rfc7231#section-4
// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
var methodRegExp = regexp.MustCompile("^[!#$%&'*+\\-.\\^_`|~0-9a-zA-Z]+$")

var _ http.Handler = &AllowedMethodsHandler{}

type AllowedMethodsHandler struct {
Expand All @@ -41,15 +35,11 @@ func NewAllowedMethodsHandler(allowedMethods []string, allowedHandler, notAllowe
allowedMethods = defaultAllowedMethods
}
for _, method := range allowedMethods {
method = strings.TrimSpace(method)
if method == "*" {
for _, m := range defaultAllowedMethods {
amh.allowedMethods[m] = struct{}{}
}
} else {
if !methodRegExp.Match([]byte(method)) {
return nil, fmt.Errorf("allowed_methods: invalid character in method %q", method)
}
method = strings.ToUpper(method)
amh.allowedMethods[method] = struct{}{}
}
Expand Down
5 changes: 3 additions & 2 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ func Test_realmain(t *testing.T) {
{"non-existent log level via env /w file", []string{"couper", "run", "-f", base + "/log_altered.hcl"}, []string{"COUPER_LOG_LEVEL=test"}, `level=error msg="configuration error: missing 'server' block" build=dev`, 1},
{"-f w/o file", []string{"couper", "run", "-f"}, nil, `level=error msg="flag needs an argument: -f" build=dev`, 1},
{"undefined AC", []string{"couper", "run", "-f", base + "/04_couper.hcl"}, nil, `level=error msg="accessControl is not defined: undefined" build=dev`, 1},
{"empty string in allowed_methods", []string{"couper", "run", "-f", base + "/13_couper.hcl"}, nil, `level=error msg="allowed_methods: invalid character in method \"\"" build=dev`, 1},
{"invalid method in allowed_methods", []string{"couper", "run", "-f", base + "/14_couper.hcl"}, nil, `level=error msg="allowed_methods: invalid character in method \"in valid\"" build=dev`, 1},
{"empty string in allowed_methods in endpoint", []string{"couper", "run", "-f", base + "/13_couper.hcl"}, nil, `level=error msg="13_couper.hcl:3,5-27: method contains invalid character(s); " build=dev`, 1},
{"invalid method in allowed_methods in endpoint", []string{"couper", "run", "-f", base + "/14_couper.hcl"}, nil, `level=error msg="14_couper.hcl:3,5-35: method contains invalid character(s); " build=dev`, 1},
{"invalid method in allowed_methods in api", []string{"couper", "run", "-f", base + "/15_couper.hcl"}, nil, `level=error msg="15_couper.hcl:3,5-35: method contains invalid character(s); " build=dev`, 1},
}
for _, tt := range tests {
t.Run(tt.name, func(subT *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions server/testdata/settings/15_couper.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
server {
api {
allowed_methods = ["in valid"]
}
}

0 comments on commit 60ea2f6

Please sign in to comment.