Ensure loggableDSN scrubs passwords in different ways

The previous implementation of the function was only scrubbing those passwords
that were part of a basic http authentication method, which means it
expected passwords to be provided as part of the URL.

However, the password
may also be specified as a parameter, or when using key-values, it may be
specified as a password=value string.

This commit ensures those passwords will also not be retained, but
removed.

Signed-off-by: Feike Steenbergen <feike@timescale.com>
This commit is contained in:
Feike Steenbergen 2022-05-04 21:23:48 +02:00
parent 1b492a6c59
commit 5b57a4d058
No known key found for this signature in database
GPG Key ID: BE67E84EF3533CA4
2 changed files with 70 additions and 0 deletions

View File

@ -421,3 +421,58 @@ func (s *FunctionalSuite) TestParseUserQueries(c *C) {
}
}
}
func (s *FunctionalSuite) TestLoggableDSN(c *C) {
type TestCase struct {
input string
expected string
}
cases := []TestCase{
{
input: "host=host.example.com user=postgres port=5432 password=s3cr3t",
expected: "host=host.example.com user=postgres port=5432 password=PASSWORD_REMOVED",
},
{
input: "host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"",
expected: "host=host.example.com user=postgres port=5432 password=PASSWORD_REMOVED",
},
{
input: "password=abcde host=host.example.com user=postgres port=5432",
expected: "password=PASSWORD_REMOVED host=host.example.com user=postgres port=5432",
},
{
input: "password=abcde host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"",
expected: "password=PASSWORD_REMOVED host=host.example.com user=postgres port=5432 password=PASSWORD_REMOVED",
},
{
input: "postgresql://host.example.com:5432/tsdb?user=postgres",
expected: "postgresql://host.example.com:5432/tsdb?user=postgres",
},
{
input: "postgresql://user:s3cret@host.example.com:5432/tsdb?user=postgres",
expected: "postgresql://user:PASSWORD_REMOVED@host.example.com:5432/tsdb?user=postgres",
},
{
input: "postgresql://host.example.com:5432/tsdb?user=postgres&password=s3cr3t",
expected: "postgresql://host.example.com:5432/tsdb?password=PASSWORD_REMOVED&user=postgres",
},
{
input: "host=host.example.com user=postgres port=5432",
expected: "host=host.example.com user=postgres port=5432",
},
}
for _, cs := range cases {
loggable := loggableDSN(cs.input)
c.Assert(loggable, Equals, cs.expected)
}
}

View File

@ -17,6 +17,7 @@ import (
"fmt"
"math"
"net/url"
"regexp"
"strconv"
"strings"
"time"
@ -212,10 +213,24 @@ func loggableDSN(dsn string) string {
if err != nil {
return "could not parse DATA_SOURCE_NAME"
}
// If the DSN is not a URL it is expected to be in the `key1=value1 key2=value2` format
if pDSN.Scheme == "" {
re := regexp.MustCompile(`(\s?password=([^"\s]+|"[^"]+"))`)
stripped := re.ReplaceAllString(dsn, " password=PASSWORD_REMOVED")
return strings.TrimSpace(stripped)
}
// Blank user info if not nil
if pDSN.User != nil {
pDSN.User = url.UserPassword(pDSN.User.Username(), "PASSWORD_REMOVED")
}
// If the password is contained in a URL parameter, we should remove it there
if q, err := url.ParseQuery(pDSN.RawQuery); err == nil && q.Has("password") {
q.Set("password", "PASSWORD_REMOVED")
pDSN.RawQuery = q.Encode()
}
return pDSN.String()
}