Skip to content

Commit

Permalink
Merge pull request #83 from heroku/cd-log-shuttle-credential-no-leak
Browse files Browse the repository at this point in the history
credential leak remediation
  • Loading branch information
cyx authored Jan 25, 2018
2 parents d60b32e + 5f1d2a6 commit 57ec80c
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
19 changes: 19 additions & 0 deletions cleanurl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package shuttle

import "net/url"

// extractCredentials extracts and scrubs basic auth credentials from a URL to
// ensure that they never get logged.
func extractCredentials(uri string) (cleanURL *url.URL, username string, password string, err error) {
cleanURL, err = url.Parse(uri)
if err != nil {
return
}

if cleanURL.User != nil {
username = cleanURL.User.Username()
password, _ = cleanURL.User.Password()
}
cleanURL.User = nil
return cleanURL, username, password, nil
}
20 changes: 20 additions & 0 deletions http_outlet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ func (ts *testEOFHelper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ts.Headers = r.Header
}

func TestCreds(t *testing.T) {
config := newTestConfig()
config.LogsURL = "http://foo:bar@localhost/"
b := NewBatch(1)
b.Add(LogLineOne)
b.Add(LogLineTwo)
br := NewLogplexBatchFormatter(b, noErrData, &config)
r, err := br.Request()
if err != nil {
t.Fatalf("unexpected error constructing request %q", err)
}
if r.URL.User != nil {
t.Error("expected r.URL.User to be nil, but wasn't")
}

if u, p, ok := r.BasicAuth(); !ok && u != "foo" && p != "bar" {
t.Errorf("expected BasicAuth to be foo, bar, true, but got %s, %s, %t", u, p, ok)
}
}

func TestOutletEOFRetry(t *testing.T) {
logLineText := "Hello"
th := &testEOFHelper{maxCloses: 1}
Expand Down
12 changes: 11 additions & 1 deletion logplex_formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,23 @@ func NewLogplexBatchFormatter(b Batch, eData []errData, config *Config) HTTPForm
// Request returns a properly constructed *http.Request, complete with headers
// and ContentLength set.
func (bf *LogplexBatchFormatter) Request() (*http.Request, error) {
req, err := http.NewRequest("POST", bf.stringURL, bf)
u, user, pass, err := extractCredentials(bf.stringURL)
if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", u.String(), bf)
if err != nil {
return nil, err
}

// Assign headers before we potentially BasicAuth
req.Header = bf.headers

if user != "" || pass != "" {
req.SetBasicAuth(user, pass)
}

return req, nil
}

Expand Down

0 comments on commit 57ec80c

Please sign in to comment.