Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter requests using regex on base64 decoded userId:passwd #475

Merged
merged 2 commits into from
Aug 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions http_modifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package main

import (
"bytes"
"strings"
"hash/fnv"
"encoding/base64"

"github.com/buger/goreplay/proto"
)
Expand All @@ -19,6 +21,7 @@ func NewHTTPModifier(config *HTTPModifierConfig) *HTTPModifier {
len(config.headerRewrite) == 0 &&
len(config.headerFilters) == 0 &&
len(config.headerNegativeFilters) == 0 &&
len(config.headerBasicAuthFilters) == 0 &&
len(config.headerHashFilters) == 0 &&
len(config.paramHashFilters) == 0 &&
len(config.params) == 0 &&
Expand Down Expand Up @@ -111,6 +114,23 @@ func (m *HTTPModifier) Rewrite(payload []byte) (response []byte) {
}
}

if len(m.config.headerBasicAuthFilters) > 0 {
for _, f := range m.config.headerBasicAuthFilters {
value := proto.Header(payload, []byte("Authorization"))

if len(value) > 0 {
valueString := string(value)
trimmedBasicAuthEncoded := strings.TrimPrefix(valueString, "Basic ")
if strings.Compare(valueString, trimmedBasicAuthEncoded) != 0 {
decodedAuth, _ := base64.StdEncoding.DecodeString(trimmedBasicAuthEncoded)
if !f.regexp.Match(decodedAuth) {
return
}
}
}
}
}

if len(m.config.headerHashFilters) > 0 {
for _, f := range m.config.headerHashFilters {
value := proto.Header(payload, f.name)
Expand Down
43 changes: 35 additions & 8 deletions http_modifier_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import (

// HTTPModifierConfig holds configuration options for built-in traffic modifier
type HTTPModifierConfig struct {
urlNegativeRegexp HTTPUrlRegexp
urlRegexp HTTPUrlRegexp
urlRewrite UrlRewriteMap
headerRewrite HeaderRewriteMap
headerFilters HTTPHeaderFilters
headerNegativeFilters HTTPHeaderFilters
headerHashFilters HTTPHashFilters
paramHashFilters HTTPHashFilters
urlNegativeRegexp HTTPUrlRegexp
urlRegexp HTTPUrlRegexp
urlRewrite UrlRewriteMap
headerRewrite HeaderRewriteMap
headerFilters HTTPHeaderFilters
headerNegativeFilters HTTPHeaderFilters
headerBasicAuthFilters HTTPHeaderBasicAuthFilters
headerHashFilters HTTPHashFilters
paramHashFilters HTTPHashFilters

params HTTPParams
headers HTTPHeaders
Expand Down Expand Up @@ -55,6 +56,32 @@ func (h *HTTPHeaderFilters) Set(value string) error {
return nil
}

//
// Handling of --http-basic-auth-filter option
//
type basicAuthFilter struct {
regexp *regexp.Regexp
}

// HTTPHeaderFilters holds list of headers and their regexps
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment on exported type HTTPHeaderBasicAuthFilters should be of the form "HTTPHeaderBasicAuthFilters ..." (with optional leading article)

type HTTPHeaderBasicAuthFilters []basicAuthFilter

func (h *HTTPHeaderBasicAuthFilters) String() string {
return fmt.Sprint(*h)
}

func (h *HTTPHeaderBasicAuthFilters) Set(value string) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exported method HTTPHeaderBasicAuthFilters.Set should have comment or be unexported

r, err := regexp.Compile(value)
if err != nil {
return err
}

*h = append(*h, basicAuthFilter{regexp: r})

return nil
}


//
// Handling of --http-allow-header-hash and --http-allow-param-hash options
//
Expand Down
39 changes: 39 additions & 0 deletions http_modifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,45 @@ func TestHTTPModifierHeaderNegativeFilters(t *testing.T) {
}
}

func TestHTTPHeaderBasicAuthFilters(t *testing.T) {
filters := HTTPHeaderBasicAuthFilters{}
filters.Set("^customer[0-9].*")

modifier := NewHTTPModifier(&HTTPModifierConfig{
headerBasicAuthFilters: filters,
})

//Encoded UserId:Password = customer3:welcome
payload := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nAuthorization: Basic Y3VzdG9tZXIzOndlbGNvbWU=\r\n\r\na=1&b=2")
if len(modifier.Rewrite(payload)) == 0 {
t.Error("Request should pass filters")
}

//customer6:rest@123^TEST
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 88\r\nAuthorization: Basic Y3VzdG9tZXI2OnJlc3RAMTIzXlRFU1Q==\r\n\r\na=1&b=2")
if len(modifier.Rewrite(payload)) == 0 {
t.Error("Request should pass filters")
}

filters = HTTPHeaderBasicAuthFilters{}
// Setting filter that not match our header
filters.Set("^(homer simpson|mickey mouse).*")

modifier = NewHTTPModifier(&HTTPModifierConfig{
headerBasicAuthFilters: filters,
})

if len(modifier.Rewrite(payload)) != 0 {
t.Error("Request should not pass filters")
}

//mickey mouse:happy123
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 88\r\nAuthorization: Basic bWlja2V5IG1vdXNlOmhhcHB5MTIz\r\n\r\na=1&b=2")
if len(modifier.Rewrite(payload)) == 0 {
t.Error("Request should pass filters")
}
}

func TestHTTPModifierURLRewrite(t *testing.T) {
var url, newURL []byte

Expand Down
5 changes: 4 additions & 1 deletion settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ func init() {

flag.Var(&Settings.modifierConfig.headerNegativeFilters, "http-disallow-header", "A regexp to match a specific header against. Requests with matching headers will be dropped:\n\t gor --input-raw :8080 --output-http staging.com --http-disallow-header \"User-Agent: Replayed by Gor\"")

flag.Var(&Settings.modifierConfig.headerHashFilters, "http-header-limiter", "Takes a fraction of requests, consistently taking or rejecting a request based on the FNV32-1A hash of a specific header:\n\t gor --input-raw :8080 --output-http staging.com --http-header-limiter user-id:25%")
flag.Var(&Settings.modifierConfig.headerBasicAuthFilters, "http-basic-auth-filter", "A regexp to match the decoded basic auth string against. Requests with non-matching headers will be dropped:\n\t gor --input-raw :8080 --output-http staging.com --http-basic-auth-filter \"^customer[0-9].*\"")

flag.Var(&Settings.modifierConfig.headerHashFilters, "http-header-limiter", "Takes a fraction of requests, consistently taking or rejecting a request based on the FNV32-1A hash of a specific header:\n\t gor --input-raw :8080 --output-http staging.com --http-header-limiter user-id:25%")

flag.Var(&Settings.modifierConfig.headerHashFilters, "output-http-header-hash-filter", "WARNING: `output-http-header-hash-filter` DEPRECATED, use `--http-header-hash-limiter` instead")

flag.Var(&Settings.modifierConfig.paramHashFilters, "http-param-limiter", "Takes a fraction of requests, consistently taking or rejecting a request based on the FNV32-1A hash of a specific GET param:\n\t gor --input-raw :8080 --output-http staging.com --http-param-limiter user_id:25%")
Expand Down