Skip to content

Commit

Permalink
new config var enable_key_logging added, request logging unified
Browse files Browse the repository at this point in the history
  • Loading branch information
dencoded committed Nov 17, 2017
1 parent 83d9a52 commit bcb9c72
Show file tree
Hide file tree
Showing 19 changed files with 244 additions and 172 deletions.
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ type Config struct {
ProxyDefaultTimeout int `json:"proxy_default_timeout"`
LogLevel string `json:"log_level"`
Security SecurityConfig `json:"security"`
EnableKeyLogging bool `json:"enable_key_logging"`
}

type CertData struct {
Expand Down
7 changes: 2 additions & 5 deletions coprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,8 @@ func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Requ
// The CP middleware indicates this is a bad auth:
if returnObject.Request.ReturnOverrides.ResponseCode > 400 {

log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
"key": token,
}).Info("Attempted access with invalid key.")
logEntry := getLogEntryForRequest(r, token, nil)
logEntry.Info("Attempted access with invalid key.")

// Fire Authfailed Event
AuthFailed(m, r, token)
Expand Down
6 changes: 2 additions & 4 deletions coprocess_id_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,8 @@ func (e *BaseExtractor) ExtractBody(r *http.Request) (bodyValue string, err erro

// Error is a helper for logging the extractor errors. It always returns HTTP 400 (so we don't expose any details).
func (e *BaseExtractor) Error(r *http.Request, err error, message string) (returnOverrides ReturnOverrides) {
log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
}).Info("Extractor error: ", message, ", ", err)
logEntry := getLogEntryForRequest(r, "", nil)
logEntry.Info("Extractor error: ", message, ", ", err)

return ReturnOverrides{
ResponseCode: 400,
Expand Down
3 changes: 3 additions & 0 deletions lint/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,9 @@ const confSchema = `{
}
}
}
},
"enable_key_logging": {
"type": "boolean"
}
}
}`
28 changes: 28 additions & 0 deletions log_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"net/http"

"github.com/Sirupsen/logrus"

"github.com/TykTechnologies/tyk/config"
)

func getLogEntryForRequest(r *http.Request, key string, data map[string]interface{}) *logrus.Entry {
// populate http request fields
fields := logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
}
// add key to log if configured to do so
if key != "" && config.Global.EnableKeyLogging {
fields["key"] = key
}
// add to log additional fields if any passed
if data != nil && len(data) > 0 {
for key, val := range data {
fields[key] = val
}
}
return log.WithFields(fields)
}
131 changes: 131 additions & 0 deletions log_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package main

import (
"net/http/httptest"
"testing"

"github.com/Sirupsen/logrus"
"github.com/TykTechnologies/tyk/config"
)

func TestGetLogEntryForRequest(t *testing.T) {
testReq := httptest.NewRequest("GET", "http://tyk.io/test", nil)
testReq.RemoteAddr = "127.0.0.1:80"
testData := []struct {
EnableKeyLogging bool
Key string
Data map[string]interface{}
Result *logrus.Entry
}{
// enable_key_logging is set, key passed, no additional data fields
{
EnableKeyLogging: true,
Key: "abc",
Data: nil,
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
"key": "abc",
}),
},
// enable_key_logging is set, key is not passed, no additional data fields
{
EnableKeyLogging: true,
Key: "",
Data: nil,
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
}),
},
// enable_key_logging is set, key passed, additional data fields are passed
{
EnableKeyLogging: true,
Key: "abc",
Data: map[string]interface{}{"a": 1, "b": "test"},
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
"key": "abc",
"a": 1,
"b": "test",
}),
},
// enable_key_logging is set, key is not passed, additional data fields are passed
{
EnableKeyLogging: true,
Key: "",
Data: map[string]interface{}{"a": 1, "b": "test"},
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
"a": 1,
"b": "test",
}),
},
// enable_key_logging is not set, key passed, no additional data field
{
EnableKeyLogging: false,
Key: "abc",
Data: nil,
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
}),
},
// enable_key_logging is not set, key is not passed, no additional data field
{
EnableKeyLogging: false,
Key: "",
Data: nil,
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
}),
},
// enable_key_logging is not set, key passed, additional data fields are passed
{
EnableKeyLogging: false,
Key: "abc",
Data: map[string]interface{}{"a": 1, "b": "test"},
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
"a": 1,
"b": "test",
}),
},
// enable_key_logging is not set, key is not passed, additional data fields are passed
{
EnableKeyLogging: false,
Key: "",
Data: map[string]interface{}{"a": 1, "b": "test"},
Result: logrus.WithFields(logrus.Fields{
"path": "/test",
"origin": "127.0.0.1",
"a": 1,
"b": "test",
}),
},
}
for _, test := range testData {
config.Global.EnableKeyLogging = test.EnableKeyLogging
logEntry := getLogEntryForRequest(testReq, test.Key, test.Data)
if logEntry.Data["path"] != test.Result.Data["path"] {
t.Error("Expected 'path':", test.Result.Data["path"], "Got:", logEntry.Data["path"])
}
if logEntry.Data["origin"] != test.Result.Data["origin"] {
t.Error("Expected 'origin':", test.Result.Data["origin"], "Got:", logEntry.Data["origin"])
}
if logEntry.Data["key"] != test.Result.Data["key"] {
t.Error("Expected 'key':", test.Result.Data["key"], "Got:", logEntry.Data["key"])
}
if test.Data != nil {
for key, val := range test.Data {
if logEntry.Data[key] != val {
t.Error("Expected data key:", key, "with value:", val, "Got:", logEntry.Data[key])
}
}
}
}
}
32 changes: 17 additions & 15 deletions mw_access_rights.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package main
import (
"errors"
"net/http"

"github.com/Sirupsen/logrus"
)

