From 84b52333c101cf29c5086650dcb6089399ff2412 Mon Sep 17 00:00:00 2001 From: Doug Lauder Date: Mon, 28 Aug 2023 07:24:55 -0400 Subject: [PATCH] MM-53165 Add X-Forwarded-For header to audit for rest api calls (#24390) * Add X-Forwarded-For header to audit for rest api calls * fix unit test --- server/channels/app/audit.go | 9 +++++---- server/channels/app/request/context.go | 8 ++++++++ server/channels/audit/audit_test.go | 4 ++-- server/channels/audit/record.go | 9 +++++---- server/channels/web/context.go | 9 +++++---- server/channels/web/handlers.go | 4 +++- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/server/channels/app/audit.go b/server/channels/app/audit.go index 200e9d8b69..3a847a1cf6 100644 --- a/server/channels/app/audit.go +++ b/server/channels/app/audit.go @@ -89,10 +89,11 @@ func (a *App) MakeAuditRecord(event string, initialStatus string) *audit.Record audit.KeyClusterID: a.GetClusterId(), }, Actor: audit.EventActor{ - UserId: userID, - SessionId: "", - Client: fmt.Sprintf("server %s-%s", model.BuildNumber, model.BuildHash), - IpAddress: "", + UserId: userID, + SessionId: "", + Client: fmt.Sprintf("server %s-%s", model.BuildNumber, model.BuildHash), + IpAddress: "", + XForwardedFor: "", }, EventData: audit.EventData{ Parameters: map[string]interface{}{}, diff --git a/server/channels/app/request/context.go b/server/channels/app/request/context.go index 29efaedeea..b9027b4ef1 100644 --- a/server/channels/app/request/context.go +++ b/server/channels/app/request/context.go @@ -16,6 +16,7 @@ type Context struct { session model.Session requestId string ipAddress string + xForwardedFor string path string userAgent string acceptLanguage string @@ -58,6 +59,9 @@ func (c *Context) RequestId() string { func (c *Context) IPAddress() string { return c.ipAddress } +func (c *Context) XForwardedFor() string { + return c.xForwardedFor +} func (c *Context) Path() string { return c.path } @@ -85,6 +89,9 @@ func (c *Context) SetRequestId(s string) { func (c *Context) SetIPAddress(s string) { c.ipAddress = s } +func (c *Context) SetXForwardedFor(s string) { + c.xForwardedFor = s +} func (c *Context) SetUserAgent(s string) { c.userAgent = s } @@ -123,6 +130,7 @@ type CTX interface { Session() *model.Session RequestId() string IPAddress() string + XForwardedFor() string Path() string UserAgent() string AcceptLanguage() string diff --git a/server/channels/audit/audit_test.go b/server/channels/audit/audit_test.go index db48b12c09..a488eee84a 100644 --- a/server/channels/audit/audit_test.go +++ b/server/channels/audit/audit_test.go @@ -32,7 +32,7 @@ func TestAudit_LogRecord(t *testing.T) { audit.LogRecord(mlog.LvlAuditAPI, rec) }, []string{ - `{"timestamp":0,"level":"audit-api","msg":"","event_name":"","status":"","actor":{"user_id":"","session_id":"","client":"","ip_address":""},"event":{"parameters":null,"prior_state":null,"resulting_state":null,"object_type":""},"meta":null,"error":{}}`, + `{"timestamp":0,"level":"audit-api","msg":"","event_name":"","status":"","actor":{"user_id":"","session_id":"","client":"","ip_address":"","x_forwarded_for":""},"event":{"parameters":null,"prior_state":null,"resulting_state":null,"object_type":""},"meta":null,"error":{}}`, }, }, { @@ -56,7 +56,7 @@ func TestAudit_LogRecord(t *testing.T) { audit.LogRecord(mlog.LvlAuditAPI, rec) }, []string{ - strings.Replace(`{"timestamp":0,"level":"audit-api","msg":"","event_name":"User.Update","status":"success","actor":{"user_id":"","session_id":"","client":"","ip_address":""},"event":{"parameters":null,"prior_state":{"allow_marketing":false,"auth_service":"","bot_description":"","bot_last_icon_update":0,"create_at":0,"delete_at":0,"disable_welcome_email":false,"email":"","email_verified":false,"failed_attempts":0,"id":"_____USERID_____","is_bot":false,"last_activity_at":0,"last_password_update":0,"last_picture_update":0,"locale":"","mfa_active":false,"notify_props":null,"position":"","props":null,"remote_id":null,"roles":"","terms_of_service_create_at":0,"terms_of_service_id":"","timezone":null,"update_at":0,"username":"TestABC"},"resulting_state":{"allow_marketing":false,"auth_service":"","bot_description":"","bot_last_icon_update":0,"create_at":0,"delete_at":0,"disable_welcome_email":false,"email":"","email_verified":false,"failed_attempts":0,"id":"_____USERID_____","is_bot":false,"last_activity_at":0,"last_password_update":0,"last_picture_update":0,"locale":"","mfa_active":false,"notify_props":null,"position":"","props":null,"remote_id":null,"roles":"","terms_of_service_create_at":0,"terms_of_service_id":"","timezone":null,"update_at":0,"username":"TestDEF"},"object_type":"user"},"meta":null,"error":{}}`, "_____USERID_____", userId, -1), + strings.Replace(`{"timestamp":0,"level":"audit-api","msg":"","event_name":"User.Update","status":"success","actor":{"user_id":"","session_id":"","client":"","ip_address":"","x_forwarded_for":""},"event":{"parameters":null,"prior_state":{"allow_marketing":false,"auth_service":"","bot_description":"","bot_last_icon_update":0,"create_at":0,"delete_at":0,"disable_welcome_email":false,"email":"","email_verified":false,"failed_attempts":0,"id":"_____USERID_____","is_bot":false,"last_activity_at":0,"last_password_update":0,"last_picture_update":0,"locale":"","mfa_active":false,"notify_props":null,"position":"","props":null,"remote_id":null,"roles":"","terms_of_service_create_at":0,"terms_of_service_id":"","timezone":null,"update_at":0,"username":"TestABC"},"resulting_state":{"allow_marketing":false,"auth_service":"","bot_description":"","bot_last_icon_update":0,"create_at":0,"delete_at":0,"disable_welcome_email":false,"email":"","email_verified":false,"failed_attempts":0,"id":"_____USERID_____","is_bot":false,"last_activity_at":0,"last_password_update":0,"last_picture_update":0,"locale":"","mfa_active":false,"notify_props":null,"position":"","props":null,"remote_id":null,"roles":"","terms_of_service_create_at":0,"terms_of_service_id":"","timezone":null,"update_at":0,"username":"TestDEF"},"object_type":"user"},"meta":null,"error":{}}`, "_____USERID_____", userId, -1), }, }, } diff --git a/server/channels/audit/record.go b/server/channels/audit/record.go index 2e12b1d7cb..fd516bfc50 100644 --- a/server/channels/audit/record.go +++ b/server/channels/audit/record.go @@ -23,10 +23,11 @@ type EventData struct { // EventActor is the subject triggering the event type EventActor struct { - UserId string `json:"user_id"` - SessionId string `json:"session_id"` - Client string `json:"client"` - IpAddress string `json:"ip_address"` + UserId string `json:"user_id"` + SessionId string `json:"session_id"` + Client string `json:"client"` + IpAddress string `json:"ip_address"` + XForwardedFor string `json:"x_forwarded_for"` } // EventMeta is a key-value store to store related information to the event that is not directly related to the modified entity diff --git a/server/channels/web/context.go b/server/channels/web/context.go index 85f73a02fb..c269c79d4b 100644 --- a/server/channels/web/context.go +++ b/server/channels/web/context.go @@ -59,10 +59,11 @@ func (c *Context) MakeAuditRecord(event string, initialStatus string) *audit.Rec EventName: event, Status: initialStatus, Actor: audit.EventActor{ - UserId: c.AppContext.Session().UserId, - SessionId: c.AppContext.Session().Id, - Client: c.AppContext.UserAgent(), - IpAddress: c.AppContext.IPAddress(), + UserId: c.AppContext.Session().UserId, + SessionId: c.AppContext.Session().Id, + Client: c.AppContext.UserAgent(), + IpAddress: c.AppContext.IPAddress(), + XForwardedFor: c.AppContext.XForwardedFor(), }, Meta: map[string]interface{}{ audit.KeyAPIPath: c.AppContext.Path(), diff --git a/server/channels/web/handlers.go b/server/channels/web/handlers.go index c1c01c9118..da155e317e 100644 --- a/server/channels/web/handlers.go +++ b/server/channels/web/handlers.go @@ -14,11 +14,12 @@ import ( "strings" "time" - "github.com/mattermost/gziphandler" "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go/ext" spanlog "github.com/opentracing/opentracing-go/log" + "github.com/mattermost/gziphandler" + "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/shared/i18n" "github.com/mattermost/mattermost/server/public/shared/mlog" @@ -172,6 +173,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { c.AppContext.SetT(t) c.AppContext.SetRequestId(requestID) c.AppContext.SetIPAddress(utils.GetIPAddress(r, c.App.Config().ServiceSettings.TrustedProxyIPHeader)) + c.AppContext.SetXForwardedFor(r.Header.Get("X-Forwarded-For")) c.AppContext.SetUserAgent(r.UserAgent()) c.AppContext.SetAcceptLanguage(r.Header.Get("Accept-Language")) c.AppContext.SetPath(r.URL.Path)