Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

Commit

Permalink
adding filtered param logger
Browse files Browse the repository at this point in the history
  • Loading branch information
paganotoni committed Aug 2, 2018
1 parent a98d8d4 commit b5a0adc
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 9 deletions.
100 changes: 91 additions & 9 deletions middleware/param_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,94 @@ import (
"encoding/json"
"mime/multipart"
"net/url"
"strings"

"github.com/gobuffalo/buffalo"
"github.com/pkg/errors"
)

//ParameterFilterBlackList is the list of parameter names that will be filtered
//from the application logs (see maskSecrets).
//Important: this list will be used in case insensitive.
var ParameterFilterBlackList = []string{
"Password",
"PasswordConfirmation",
"CreditCard",
"CVC",
}

var filteredIndicator = []string{"[FILTERED]"}

// ParameterLogger logs form and parameter values to the logger
type parameterLogger struct {
blacklist []string
}

// ParameterLogger logs form and parameter values to the loggers
func ParameterLogger(next buffalo.Handler) buffalo.Handler {
pl := parameterLogger{
blacklist: ParameterFilterBlackList,
}

return func(c buffalo.Context) error {
defer func() {
req := c.Request()
if req.Method != "GET" {
if err := postParamLogger(c); err != nil {
if err := pl.logForm(c); err != nil {
c.Logger().Error(err)
}
}

b, err := json.Marshal(c.Params())
if err != nil {
c.Logger().Error(err)
}

c.LogField("params", string(b))
}()

return next(c)
}
}

func postParamLogger(c buffalo.Context) error {
//Middleware is a buffalo middleware function to connect this parameter filterer with buffalo
func (pl parameterLogger) Middleware(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
defer func() {
req := c.Request()
if req.Method != "GET" {
if err := pl.logForm(c); err != nil {
c.Logger().Error(err)
}
}

b, err := json.Marshal(c.Params())
if err != nil {
c.Logger().Error(err)
}

c.LogField("params", string(b))
}()

return next(c)
}
}

func (pl parameterLogger) logForm(c buffalo.Context) error {
req := c.Request()
mp := req.MultipartForm
if mp != nil {
return multipartParamLogger(mp, c)
return pl.multipartParamLogger(mp, c)
}

b, err := json.Marshal(req.Form)
if err != nil {
if err := pl.addFormFieldTo(c, req.Form); err != nil {
return errors.WithStack(err)
}
c.LogField("form", string(b))

return nil
}

func multipartParamLogger(mp *multipart.Form, c buffalo.Context) error {
func (pl parameterLogger) multipartParamLogger(mp *multipart.Form, c buffalo.Context) error {
uv := url.Values{}
for k, v := range mp.Value {
for _, vv := range v {
Expand All @@ -56,10 +103,45 @@ func multipartParamLogger(mp *multipart.Form, c buffalo.Context) error {
uv.Add(k, vv.Filename)
}
}
b, err := json.Marshal(uv)
if err != nil {

if err := pl.addFormFieldTo(c, uv); err != nil {
return errors.WithStack(err)
}
return nil
}

func (pl parameterLogger) addFormFieldTo(c buffalo.Context, form url.Values) error {
maskedForm := pl.maskSecrets(form)
b, err := json.Marshal(maskedForm)

if err != nil {
return err
}

c.LogField("form", string(b))
return nil
}

//maskSecrets matches ParameterFilterBlackList against parameters passed in the
//request, and returns a copy of the request parameters replacing blacklisted params
//with [FILTERED].
func (pl parameterLogger) maskSecrets(form url.Values) url.Values {
if len(pl.blacklist) == 0 {
pl.blacklist = ParameterFilterBlackList
}

copy := url.Values{}
for key, values := range form {
blcheck:
for _, blacklisted := range pl.blacklist {
copy[key] = values
if strings.ToUpper(key) == strings.ToUpper(blacklisted) {
copy[key] = filteredIndicator
break blcheck
}

}
}

return copy
}
58 changes: 58 additions & 0 deletions middleware/param_logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package middleware

import (
"net/url"
"testing"

"github.com/stretchr/testify/require"
)

func Test_maskSecrets(t *testing.T) {
r := require.New(t)
pl := parameterLogger{}

filteredForm := pl.maskSecrets(url.Values{
"FirstName": []string{"Antonio"},
"MiddleName": []string{"José"},
"LastName": []string{"Pagano"},
"Password": []string{"Secret!"},
"password": []string{"Other"},
"pAssWorD": []string{"Weird one"},
"PasswordConfirmation": []string{"Secret!"},

"SomeCVC": []string{"Untouched"},
})

r.Equal(filteredForm.Get("Password"), filteredIndicator[0])
r.Equal(filteredForm.Get("password"), filteredIndicator[0])
r.Equal(filteredForm.Get("pAssWorD"), filteredIndicator[0])
r.Equal(filteredForm.Get("PasswordConfirmation"), filteredIndicator[0])
r.Equal(filteredForm.Get("LastName"), "Pagano")
r.Equal(filteredForm.Get("SomeCVC"), "Untouched")
}

func Test_maskSecretsCustom(t *testing.T) {
r := require.New(t)
ParameterFilterBlackList = []string{
"FirstName", "LastName", "MiddleName",
}

pl := parameterLogger{}

filteredForm := pl.maskSecrets(url.Values{
"FirstName": []string{"Antonio"},
"MiddleName": []string{"José"},
"LastName": []string{"Pagano"},
"Password": []string{"Secret!"},
"password": []string{"Other"},
"pAssWorD": []string{"Weird one"},
"PasswordConfirmation": []string{"Secret!"},

"SomeCVC": []string{"Untouched"},
})

r.Equal(filteredForm.Get("Password"), "Secret!")
r.Equal(filteredForm.Get("password"), "Other")
r.Equal(filteredForm.Get("LastName"), filteredIndicator[0])
r.Equal(filteredForm.Get("SomeCVC"), "Untouched")
}

0 comments on commit b5a0adc

Please sign in to comment.