github.com/adacta-ru/mattermost-server/v6@v6.0.0/app/audit.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"net/http"
    10  	"os/user"
    11  
    12  	"github.com/hashicorp/go-multierror"
    13  	"github.com/adacta-ru/mattermost-server/v6/audit"
    14  	"github.com/adacta-ru/mattermost-server/v6/config"
    15  	"github.com/adacta-ru/mattermost-server/v6/mlog"
    16  	"github.com/adacta-ru/mattermost-server/v6/model"
    17  	"github.com/adacta-ru/mattermost-server/v6/store"
    18  )
    19  
    20  const (
    21  	RestLevelID        = 240
    22  	RestContentLevelID = 241
    23  	RestPermsLevelID   = 242
    24  	CLILevelID         = 243
    25  )
    26  
    27  var (
    28  	LevelAPI     = mlog.LvlAuditAPI
    29  	LevelContent = mlog.LvlAuditContent
    30  	LevelPerms   = mlog.LvlAuditPerms
    31  	LevelCLI     = mlog.LvlAuditCLI
    32  )
    33  
    34  func (a *App) GetAudits(userId string, limit int) (model.Audits, *model.AppError) {
    35  	audits, err := a.Srv().Store.Audit().Get(userId, 0, limit)
    36  	if err != nil {
    37  		var outErr *store.ErrOutOfBounds
    38  		switch {
    39  		case errors.As(err, &outErr):
    40  			return nil, model.NewAppError("GetAudits", "app.audit.get.limit.app_error", nil, err.Error(), http.StatusBadRequest)
    41  		default:
    42  			return nil, model.NewAppError("GetAudits", "app.audit.get.finding.app_error", nil, err.Error(), http.StatusInternalServerError)
    43  		}
    44  	}
    45  	return audits, nil
    46  }
    47  
    48  func (a *App) GetAuditsPage(userId string, page int, perPage int) (model.Audits, *model.AppError) {
    49  	audits, err := a.Srv().Store.Audit().Get(userId, page*perPage, perPage)
    50  	if err != nil {
    51  		var outErr *store.ErrOutOfBounds
    52  		switch {
    53  		case errors.As(err, &outErr):
    54  			return nil, model.NewAppError("GetAuditsPage", "app.audit.get.limit.app_error", nil, err.Error(), http.StatusBadRequest)
    55  		default:
    56  			return nil, model.NewAppError("GetAuditsPage", "app.audit.get.finding.app_error", nil, err.Error(), http.StatusInternalServerError)
    57  		}
    58  	}
    59  	return audits, nil
    60  }
    61  
    62  // LogAuditRec logs an audit record using default LvlAuditCLI.
    63  func (a *App) LogAuditRec(rec *audit.Record, err error) {
    64  	a.LogAuditRecWithLevel(rec, mlog.LvlAuditCLI, err)
    65  }
    66  
    67  // LogAuditRecWithLevel logs an audit record using specified Level.
    68  func (a *App) LogAuditRecWithLevel(rec *audit.Record, level mlog.LogLevel, err error) {
    69  	if rec == nil {
    70  		return
    71  	}
    72  	if err != nil {
    73  		if appErr, ok := err.(*model.AppError); ok {
    74  			rec.AddMeta("err", appErr.Error())
    75  			rec.AddMeta("code", appErr.StatusCode)
    76  		} else {
    77  			rec.AddMeta("err", err)
    78  		}
    79  		rec.Fail()
    80  	}
    81  	a.Srv().Audit.LogRecord(level, *rec)
    82  }
    83  
    84  // MakeAuditRecord creates a audit record pre-populated with defaults.
    85  func (a *App) MakeAuditRecord(event string, initialStatus string) *audit.Record {
    86  	var userID string
    87  	user, err := user.Current()
    88  	if err == nil {
    89  		userID = fmt.Sprintf("%s:%s", user.Uid, user.Username)
    90  	}
    91  
    92  	rec := &audit.Record{
    93  		APIPath:   "",
    94  		Event:     event,
    95  		Status:    initialStatus,
    96  		UserID:    userID,
    97  		SessionID: "",
    98  		Client:    fmt.Sprintf("server %s-%s", model.BuildNumber, model.BuildHash),
    99  		IPAddress: "",
   100  		Meta:      audit.Meta{audit.KeyClusterID: a.GetClusterId()},
   101  	}
   102  	rec.AddMetaTypeConverter(model.AuditModelTypeConv)
   103  
   104  	return rec
   105  }
   106  
   107  func (s *Server) configureAudit(adt *audit.Audit, bAllowAdvancedLogging bool) error {
   108  	var errs error
   109  
   110  	adt.OnQueueFull = s.onAuditTargetQueueFull
   111  	adt.OnError = s.onAuditError
   112  
   113  	// Configure target for rotating file output (E0, E10)
   114  	if *s.Config().ExperimentalAuditSettings.FileEnabled {
   115  		opts := audit.FileOptions{
   116  			Filename:   *s.Config().ExperimentalAuditSettings.FileName,
   117  			MaxSize:    *s.Config().ExperimentalAuditSettings.FileMaxSizeMB,
   118  			MaxAge:     *s.Config().ExperimentalAuditSettings.FileMaxAgeDays,
   119  			MaxBackups: *s.Config().ExperimentalAuditSettings.FileMaxBackups,
   120  			Compress:   *s.Config().ExperimentalAuditSettings.FileCompress,
   121  		}
   122  
   123  		maxQueueSize := *s.Config().ExperimentalAuditSettings.FileMaxQueueSize
   124  		if maxQueueSize <= 0 {
   125  			maxQueueSize = audit.DefMaxQueueSize
   126  		}
   127  
   128  		filter := adt.MakeFilter(LevelAPI, LevelContent, LevelPerms, LevelCLI)
   129  		formatter := adt.MakeJSONFormatter()
   130  		formatter.DisableTimestamp = false
   131  		target, err := audit.NewFileTarget(filter, formatter, opts, maxQueueSize)
   132  		if err != nil {
   133  			errs = multierror.Append(err)
   134  		} else {
   135  			mlog.Debug("File audit target created successfully", mlog.String("filename", opts.Filename))
   136  			adt.AddTarget(target)
   137  		}
   138  	}
   139  
   140  	// Advanced logging for audit requires license.
   141  	dsn := *s.Config().ExperimentalAuditSettings.AdvancedLoggingConfig
   142  	if !bAllowAdvancedLogging || dsn == "" {
   143  		return errs
   144  	}
   145  	isJson := config.IsJsonMap(dsn)
   146  	cfg, err := config.NewLogConfigSrc(dsn, isJson, s.configStore)
   147  	if err != nil {
   148  		errs = multierror.Append(fmt.Errorf("invalid config for audit, %w", err))
   149  		return errs
   150  	}
   151  	if !isJson {
   152  		mlog.Debug("Loaded audit configuration", mlog.String("filename", dsn))
   153  	}
   154  
   155  	for name, t := range cfg.Get() {
   156  		if len(t.Levels) == 0 {
   157  			t.Levels = mlog.MLvlAuditAll
   158  		}
   159  		target, err := mlog.NewLogrTarget(name, t)
   160  		if err != nil {
   161  			errs = multierror.Append(err)
   162  			continue
   163  		}
   164  		if target != nil {
   165  			adt.AddTarget(target)
   166  		}
   167  	}
   168  	return errs
   169  }
   170  
   171  func (s *Server) onAuditTargetQueueFull(qname string, maxQSize int) bool {
   172  	mlog.Error("Audit queue full, dropping record.", mlog.String("qname", qname), mlog.Int("queueSize", maxQSize))
   173  	return true // drop it
   174  }
   175  
   176  func (s *Server) onAuditError(err error) {
   177  	mlog.Error("Audit Error", mlog.Err(err))
   178  }