// AccessRightsCheck is a middleware that will check if the key bing used to access the API has
Expand All @@ -29,12 +27,14 @@ func (a *AccessRightsCheck) ProcessRequest(w http.ResponseWriter, r *http.Reques
// Otherwise, run auth checks
versionList, apiExists := session.AccessRights[a.Spec.APIID]
if !apiExists {
log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
"key": token,
"api_found": false,
}).Info("Attempted access to unauthorised API.")
logEntry := getLogEntryForRequest(
r,
token,
map[string]interface{}{
"api_found": false,
},
)
logEntry.Info("Attempted access to unauthorised API.")

return errors.New("Access to this API has been disallowed"), 403
}
Expand All @@ -55,13 +55,15 @@ func (a *AccessRightsCheck) ProcessRequest(w http.ResponseWriter, r *http.Reques

if !found {
// Not found? Bounce
log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
"key": token,
"api_found": true,
"version_found": false,
}).Info("Attempted access to unauthorised API version.")
logEntry := getLogEntryForRequest(
r,
token,
map[string]interface{}{
"api_found": true,
"version_found": false,
},
)
logEntry.Info("Attempted access to unauthorised API version.")

return errors.New("Access to this API has been disallowed"), 403
}
Expand Down
9 changes: 2 additions & 7 deletions mw_api_rate_limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"fmt"
"net/http"

"github.com/Sirupsen/logrus"

"strconv"
"time"

Expand Down Expand Up @@ -44,11 +42,8 @@ func (k *RateLimitForAPI) EnabledForSpec() bool {
}

func (k *RateLimitForAPI) handleRateLimitFailure(r *http.Request, token string) (error, int) {
log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
"key": token,
}).Info("API rate limit exceeded.")
logEntry := getLogEntryForRequest(r, token, nil)
logEntry.Info("API rate limit exceeded.")

// Fire a rate limit exceeded event
k.FireEvent(EventRateLimitExceeded, EventKeyFailureMeta{
Expand Down
15 changes: 4 additions & 11 deletions mw_auth_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"net/http"
"strings"

"github.com/Sirupsen/logrus"

"github.com/TykTechnologies/tyk/apidef"
"github.com/TykTechnologies/tyk/certs"
)
Expand Down Expand Up @@ -76,10 +74,8 @@ func (k *AuthKey) ProcessRequest(w http.ResponseWriter, r *http.Request, _ inter

if key == "" {
// No header value, fail
log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
}).Info("Attempted access with malformed header, no auth header found.")
logEntry := getLogEntryForRequest(r, "", nil)
logEntry.Info("Attempted access with malformed header, no auth header found.")

return errors.New("Authorization field missing"), 401
}
Expand All @@ -90,11 +86,8 @@ func (k *AuthKey) ProcessRequest(w http.ResponseWriter, r *http.Request, _ inter
// Check if API key valid
session, keyExists := k.CheckSessionAndIdentityForValidKey(key)
if !keyExists {
log.WithFields(logrus.Fields{
"path": r.URL.Path,
"origin": requestIP(r),
"key": key,
}).Info("Attempted access with non-existent key.")
logEntry := getLogEntryForRequest(r, key, nil)
logEntry.Info("Attempted access with non-existent key.")

// Fire Authfailed Event
AuthFailed(k, r, key)
Expand Down
Loading

0 comments on commit bcb9c72

Please sign in to comment.