Add logging to capture user email upon successful login (#7927)

* Log user email upon successful login

* Add user email to logger context

* Use logging.With Extras for login email
This commit is contained in:
gillespi314 2022-09-27 14:32:46 -05:00 committed by GitHub
parent 474fd8fab8
commit 749ff9ec2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 4 deletions

View file

@ -0,0 +1 @@
* Added logging to capture user email upon successful login

View file

@ -132,7 +132,6 @@ func (l *LoggingContext) Log(ctx context.Context, logger kitlog.Logger) {
}
keyvals = append(keyvals, "user", loggedInUser)
}
requestMethod, ok := ctx.Value(kithttp.ContextKeyRequestMethod).(string)
if !ok {
requestMethod = ""

View file

@ -86,7 +86,7 @@ func (s *integrationLoggerTestSuite) TestLogger() {
assert.Equal(t, "GET", kv["method"])
assert.Equal(t, "/api/latest/fleet/config", kv["uri"])
assert.Equal(t, "admin1@example.com", kv["user"])
case 2:
case 3:
assert.Equal(t, "debug", kv["level"])
assert.Equal(t, "POST", kv["method"])
assert.Equal(t, "/api/latest/fleet/queries", kv["uri"])
@ -99,6 +99,61 @@ func (s *integrationLoggerTestSuite) TestLogger() {
}
}
func (s *integrationLoggerTestSuite) TestLoggerLogin() {
t := s.T()
type logEntry struct {
key string
val string
}
testCases := []struct {
loginRequest loginRequest
expectedStatus int
expectedLogs []logEntry
}{
{
loginRequest: loginRequest{Email: testUsers["admin1"].Email, Password: testUsers["admin1"].PlaintextPassword},
expectedStatus: http.StatusOK,
expectedLogs: []logEntry{{"email", testUsers["admin1"].Email}},
},
{
loginRequest: loginRequest{Email: testUsers["admin1"].Email, Password: "n074v411dp455w02d"},
expectedStatus: http.StatusUnauthorized,
expectedLogs: []logEntry{
{"email", testUsers["admin1"].Email},
{"level", "error"},
{"internal", "invalid password"},
},
},
{
loginRequest: loginRequest{Email: "h4x0r@3x4mp13.c0m", Password: "n074v411dp455w02d"},
expectedStatus: http.StatusUnauthorized,
expectedLogs: []logEntry{
{"email", "h4x0r@3x4mp13.c0m"},
{"level", "error"},
{"internal", "user not found"},
},
},
}
var resp loginResponse
for _, tt := range testCases {
s.DoJSON("POST", "/api/latest/fleet/login", tt.loginRequest, tt.expectedStatus, &resp)
logString := s.buf.String()
parts := strings.Split(strings.TrimSpace(logString), "\n")
require.Len(t, parts, 1)
logData := make(map[string]string)
require.NoError(t, json.Unmarshal([]byte(parts[0]), &logData))
require.NotContains(t, logData, "user") // logger context is set to skip user
for _, e := range tt.expectedLogs {
assert.Equal(t, logData[e.key], e.val)
}
s.buf.Reset()
}
}
func (s *integrationLoggerTestSuite) TestOsqueryEndpointsLogErrors() {
t := s.T()

View file

@ -153,7 +153,7 @@ func (svc *Service) Login(ctx context.Context, email, password string) (*fleet.U
// skipauth: No user context available yet to authorize against.
svc.authz.SkipAuthorization(ctx)
logging.WithLevel(logging.WithNoUser(ctx), level.Info)
logging.WithLevel(logging.WithExtras(logging.WithNoUser(ctx), "email", email), level.Info)
// If there is an error, sleep until the request has taken at least 1
// second. This means that generally a login failure for any reason will

View file

@ -98,7 +98,7 @@ func TestAuthenticate(t *testing.T) {
svc := newTestService(t, ds, nil, nil)
createTestUsers(t, ds)
var loginTests = []struct {
loginTests := []struct {
name string
email string
password string