MM-22273 New auditing system (phase 1) (#13967)

* New auditing API outputting to syslog via TLS

* New config section for specifying remote syslog server IP, port, and cert.

* Legacy audit API retained for access history feature
Этот коммит содержится в:
Doug Lauder
2020-03-12 15:50:21 -04:00
коммит произвёл GitHub
родитель bd1e7f2265
Коммит 4ac0619c90
156 изменённых файлов: 16991 добавлений и 49 удалений

Просмотреть файл

@@ -10,6 +10,7 @@ import (
"strings"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/audit"
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/utils"
@@ -23,6 +24,56 @@ type Context struct {
siteURLHeader string
}
// LogAuditRec logs an audit record using default RestLevel.
func (c *Context) LogAuditRec(rec *audit.Record) {
c.LogAuditRecWithLevel(rec, app.RestLevel)
}
// LogAuditRec logs an audit record using specificed Level.
func (c *Context) LogAuditRecWithLevel(rec *audit.Record, level audit.Level) {
if rec == nil {
return
}
if c.Err != nil {
rec.AddMeta("err", c.Err.Id)
rec.AddMeta("code", c.Err.StatusCode)
if c.Err.Id == "api.context.permissions.app_error" {
level = app.RestPermsLevel
}
rec.Fail()
}
c.App.Srv().Audit.LogRecord(level, *rec)
}
// LogAuditMeta creates an audit record and logs it.
func (c *Context) LogAuditEx(event string, status string) {
rec := c.MakeAuditRecord(event, status)
c.LogAuditRec(rec)
}
// LogAuditMeta creates an audit record with metadata and logs it.
func (c *Context) LogAuditMeta(event string, status string, meta audit.Meta) {
rec := c.MakeAuditRecord(event, status)
if meta != nil {
rec.Meta = meta
}
c.LogAuditRec(rec)
}
// MakeAuditRecord creates a audit record pre-populated with data from this context.
func (c *Context) MakeAuditRecord(event string, initialStatus string) *audit.Record {
return &audit.Record{
APIPath: c.App.Path(),
Event: event,
Status: initialStatus,
UserID: c.App.Session().UserId,
SessionID: c.App.Session().Id,
Client: c.App.UserAgent(),
IPAddress: c.App.IpAddress(),
Meta: audit.Meta{},
}
}
func (c *Context) LogAudit(extraInfo string) {
audit := &model.Audit{UserId: c.App.Session().UserId, IpAddress: c.App.IpAddress(), Action: c.App.Path(), ExtraInfo: extraInfo, SessionId: c.App.Session().Id}
if err := c.App.Srv().Store.Audit().Save(audit); err != nil {

Просмотреть файл

@@ -10,6 +10,7 @@ import (
"strings"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/audit"
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/utils"
@@ -57,6 +58,8 @@ func authorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("authorizeOAuthApp", audit.Fail)
defer c.LogAuditRec(auditRec)
c.LogAudit("attempt")
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.App.Session().UserId, authRequest)
@@ -66,6 +69,7 @@ func authorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec.Success()
c.LogAudit("")
w.Write([]byte(model.MapToJson(map[string]string{"redirect": redirectUrl})))
@@ -80,13 +84,18 @@ func deauthorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("deauthorizeOAuthApp", audit.Fail)
defer c.LogAuditRec(auditRec)
err := c.App.DeauthorizeOAuthAppForUser(c.App.Session().UserId, clientId)
if err != nil {
c.Err = err
return
}
auditRec.Success()
c.LogAudit("success")
ReturnStatusOK(w)
}
@@ -200,6 +209,10 @@ func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
redirectUri := r.FormValue("redirect_uri")
auditRec := c.MakeAuditRecord("getAccessToken", audit.Fail)
defer c.LogAuditRec(auditRec)
auditRec.AddMeta("grant_type", grantType)
auditRec.AddMeta("client_id", clientId)
c.LogAudit("attempt")
accessRsp, err := c.App.GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectUri, code, secret, refreshToken)
@@ -212,6 +225,7 @@ func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Pragma", "no-cache")
auditRec.Success()
c.LogAudit("success")
w.Write([]byte(accessRsp.ToJson()))

Просмотреть файл

@@ -8,6 +8,7 @@ import (
"net/http"
"strings"
"github.com/mattermost/mattermost-server/v5/audit"
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
)
@@ -84,13 +85,16 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
relayProps = model.MapFromJson(strings.NewReader(stateStr))
}
auditRec := c.MakeAuditRecord("completeSaml", audit.Fail)
defer c.LogAuditRec(auditRec)
c.LogAudit("attempt")
action := relayProps["action"]
auditRec.AddMeta("action", action)
user, err := samlInterface.DoLogin(encodedXML, relayProps)
if err != nil {
c.LogAudit("fail")
if action == model.OAUTH_ACTION_MOBILE {
err.Translate(c.App.T)
w.Write([]byte(err.ToJson()))
@@ -124,6 +128,9 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = err
return
}
auditRec.AddMeta("revoked_user_id", user.Id)
auditRec.AddMeta("revoked", "Revoked all sessions for user")
c.LogAuditWithUserId(user.Id, "Revoked all sessions for user")
c.App.Srv().Go(func() {
if err = c.App.SendSignInChangeEmail(user.Email, strings.Title(model.USER_AUTH_SERVICE_SAML)+" SSO", user.Locale, c.App.GetSiteURL()); err != nil {
@@ -132,6 +139,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
})
}
auditRec.AddMeta("obtained_user_id", user.Id)
c.LogAuditWithUserId(user.Id, "obtained user")
err = c.App.DoLogin(w, r, user, "")
@@ -140,6 +148,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec.Success()
c.LogAuditWithUserId(user.Id, "success")
c.App.AttachSessionCookies(w, r)