Skip to content

Commit

Permalink
proxy config: support path regex in allowed requests (#2731)
Browse files Browse the repository at this point in the history
  • Loading branch information
scarlettperry authored Jul 19, 2023
1 parent b6d33f4 commit a97fa67
Show file tree
Hide file tree
Showing 7 changed files with 356 additions and 47 deletions.
8 changes: 7 additions & 1 deletion api/config/module/proxy/v1/proxy.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ message Service {
}

message AllowRequest {
string path = 1 [ (validate.rules).string.min_len = 1 ];
oneof path_type {
option (validate.required) = true;
// Must match the request path exactly
string path = 1 [ (validate.rules).string.min_len = 1 ];
// Request path must match the regex pattern
string path_regex = 3 [ (validate.rules).string.min_len = 1 ];
}
string method = 2 [ (validate.rules).string.min_len = 1 ];
}
72 changes: 58 additions & 14 deletions backend/api/config/module/proxy/v1/proxy.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 58 additions & 5 deletions backend/api/config/module/proxy/v1/proxy.pb.validate.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 47 additions & 15 deletions backend/module/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"net/http"
"net/url"
"regexp"
"strings"

"github.com/golang/protobuf/ptypes/any"
Expand Down Expand Up @@ -35,14 +36,9 @@ func New(cfg *any.Any, log *zap.Logger, scope tally.Scope) (module.Module, error
return nil, err
}

// Validate that each services constructs a parsable URL
for _, service := range config.Services {
for _, ar := range service.AllowedRequests {
_, err := url.Parse(fmt.Sprintf("%s%s", service.Host, ar.Path))
if err != nil {
return nil, fmt.Errorf("unable to parse the configured URL for service [%s]", service.Name)
}
}
err = validateConfigPaths(config)
if err != nil {
return nil, err
}

m := &mod{
Expand Down Expand Up @@ -205,13 +201,25 @@ func isAllowedRequest(services []*proxyv1cfg.Service, service, path, method stri
for _, s := range services {
if s.Name == service {
for _, ar := range s.AllowedRequests {
parsedUrl, err := url.Parse(fmt.Sprintf("%s%s", s.Host, path))
if err != nil {
return false, err
}

if parsedUrl.Path == ar.Path && strings.EqualFold(method, ar.Method) {
return true, nil
switch t := ar.PathType.(type) {
case *proxyv1cfg.AllowRequest_Path:
parsedUrl, err := url.Parse(fmt.Sprintf("%s%s", s.Host, path))
if err != nil {
return false, err
}
if parsedUrl.Path == t.Path && strings.EqualFold(method, ar.Method) {
return true, nil
}
case *proxyv1cfg.AllowRequest_PathRegex:
r, err := regexp.Compile(t.PathRegex)
if err != nil {
return false, err
}
if r.MatchString(path) {
return true, nil
}
default:
return false, fmt.Errorf("path type not supported: %T", t)
}
}
// return early here as were done checking allowed request for this service
Expand All @@ -235,3 +243,27 @@ func addExcludedHeaders(request *http.Request) {
request.Host = hostHeader
}
}

func validateConfigPaths(config *proxyv1cfg.Config) error {
for _, service := range config.Services {
for _, ar := range service.AllowedRequests {
switch t := ar.PathType.(type) {
case *proxyv1cfg.AllowRequest_Path:
// For exact path type, validate that string constructs a parsable URL
_, err := url.Parse(fmt.Sprintf("%s%s", service.Host, t.Path))
if err != nil {
return fmt.Errorf("unable to parse the configured URL for service [%s]", service.Name)
}
case *proxyv1cfg.AllowRequest_PathRegex:
// For path regex type, validate that expression can be parsed
_, err := regexp.Compile(t.PathRegex)
if err != nil {
return err
}
default:
return fmt.Errorf("path type not supported: %T", t)
}
}
}
return nil
}
Loading

0 comments on commit a97fa67

Please sign in to comment.