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
Этот коммит содержится в:
@@ -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 {
|
||||
|
||||
14
web/oauth.go
14
web/oauth.go
@@ -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()))
|
||||
|
||||
11
web/saml.go
11
web/saml.go
@@ -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)
|
||||
|
||||
Ссылка в новой задаче
Block a user