From f0671015f8819e129a218810b1a1151f6120d4a8 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Tue, 8 Mar 2022 11:25:26 +0100 Subject: [PATCH 1/6] initial draft Signed-off-by: jkoberg --- audit/cmd/notifications/main.go | 14 ++++ audit/pkg/channels/channels.go | 105 ++++++++++++++++++++++++++++++ audit/pkg/command/health.go | 18 +++++ audit/pkg/command/root.go | 64 ++++++++++++++++++ audit/pkg/command/server.go | 50 ++++++++++++++ audit/pkg/command/version.go | 19 ++++++ audit/pkg/config/config.go | 44 +++++++++++++ audit/pkg/config/debug.go | 9 +++ audit/pkg/config/defaultconfig.go | 27 ++++++++ audit/pkg/config/log.go | 9 +++ audit/pkg/config/parser/parse.go | 40 ++++++++++++ audit/pkg/config/service.go | 6 ++ audit/pkg/logging/logging.go | 17 +++++ audit/pkg/service/events.go | 79 ++++++++++++++++++++++ audit/pkg/service/instrument.go | 21 ++++++ audit/pkg/service/logging.go | 23 +++++++ audit/pkg/service/option.go | 50 ++++++++++++++ audit/pkg/service/service.go | 48 ++++++++++++++ audit/pkg/service/tracing.go | 17 +++++ audit/pkg/types/conversion.go | 79 ++++++++++++++++++++++ audit/pkg/types/types.go | 40 ++++++++++++ go.mod | 3 +- 22 files changed, 781 insertions(+), 1 deletion(-) create mode 100644 audit/cmd/notifications/main.go create mode 100644 audit/pkg/channels/channels.go create mode 100644 audit/pkg/command/health.go create mode 100644 audit/pkg/command/root.go create mode 100644 audit/pkg/command/server.go create mode 100644 audit/pkg/command/version.go create mode 100644 audit/pkg/config/config.go create mode 100644 audit/pkg/config/debug.go create mode 100644 audit/pkg/config/defaultconfig.go create mode 100644 audit/pkg/config/log.go create mode 100644 audit/pkg/config/parser/parse.go create mode 100644 audit/pkg/config/service.go create mode 100644 audit/pkg/logging/logging.go create mode 100644 audit/pkg/service/events.go create mode 100644 audit/pkg/service/instrument.go create mode 100644 audit/pkg/service/logging.go create mode 100644 audit/pkg/service/option.go create mode 100644 audit/pkg/service/service.go create mode 100644 audit/pkg/service/tracing.go create mode 100644 audit/pkg/types/conversion.go create mode 100644 audit/pkg/types/types.go diff --git a/audit/cmd/notifications/main.go b/audit/cmd/notifications/main.go new file mode 100644 index 0000000000..64d0cdc081 --- /dev/null +++ b/audit/cmd/notifications/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "os" + + "github.com/owncloud/ocis/audit/pkg/command" + "github.com/owncloud/ocis/audit/pkg/config" +) + +func main() { + if err := command.Execute(config.DefaultConfig()); err != nil { + os.Exit(1) + } +} diff --git a/audit/pkg/channels/channels.go b/audit/pkg/channels/channels.go new file mode 100644 index 0000000000..f13914da45 --- /dev/null +++ b/audit/pkg/channels/channels.go @@ -0,0 +1,105 @@ +// Package channels provides different communication channels to notify users. +package channels + +import ( + "context" + "net/smtp" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + groups "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" + "github.com/pkg/errors" +) + +// Channel defines the methods of a communication channel. +type Channel interface { + // SendMessage sends a message to users. + SendMessage(userIDs []string, msg string) error + // SendMessageToGroup sends a message to a group. + SendMessageToGroup(groupdID *groups.GroupId, msg string) error +} + +// NewMailChannel instantiates a new mail communication channel. +func NewMailChannel(cfg config.Config, logger log.Logger) (Channel, error) { + gc, err := pool.GetGatewayServiceClient(cfg.Notifications.RevaGateway) + if err != nil { + logger.Error().Err(err).Msg("could not get gateway client") + return nil, err + } + return Mail{ + gatewayClient: gc, + conf: cfg, + logger: logger, + }, nil +} + +// Mail is the communcation channel for email. +type Mail struct { + gatewayClient gateway.GatewayAPIClient + conf config.Config + logger log.Logger +} + +// SendMessage sends a message to all given users. +func (m Mail) SendMessage(userIDs []string, msg string) error { + to, err := m.getReceiverAddresses(userIDs) + if err != nil { + return err + } + body := []byte(msg) + + smtpConf := m.conf.Notifications.SMTP + auth := smtp.PlainAuth("", smtpConf.Sender, smtpConf.Password, smtpConf.Host) + if err := smtp.SendMail(smtpConf.Host+":"+smtpConf.Port, auth, smtpConf.Sender, to, body); err != nil { + return errors.Wrap(err, "could not send mail") + } + return nil +} + +// SendMessageToGroup sends a message to all members of the given group. +func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg string) error { + // TODO We need an authenticated context here... + res, err := m.gatewayClient.GetGroup(context.Background(), &groups.GetGroupRequest{GroupId: groupID}) + if err != nil { + return err + } + if res.Status.Code != rpc.Code_CODE_OK { + return errors.New("could not get group") + } + + members := make([]string, 0, len(res.Group.Members)) + for _, id := range res.Group.Members { + members = append(members, id.OpaqueId) + } + + return m.SendMessage(members, msg) +} + +func (m Mail) getReceiverAddresses(receivers []string) ([]string, error) { + addresses := make([]string, 0, len(receivers)) + for _, id := range receivers { + // Authenticate is too costly but at the moment our only option to get the user. + // We don't have an authenticated context so calling `GetUser` doesn't work. + res, err := m.gatewayClient.Authenticate(context.Background(), &gateway.AuthenticateRequest{ + Type: "machine", + ClientId: "userid:" + id, + ClientSecret: m.conf.Notifications.MachineAuthSecret, + }) + if err != nil { + return nil, err + } + if res.Status.Code != rpc.Code_CODE_OK { + m.logger.Error(). + Interface("status", res.Status). + Str("receiver_id", id). + Msg("could not get user") + continue + } + addresses = append(addresses, res.User.Mail) + } + + return addresses, nil +} diff --git a/audit/pkg/command/health.go b/audit/pkg/command/health.go new file mode 100644 index 0000000000..7f2adb85b5 --- /dev/null +++ b/audit/pkg/command/health.go @@ -0,0 +1,18 @@ +package command + +import ( + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/urfave/cli/v2" +) + +// Health is the entrypoint for the health command. +func Health(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "health", + Usage: "Check health status", + Action: func(c *cli.Context) error { + // Not implemented + return nil + }, + } +} diff --git a/audit/pkg/command/root.go b/audit/pkg/command/root.go new file mode 100644 index 0000000000..805d8cec3a --- /dev/null +++ b/audit/pkg/command/root.go @@ -0,0 +1,64 @@ +package command + +import ( + "context" + "os" + + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/clihelper" + ociscfg "github.com/owncloud/ocis/ocis-pkg/config" + "github.com/thejerf/suture/v4" + "github.com/urfave/cli/v2" +) + +// GetCommands provides all commands for this service +func GetCommands(cfg *config.Config) cli.Commands { + return []*cli.Command{ + // start this service + Server(cfg), + + // interaction with this service + + // infos about this service + Health(cfg), + Version(cfg), + } +} + +// Execute is the entry point for the notifications command. +func Execute(cfg *config.Config) error { + app := clihelper.DefaultApp(&cli.App{ + Name: "notifications", + Usage: "starts notifications service", + Commands: GetCommands(cfg), + }) + + cli.HelpFlag = &cli.BoolFlag{ + Name: "help,h", + Usage: "Show the help", + } + + return app.Run(os.Args) +} + +// SutureService allows for the notifications command to be embedded and supervised by a suture supervisor tree. +type SutureService struct { + cfg *config.Config +} + +// NewSutureService creates a new notifications.SutureService +func NewSutureService(cfg *ociscfg.Config) suture.Service { + cfg.Settings.Commons = cfg.Commons + return SutureService{ + cfg: cfg.Notifications, + } +} + +func (s SutureService) Serve(ctx context.Context) error { + s.cfg.Context = ctx + if err := Execute(s.cfg); err != nil { + return err + } + + return nil +} diff --git a/audit/pkg/command/server.go b/audit/pkg/command/server.go new file mode 100644 index 0000000000..37bd6375fd --- /dev/null +++ b/audit/pkg/command/server.go @@ -0,0 +1,50 @@ +package command + +import ( + "fmt" + + "github.com/asim/go-micro/plugins/events/nats/v4" + "github.com/cs3org/reva/v2/pkg/events" + "github.com/cs3org/reva/v2/pkg/events/server" + "github.com/owncloud/ocis/notifications/pkg/channels" + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/notifications/pkg/config/parser" + "github.com/owncloud/ocis/notifications/pkg/logging" + "github.com/owncloud/ocis/notifications/pkg/service" + "github.com/urfave/cli/v2" +) + +// Server is the entrypoint for the server command. +func Server(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "server", + Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name), + Category: "server", + Before: func(c *cli.Context) error { + return parser.ParseConfig(cfg) + }, + Action: func(c *cli.Context) error { + logger := logging.Configure(cfg.Service.Name, cfg.Log) + + evs := []events.Unmarshaller{ + events.ShareCreated{}, + } + + evtsCfg := cfg.Notifications.Events + client, err := server.NewNatsStream(nats.Address(evtsCfg.Endpoint), nats.ClusterID(evtsCfg.Cluster)) + if err != nil { + return err + } + evts, err := events.Consume(client, evtsCfg.ConsumerGroup, evs...) + if err != nil { + return err + } + channel, err := channels.NewMailChannel(*cfg, logger) + if err != nil { + return err + } + svc := service.NewEventsNotifier(evts, channel, logger) + return svc.Run() + }, + } +} diff --git a/audit/pkg/command/version.go b/audit/pkg/command/version.go new file mode 100644 index 0000000000..f2d47a569a --- /dev/null +++ b/audit/pkg/command/version.go @@ -0,0 +1,19 @@ +package command + +import ( + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/urfave/cli/v2" +) + +// Version prints the service versions of all running instances. +func Version(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "version", + Usage: "print the version of this binary and the running extension instances", + Category: "info", + Action: func(c *cli.Context) error { + // not implemented + return nil + }, + } +} diff --git a/audit/pkg/config/config.go b/audit/pkg/config/config.go new file mode 100644 index 0000000000..8ac7da5d8f --- /dev/null +++ b/audit/pkg/config/config.go @@ -0,0 +1,44 @@ +package config + +import ( + "context" + + "github.com/owncloud/ocis/ocis-pkg/shared" +) + +// Config combines all available configuration parts. +type Config struct { + *shared.Commons + + Service Service + + Log *Log `ocisConfig:"log"` + Debug Debug `ocisConfig:"debug"` + + Notifications Notifications `ocisConfig:"notifications"` + + Context context.Context +} + +// Notifications definces the config options for the notifications service. +type Notifications struct { + SMTP SMTP `ocisConfig:"SMTP"` + Events Events `ocisConfig:"events"` + RevaGateway string `ocisConfig:"reva_gateway" env:"REVA_GATEWAY;NOTIFICATIONS_REVA_GATEWAY"` + MachineAuthSecret string `ocisConfig:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;NOTIFICATIONS_MACHINE_AUTH_API_KEY"` +} + +// SMTP combines the smtp configuration options. +type SMTP struct { + Host string `ocisConfig:"smtp_host" env:"NOTIFICATIONS_SMTP_HOST"` + Port string `ocisConfig:"smtp_port" env:"NOTIFICATIONS_SMTP_PORT"` + Sender string `ocisConfig:"smtp_sender" env:"NOTIFICATIONS_SMTP_SENDER"` + Password string `ocisConfig:"smtp_password" env:"NOTIFICATIONS_SMTP_PASSWORD"` +} + +// Events combines the configuration options for the event bus. +type Events struct { + Endpoint string `ocisConfig:"events_endpoint" env:"NOTIFICATIONS_EVENTS_ENDPOINT"` + Cluster string `ocisConfig:"events_cluster" env:"NOTIFICATIONS_EVENTS_CLUSTER"` + ConsumerGroup string `ocisConfig:"events_group" env:"NOTIFICATIONS_EVENTS_GROUP"` +} diff --git a/audit/pkg/config/debug.go b/audit/pkg/config/debug.go new file mode 100644 index 0000000000..da6d2d5906 --- /dev/null +++ b/audit/pkg/config/debug.go @@ -0,0 +1,9 @@ +package config + +// Debug defines the available debug configuration. +type Debug struct { + Addr string `ocisConfig:"addr" env:"NOTIFICATIONS_DEBUG_ADDR"` + Token string `ocisConfig:"token" env:"NOTIFICATIONS_DEBUG_TOKEN"` + Pprof bool `ocisConfig:"pprof" env:"NOTIFICATIONS_DEBUG_PPROF"` + Zpages bool `ocisConfig:"zpages" env:"NOTIFICATIONS_DEBUG_ZPAGES"` +} diff --git a/audit/pkg/config/defaultconfig.go b/audit/pkg/config/defaultconfig.go new file mode 100644 index 0000000000..d5fb6e3498 --- /dev/null +++ b/audit/pkg/config/defaultconfig.go @@ -0,0 +1,27 @@ +package config + +// NOTE: Most of this configuration is not needed to keep it as simple as possible +// TODO: Clean up unneeded configuration + +func DefaultConfig() *Config { + return &Config{ + Service: Service{ + Name: "notifications", + }, + Notifications: Notifications{ + SMTP: SMTP{ + Host: "127.0.0.1", + Port: "1025", + Sender: "god@example.com", + Password: "godisdead", + }, + Events: Events{ + Endpoint: "127.0.0.1:9233", + Cluster: "test-cluster", + ConsumerGroup: "notifications", + }, + RevaGateway: "127.0.0.1:9142", + MachineAuthSecret: "change-me-please", + }, + } +} diff --git a/audit/pkg/config/log.go b/audit/pkg/config/log.go new file mode 100644 index 0000000000..ddb4d391f0 --- /dev/null +++ b/audit/pkg/config/log.go @@ -0,0 +1,9 @@ +package config + +// Log defines the available log configuration. +type Log struct { + Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;NOTIFICATIONS_LOG_LEVEL"` + Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;NOTIFICATIONS_LOG_PRETTY"` + Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;NOTIFICATIONS_LOG_COLOR"` + File string `mapstructure:"file" env:"OCIS_LOG_FILE;NOTIFICATIONS_LOG_FILE"` +} diff --git a/audit/pkg/config/parser/parse.go b/audit/pkg/config/parser/parse.go new file mode 100644 index 0000000000..5bc4e6e571 --- /dev/null +++ b/audit/pkg/config/parser/parse.go @@ -0,0 +1,40 @@ +package parser + +import ( + "errors" + + "github.com/owncloud/ocis/notifications/pkg/config" + ociscfg "github.com/owncloud/ocis/ocis-pkg/config" + + "github.com/owncloud/ocis/ocis-pkg/config/envdecode" +) + +// ParseConfig loads accounts configuration from known paths. +func ParseConfig(cfg *config.Config) error { + _, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg) + if err != nil { + return err + } + + // provide with defaults for shared logging, since we need a valid destination address for BindEnv. + if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil { + cfg.Log = &config.Log{ + Level: cfg.Commons.Log.Level, + Pretty: cfg.Commons.Log.Pretty, + Color: cfg.Commons.Log.Color, + File: cfg.Commons.Log.File, + } + } else if cfg.Log == nil { + cfg.Log = &config.Log{} + } + + // load all env variables relevant to the config in the current context. + if err := envdecode.Decode(cfg); err != nil { + // no environment variable set for this config is an expected "error" + if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) { + return err + } + } + + return nil +} diff --git a/audit/pkg/config/service.go b/audit/pkg/config/service.go new file mode 100644 index 0000000000..f98aa3d27e --- /dev/null +++ b/audit/pkg/config/service.go @@ -0,0 +1,6 @@ +package config + +// Service defines the available service configuration. +type Service struct { + Name string +} diff --git a/audit/pkg/logging/logging.go b/audit/pkg/logging/logging.go new file mode 100644 index 0000000000..039b0451c4 --- /dev/null +++ b/audit/pkg/logging/logging.go @@ -0,0 +1,17 @@ +package logging + +import ( + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// LoggerFromConfig initializes a service-specific logger instance. +func Configure(name string, cfg *config.Log) log.Logger { + return log.NewLogger( + log.Name(name), + log.Level(cfg.Level), + log.Pretty(cfg.Pretty), + log.Color(cfg.Color), + log.File(cfg.File), + ) +} diff --git a/audit/pkg/service/events.go b/audit/pkg/service/events.go new file mode 100644 index 0000000000..7c8a05d235 --- /dev/null +++ b/audit/pkg/service/events.go @@ -0,0 +1,79 @@ +package svc + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/asim/go-micro/plugins/events/nats/v4" + "github.com/cs3org/reva/v2/pkg/events" + "github.com/cs3org/reva/v2/pkg/events/server" + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/audit/pkg/types" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +func startConsumer(c config.Eventstream, log log.Logger) (<-chan interface{}, error) { + s, err := server.NewNatsStream(nats.Address(c.Address), nats.ClusterID(c.ClusterID)) + if err != nil { + return nil, err + } + + return events.Consume(s, "audit", events.ShareCreated{}) +} + +func startAuditLogger(c config.Auditlog, ch <-chan interface{}, log log.Logger) { + for { + i := <-ch + + var auditEvent interface{} + switch ev := i.(type) { + case events.ShareCreated: + auditEvent = types.ShareCreated(ev) + default: + log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev)) + continue + + } + + b, err := marshal(auditEvent, c.Format) + if err != nil { + log.Error().Err(err).Msg("error marshaling the event") + continue + } + + if c.LogToConsole { + log.Info().Msg(string(b)) + } + + if c.LogToFile { + err := writeToFile(c.FilePath, b) + if err != nil { + log.Error().Err(err).Msg("error writing audit log file") + } + } + + } + +} + +func writeToFile(path string, ev []byte) error { + file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + if _, err := fmt.Fprintln(file, string(ev)); err != nil { + return err + } + return nil +} + +func marshal(ev interface{}, format string) ([]byte, error) { + switch format { + default: + return nil, fmt.Errorf("unsupported format '%s'", format) + case "json": + return json.Marshal(ev) + } +} diff --git a/audit/pkg/service/instrument.go b/audit/pkg/service/instrument.go new file mode 100644 index 0000000000..0ebd9af678 --- /dev/null +++ b/audit/pkg/service/instrument.go @@ -0,0 +1,21 @@ +package svc + +/* +// NewInstrument returns a service that instruments metrics. +func NewInstrument(next Service, metrics *metrics.Metrics) Service { + return instrument{ + next: next, + metrics: metrics, + } +} + +type instrument struct { + next Service + metrics *metrics.Metrics +} + +// ListenForEvents implements service interface +func (i instrument) ListenForEvents() { + i.next.ListenForEvents() +} +*/ diff --git a/audit/pkg/service/logging.go b/audit/pkg/service/logging.go new file mode 100644 index 0000000000..355a8ba669 --- /dev/null +++ b/audit/pkg/service/logging.go @@ -0,0 +1,23 @@ +package svc + +import ( + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// NewLogging returns a service that logs messages. +func NewLogging(next Service, logger log.Logger) Service { + return logging{ + next: next, + logger: logger, + } +} + +type logging struct { + next Service + logger log.Logger +} + +// ListenForEvents implements service interface +func (l logging) ListenForEvents() { + l.next.ListenForEvents() +} diff --git a/audit/pkg/service/option.go b/audit/pkg/service/option.go new file mode 100644 index 0000000000..ecca7d139d --- /dev/null +++ b/audit/pkg/service/option.go @@ -0,0 +1,50 @@ +package svc + +import ( + "net/http" + + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// Option defines a single option function. +type Option func(o *Options) + +// Options defines the available options for this package. +type Options struct { + Logger log.Logger + Config *config.Config + Middleware []func(http.Handler) http.Handler +} + +// newOptions initializes the available default options. +func newOptions(opts ...Option) Options { + opt := Options{} + + for _, o := range opts { + o(&opt) + } + + return opt +} + +// Logger provides a function to set the logger option. +func Logger(val log.Logger) Option { + return func(o *Options) { + o.Logger = val + } +} + +// Config provides a function to set the config option. +func Config(val *config.Config) Option { + return func(o *Options) { + o.Config = val + } +} + +// Middleware provides a function to set the middleware option. +func Middleware(val ...func(http.Handler) http.Handler) Option { + return func(o *Options) { + o.Middleware = val + } +} diff --git a/audit/pkg/service/service.go b/audit/pkg/service/service.go new file mode 100644 index 0000000000..c115f030a8 --- /dev/null +++ b/audit/pkg/service/service.go @@ -0,0 +1,48 @@ +package svc + +import ( + "github.com/go-chi/chi" + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// Service defines the extension handlers. +type Service interface { + ListenForEvents() +} + +// NewService returns a service implementation for Service. +func NewService(opts ...Option) Service { + options := newOptions(opts...) + + m := chi.NewMux() + m.Use(options.Middleware...) + + svc := Audit{ + logger: options.Logger, + config: options.Config, + mux: m, + } + + go svc.ListenForEvents() + return svc +} + +// Audit defines implements the business logic for Service. +type Audit struct { + logger log.Logger + config *config.Config + mux *chi.Mux +} + +// ListenForEvents hooks into event queue and logs interesting events +func (g Audit) ListenForEvents() { + log := g.logger + ch, err := startConsumer(g.config.Eventstream, log) + if err != nil { + log.Fatal().Err(err).Msg("can't listen for events") + return + } + + startAuditLogger(g.config.Auditlog, ch, log) +} diff --git a/audit/pkg/service/tracing.go b/audit/pkg/service/tracing.go new file mode 100644 index 0000000000..87b5ac392b --- /dev/null +++ b/audit/pkg/service/tracing.go @@ -0,0 +1,17 @@ +package svc + +// NewTracing returns a service that instruments traces. +func NewTracing(next Service) Service { + return tracing{ + next: next, + } +} + +type tracing struct { + next Service +} + +// ListenForEvents implements service interface +func (t tracing) ListenForEvents() { + t.next.ListenForEvents() +} diff --git a/audit/pkg/types/conversion.go b/audit/pkg/types/conversion.go new file mode 100644 index 0000000000..c4ab66f5e4 --- /dev/null +++ b/audit/pkg/types/conversion.go @@ -0,0 +1,79 @@ +package types + +import ( + "fmt" + "time" + + "github.com/cs3org/reva/v2/pkg/events" +) + +// actions +const ( + actionShareCreated = "file_shared" +) + +// messages +const ( + messageShareCreated = "user '%s' shared file '%s' with '%s'" +) + +// BasicAuditEvent creates an AuditEvent from given values +func BasicAuditEvent(uid string, ctime string, msg string, action string) AuditEvent { + return AuditEvent{ + User: uid, + Time: ctime, + App: "admin_audit", + Message: msg, + Action: action, + Level: 1, + + // NOTE: those values are not in the events and can therefore not be filled at the moment + RemoteAddr: "", + URL: "", + Method: "", + UserAgent: "", + CLI: false, + } +} + +// SharingAuditEvent creates an AuditEventSharing from given values +func SharingAuditEvent(fileid string, uid string, base AuditEvent) AuditEventSharing { + return AuditEventSharing{ + AuditEvent: base, + FileID: fileid, + Owner: uid, + + // NOTE: those values are not in the events and can therefore not be filled at the moment + ShareID: "", + Path: "", + } +} + +// ShareCreated converts a ShareCreated Event to an AuditEventShareCreated +func ShareCreated(ev events.ShareCreated) AuditEventShareCreated { + with := "" + typ := "" + if ev.GranteeUserID != nil && ev.GranteeUserID.OpaqueId != "" { + with = ev.GranteeUserID.OpaqueId + typ = "user" + } else if ev.GranteeGroupID != nil && ev.GranteeGroupID.OpaqueId != "" { + with = ev.GranteeGroupID.OpaqueId + typ = "group" + } + uid := ev.Sharer.OpaqueId + t := time.Unix(int64(ev.CTime.Seconds), int64(ev.CTime.Nanos)).Format(time.RFC3339) + base := BasicAuditEvent(uid, t, fmt.Sprintf(messageShareCreated, uid, ev.ItemID.OpaqueId, with), actionShareCreated) + return AuditEventShareCreated{ + AuditEventSharing: SharingAuditEvent(ev.ItemID.OpaqueId, uid, base), + ShareOwner: uid, + ShareWith: with, + ShareType: typ, + + // NOTE: those values are not in the events and can therefore not be filled at the moment + ItemType: "", + ExpirationDate: "", + SharePass: false, + Permissions: "", + ShareToken: "", + } +} diff --git a/audit/pkg/types/types.go b/audit/pkg/types/types.go new file mode 100644 index 0000000000..cd07e994f0 --- /dev/null +++ b/audit/pkg/types/types.go @@ -0,0 +1,40 @@ +package types + +// AuditEvent is the basic audit event +type AuditEvent struct { + RemoteAddr string // the remote client IP + User string // the UID of the user performing the action. Or "IP x.x.x.x.", "cron", "CLI", "unknown" + URL string // the process request URI + Method string // the HTTP request method + UserAgent string // the HTTP request user agent + Time string // the time of the event eg: 2018-05-08T08:26:00+00:00 + App string // always 'admin_audit' + Message string // sentence explaining the action + Action string // unique action identifier eg: file_delete or public_link_created + CLI bool // if the action was performed from the CLI + Level int // the log level of the entry (usually 1 for audit events) +} + +// AuditEventSharing is the basic audit event for shares +type AuditEventSharing struct { + AuditEvent + + FileID string // The file identifier for the item shared. + Owner string // The UID of the owner of the shared item. + Path string // The path to the shared item. + ShareID string // The sharing identifier. (not available for public_link_accessed or when recipient unshares) +} + +// AuditEventShareCreated is the event logged when a share is created +type AuditEventShareCreated struct { + AuditEventSharing + + ItemType string // file or folder + ExpirationDate string // The text expiration date in format 'yyyy-mm-dd' + SharePass bool // If the share is password protected. + Permissions string // The permissions string eg: "READ" + ShareType string // group user or link + ShareWith string // The UID or GID of the share recipient. (not available for public link) + ShareOwner string // The UID of the share owner. + ShareToken string // For link shares the unique token, else null +} diff --git a/go.mod b/go.mod index 448427b685..538439d5cf 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/cs3org/reva/v2 v2.0.0-20220304131900-b8be80d1ba81 github.com/disintegration/imaging v1.6.2 github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733 + github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/cors v1.2.0 github.com/go-chi/render v1.0.1 @@ -46,6 +47,7 @@ require ( github.com/mennanov/fieldmask-utils v0.5.0 github.com/mitchellh/mapstructure v1.4.3 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 + github.com/nats-io/nats-server/v2 v2.7.3 github.com/nats-io/nats-streaming-server v0.24.2 github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba @@ -208,7 +210,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 // indirect - github.com/nats-io/nats-server/v2 v2.7.3 // indirect github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d // indirect github.com/nats-io/nkeys v0.3.0 // indirect github.com/nats-io/nuid v1.0.1 // indirect From 1609bb3a7c6e9d8e58827f3267197d74746a122b Mon Sep 17 00:00:00 2001 From: jkoberg Date: Tue, 8 Mar 2022 14:44:39 +0100 Subject: [PATCH 2/6] make service start Signed-off-by: jkoberg --- audit/pkg/channels/channels.go | 105 ---------------------------- audit/pkg/command/health.go | 2 +- audit/pkg/command/root.go | 14 ++-- audit/pkg/command/server.go | 20 +++--- audit/pkg/command/version.go | 2 +- audit/pkg/config/config.go | 33 ++++----- audit/pkg/config/defaultconfig.go | 27 +++---- audit/pkg/config/parser/parse.go | 2 +- audit/pkg/logging/logging.go | 2 +- audit/pkg/service/events.go | 79 --------------------- audit/pkg/service/instrument.go | 21 ------ audit/pkg/service/logging.go | 23 ------ audit/pkg/service/option.go | 50 ------------- audit/pkg/service/service.go | 83 ++++++++++++++-------- audit/pkg/service/tracing.go | 17 ----- ocis-pkg/config/config.go | 2 + ocis-pkg/config/defaultconfig.go | 2 + ocis/pkg/command/audit.go | 26 +++++++ ocis/pkg/runtime/service/service.go | 3 + 19 files changed, 126 insertions(+), 387 deletions(-) delete mode 100644 audit/pkg/channels/channels.go delete mode 100644 audit/pkg/service/events.go delete mode 100644 audit/pkg/service/instrument.go delete mode 100644 audit/pkg/service/logging.go delete mode 100644 audit/pkg/service/option.go delete mode 100644 audit/pkg/service/tracing.go create mode 100644 ocis/pkg/command/audit.go diff --git a/audit/pkg/channels/channels.go b/audit/pkg/channels/channels.go deleted file mode 100644 index f13914da45..0000000000 --- a/audit/pkg/channels/channels.go +++ /dev/null @@ -1,105 +0,0 @@ -// Package channels provides different communication channels to notify users. -package channels - -import ( - "context" - "net/smtp" - - gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" - groups "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" - rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" - "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" - "github.com/owncloud/ocis/notifications/pkg/config" - "github.com/owncloud/ocis/ocis-pkg/log" - "github.com/pkg/errors" -) - -// Channel defines the methods of a communication channel. -type Channel interface { - // SendMessage sends a message to users. - SendMessage(userIDs []string, msg string) error - // SendMessageToGroup sends a message to a group. - SendMessageToGroup(groupdID *groups.GroupId, msg string) error -} - -// NewMailChannel instantiates a new mail communication channel. -func NewMailChannel(cfg config.Config, logger log.Logger) (Channel, error) { - gc, err := pool.GetGatewayServiceClient(cfg.Notifications.RevaGateway) - if err != nil { - logger.Error().Err(err).Msg("could not get gateway client") - return nil, err - } - return Mail{ - gatewayClient: gc, - conf: cfg, - logger: logger, - }, nil -} - -// Mail is the communcation channel for email. -type Mail struct { - gatewayClient gateway.GatewayAPIClient - conf config.Config - logger log.Logger -} - -// SendMessage sends a message to all given users. -func (m Mail) SendMessage(userIDs []string, msg string) error { - to, err := m.getReceiverAddresses(userIDs) - if err != nil { - return err - } - body := []byte(msg) - - smtpConf := m.conf.Notifications.SMTP - auth := smtp.PlainAuth("", smtpConf.Sender, smtpConf.Password, smtpConf.Host) - if err := smtp.SendMail(smtpConf.Host+":"+smtpConf.Port, auth, smtpConf.Sender, to, body); err != nil { - return errors.Wrap(err, "could not send mail") - } - return nil -} - -// SendMessageToGroup sends a message to all members of the given group. -func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg string) error { - // TODO We need an authenticated context here... - res, err := m.gatewayClient.GetGroup(context.Background(), &groups.GetGroupRequest{GroupId: groupID}) - if err != nil { - return err - } - if res.Status.Code != rpc.Code_CODE_OK { - return errors.New("could not get group") - } - - members := make([]string, 0, len(res.Group.Members)) - for _, id := range res.Group.Members { - members = append(members, id.OpaqueId) - } - - return m.SendMessage(members, msg) -} - -func (m Mail) getReceiverAddresses(receivers []string) ([]string, error) { - addresses := make([]string, 0, len(receivers)) - for _, id := range receivers { - // Authenticate is too costly but at the moment our only option to get the user. - // We don't have an authenticated context so calling `GetUser` doesn't work. - res, err := m.gatewayClient.Authenticate(context.Background(), &gateway.AuthenticateRequest{ - Type: "machine", - ClientId: "userid:" + id, - ClientSecret: m.conf.Notifications.MachineAuthSecret, - }) - if err != nil { - return nil, err - } - if res.Status.Code != rpc.Code_CODE_OK { - m.logger.Error(). - Interface("status", res.Status). - Str("receiver_id", id). - Msg("could not get user") - continue - } - addresses = append(addresses, res.User.Mail) - } - - return addresses, nil -} diff --git a/audit/pkg/command/health.go b/audit/pkg/command/health.go index 7f2adb85b5..4dbaa30fb5 100644 --- a/audit/pkg/command/health.go +++ b/audit/pkg/command/health.go @@ -1,7 +1,7 @@ package command import ( - "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/audit/pkg/config" "github.com/urfave/cli/v2" ) diff --git a/audit/pkg/command/root.go b/audit/pkg/command/root.go index 805d8cec3a..5c2124f183 100644 --- a/audit/pkg/command/root.go +++ b/audit/pkg/command/root.go @@ -4,7 +4,7 @@ import ( "context" "os" - "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/audit/pkg/config" "github.com/owncloud/ocis/ocis-pkg/clihelper" ociscfg "github.com/owncloud/ocis/ocis-pkg/config" "github.com/thejerf/suture/v4" @@ -25,11 +25,11 @@ func GetCommands(cfg *config.Config) cli.Commands { } } -// Execute is the entry point for the notifications command. +// Execute is the entry point for the audit command. func Execute(cfg *config.Config) error { app := clihelper.DefaultApp(&cli.App{ - Name: "notifications", - Usage: "starts notifications service", + Name: "audit", + Usage: "starts audit service", Commands: GetCommands(cfg), }) @@ -41,16 +41,16 @@ func Execute(cfg *config.Config) error { return app.Run(os.Args) } -// SutureService allows for the notifications command to be embedded and supervised by a suture supervisor tree. +// SutureService allows for the audit command to be embedded and supervised by a suture supervisor tree. type SutureService struct { cfg *config.Config } -// NewSutureService creates a new notifications.SutureService +// NewSutureService creates a new audit.SutureService func NewSutureService(cfg *ociscfg.Config) suture.Service { cfg.Settings.Commons = cfg.Commons return SutureService{ - cfg: cfg.Notifications, + cfg: cfg.Audit, } } diff --git a/audit/pkg/command/server.go b/audit/pkg/command/server.go index 37bd6375fd..b88ab633f9 100644 --- a/audit/pkg/command/server.go +++ b/audit/pkg/command/server.go @@ -6,11 +6,10 @@ import ( "github.com/asim/go-micro/plugins/events/nats/v4" "github.com/cs3org/reva/v2/pkg/events" "github.com/cs3org/reva/v2/pkg/events/server" - "github.com/owncloud/ocis/notifications/pkg/channels" - "github.com/owncloud/ocis/notifications/pkg/config" - "github.com/owncloud/ocis/notifications/pkg/config/parser" - "github.com/owncloud/ocis/notifications/pkg/logging" - "github.com/owncloud/ocis/notifications/pkg/service" + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/audit/pkg/config/parser" + "github.com/owncloud/ocis/audit/pkg/logging" + svc "github.com/owncloud/ocis/audit/pkg/service" "github.com/urfave/cli/v2" ) @@ -30,7 +29,7 @@ func Server(cfg *config.Config) *cli.Command { events.ShareCreated{}, } - evtsCfg := cfg.Notifications.Events + evtsCfg := cfg.Events client, err := server.NewNatsStream(nats.Address(evtsCfg.Endpoint), nats.ClusterID(evtsCfg.Cluster)) if err != nil { return err @@ -39,12 +38,9 @@ func Server(cfg *config.Config) *cli.Command { if err != nil { return err } - channel, err := channels.NewMailChannel(*cfg, logger) - if err != nil { - return err - } - svc := service.NewEventsNotifier(evts, channel, logger) - return svc.Run() + + svc.StartAuditLogger(cfg.Auditlog, evts, logger) + return nil }, } } diff --git a/audit/pkg/command/version.go b/audit/pkg/command/version.go index f2d47a569a..db018de572 100644 --- a/audit/pkg/command/version.go +++ b/audit/pkg/command/version.go @@ -1,7 +1,7 @@ package command import ( - "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/audit/pkg/config" "github.com/urfave/cli/v2" ) diff --git a/audit/pkg/config/config.go b/audit/pkg/config/config.go index 8ac7da5d8f..3f72ddab0f 100644 --- a/audit/pkg/config/config.go +++ b/audit/pkg/config/config.go @@ -15,30 +15,23 @@ type Config struct { Log *Log `ocisConfig:"log"` Debug Debug `ocisConfig:"debug"` - Notifications Notifications `ocisConfig:"notifications"` + Events Events `ocisConfig:"events"` + Auditlog Auditlog `ocisConfig:"auditlog"` Context context.Context } -// Notifications definces the config options for the notifications service. -type Notifications struct { - SMTP SMTP `ocisConfig:"SMTP"` - Events Events `ocisConfig:"events"` - RevaGateway string `ocisConfig:"reva_gateway" env:"REVA_GATEWAY;NOTIFICATIONS_REVA_GATEWAY"` - MachineAuthSecret string `ocisConfig:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;NOTIFICATIONS_MACHINE_AUTH_API_KEY"` -} - -// SMTP combines the smtp configuration options. -type SMTP struct { - Host string `ocisConfig:"smtp_host" env:"NOTIFICATIONS_SMTP_HOST"` - Port string `ocisConfig:"smtp_port" env:"NOTIFICATIONS_SMTP_PORT"` - Sender string `ocisConfig:"smtp_sender" env:"NOTIFICATIONS_SMTP_SENDER"` - Password string `ocisConfig:"smtp_password" env:"NOTIFICATIONS_SMTP_PASSWORD"` -} - // Events combines the configuration options for the event bus. type Events struct { - Endpoint string `ocisConfig:"events_endpoint" env:"NOTIFICATIONS_EVENTS_ENDPOINT"` - Cluster string `ocisConfig:"events_cluster" env:"NOTIFICATIONS_EVENTS_CLUSTER"` - ConsumerGroup string `ocisConfig:"events_group" env:"NOTIFICATIONS_EVENTS_GROUP"` + Endpoint string `ocisConfig:"events_endpoint" env:"AUDIT_EVENTS_ENDPOINT"` + Cluster string `ocisConfig:"events_cluster" env:"AUDIT_EVENTS_CLUSTER"` + ConsumerGroup string `ocisConfig:"events_group" env:"AUDIT_EVENTS_GROUP"` +} + +// Auditlog holds audit log information +type Auditlog struct { + LogToConsole bool `ocisConfig:"log_to_console" env:"AUDIT_LOG_TO_CONSOLE"` + LogToFile bool `ocisConfig:"log_to_file" env:"AUDIT_LOG_TO_FILE"` + FilePath string `ocisConfig:"filepath" env:"AUDIT_FILEPATH"` + Format string `ocisConfig:"format" env:"AUDIT_FORMAT"` } diff --git a/audit/pkg/config/defaultconfig.go b/audit/pkg/config/defaultconfig.go index d5fb6e3498..7988ab3fd1 100644 --- a/audit/pkg/config/defaultconfig.go +++ b/audit/pkg/config/defaultconfig.go @@ -1,27 +1,18 @@ package config -// NOTE: Most of this configuration is not needed to keep it as simple as possible -// TODO: Clean up unneeded configuration - func DefaultConfig() *Config { return &Config{ Service: Service{ - Name: "notifications", + Name: "audit", }, - Notifications: Notifications{ - SMTP: SMTP{ - Host: "127.0.0.1", - Port: "1025", - Sender: "god@example.com", - Password: "godisdead", - }, - Events: Events{ - Endpoint: "127.0.0.1:9233", - Cluster: "test-cluster", - ConsumerGroup: "notifications", - }, - RevaGateway: "127.0.0.1:9142", - MachineAuthSecret: "change-me-please", + Events: Events{ + Endpoint: "127.0.0.1:9233", + Cluster: "test-cluster", + ConsumerGroup: "audit", + }, + Auditlog: Auditlog{ + LogToConsole: true, + Format: "json", }, } } diff --git a/audit/pkg/config/parser/parse.go b/audit/pkg/config/parser/parse.go index 5bc4e6e571..6bcaf0ad75 100644 --- a/audit/pkg/config/parser/parse.go +++ b/audit/pkg/config/parser/parse.go @@ -3,7 +3,7 @@ package parser import ( "errors" - "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/audit/pkg/config" ociscfg "github.com/owncloud/ocis/ocis-pkg/config" "github.com/owncloud/ocis/ocis-pkg/config/envdecode" diff --git a/audit/pkg/logging/logging.go b/audit/pkg/logging/logging.go index 039b0451c4..4b415776fc 100644 --- a/audit/pkg/logging/logging.go +++ b/audit/pkg/logging/logging.go @@ -1,7 +1,7 @@ package logging import ( - "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/audit/pkg/config" "github.com/owncloud/ocis/ocis-pkg/log" ) diff --git a/audit/pkg/service/events.go b/audit/pkg/service/events.go deleted file mode 100644 index 7c8a05d235..0000000000 --- a/audit/pkg/service/events.go +++ /dev/null @@ -1,79 +0,0 @@ -package svc - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/asim/go-micro/plugins/events/nats/v4" - "github.com/cs3org/reva/v2/pkg/events" - "github.com/cs3org/reva/v2/pkg/events/server" - "github.com/owncloud/ocis/audit/pkg/config" - "github.com/owncloud/ocis/audit/pkg/types" - "github.com/owncloud/ocis/ocis-pkg/log" -) - -func startConsumer(c config.Eventstream, log log.Logger) (<-chan interface{}, error) { - s, err := server.NewNatsStream(nats.Address(c.Address), nats.ClusterID(c.ClusterID)) - if err != nil { - return nil, err - } - - return events.Consume(s, "audit", events.ShareCreated{}) -} - -func startAuditLogger(c config.Auditlog, ch <-chan interface{}, log log.Logger) { - for { - i := <-ch - - var auditEvent interface{} - switch ev := i.(type) { - case events.ShareCreated: - auditEvent = types.ShareCreated(ev) - default: - log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev)) - continue - - } - - b, err := marshal(auditEvent, c.Format) - if err != nil { - log.Error().Err(err).Msg("error marshaling the event") - continue - } - - if c.LogToConsole { - log.Info().Msg(string(b)) - } - - if c.LogToFile { - err := writeToFile(c.FilePath, b) - if err != nil { - log.Error().Err(err).Msg("error writing audit log file") - } - } - - } - -} - -func writeToFile(path string, ev []byte) error { - file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer file.Close() - if _, err := fmt.Fprintln(file, string(ev)); err != nil { - return err - } - return nil -} - -func marshal(ev interface{}, format string) ([]byte, error) { - switch format { - default: - return nil, fmt.Errorf("unsupported format '%s'", format) - case "json": - return json.Marshal(ev) - } -} diff --git a/audit/pkg/service/instrument.go b/audit/pkg/service/instrument.go deleted file mode 100644 index 0ebd9af678..0000000000 --- a/audit/pkg/service/instrument.go +++ /dev/null @@ -1,21 +0,0 @@ -package svc - -/* -// NewInstrument returns a service that instruments metrics. -func NewInstrument(next Service, metrics *metrics.Metrics) Service { - return instrument{ - next: next, - metrics: metrics, - } -} - -type instrument struct { - next Service - metrics *metrics.Metrics -} - -// ListenForEvents implements service interface -func (i instrument) ListenForEvents() { - i.next.ListenForEvents() -} -*/ diff --git a/audit/pkg/service/logging.go b/audit/pkg/service/logging.go deleted file mode 100644 index 355a8ba669..0000000000 --- a/audit/pkg/service/logging.go +++ /dev/null @@ -1,23 +0,0 @@ -package svc - -import ( - "github.com/owncloud/ocis/ocis-pkg/log" -) - -// NewLogging returns a service that logs messages. -func NewLogging(next Service, logger log.Logger) Service { - return logging{ - next: next, - logger: logger, - } -} - -type logging struct { - next Service - logger log.Logger -} - -// ListenForEvents implements service interface -func (l logging) ListenForEvents() { - l.next.ListenForEvents() -} diff --git a/audit/pkg/service/option.go b/audit/pkg/service/option.go deleted file mode 100644 index ecca7d139d..0000000000 --- a/audit/pkg/service/option.go +++ /dev/null @@ -1,50 +0,0 @@ -package svc - -import ( - "net/http" - - "github.com/owncloud/ocis/audit/pkg/config" - "github.com/owncloud/ocis/ocis-pkg/log" -) - -// Option defines a single option function. -type Option func(o *Options) - -// Options defines the available options for this package. -type Options struct { - Logger log.Logger - Config *config.Config - Middleware []func(http.Handler) http.Handler -} - -// newOptions initializes the available default options. -func newOptions(opts ...Option) Options { - opt := Options{} - - for _, o := range opts { - o(&opt) - } - - return opt -} - -// Logger provides a function to set the logger option. -func Logger(val log.Logger) Option { - return func(o *Options) { - o.Logger = val - } -} - -// Config provides a function to set the config option. -func Config(val *config.Config) Option { - return func(o *Options) { - o.Config = val - } -} - -// Middleware provides a function to set the middleware option. -func Middleware(val ...func(http.Handler) http.Handler) Option { - return func(o *Options) { - o.Middleware = val - } -} diff --git a/audit/pkg/service/service.go b/audit/pkg/service/service.go index c115f030a8..0fc90ae590 100644 --- a/audit/pkg/service/service.go +++ b/audit/pkg/service/service.go @@ -1,48 +1,69 @@ package svc import ( - "github.com/go-chi/chi" + "encoding/json" + "fmt" + "os" + + "github.com/cs3org/reva/v2/pkg/events" "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/audit/pkg/types" "github.com/owncloud/ocis/ocis-pkg/log" ) -// Service defines the extension handlers. -type Service interface { - ListenForEvents() -} +// StartAuditLogger starts the audit logger +func StartAuditLogger(c config.Auditlog, ch <-chan interface{}, log log.Logger) { + for { + i := <-ch -// NewService returns a service implementation for Service. -func NewService(opts ...Option) Service { - options := newOptions(opts...) + var auditEvent interface{} + switch ev := i.(type) { + case events.ShareCreated: + auditEvent = types.ShareCreated(ev) + default: + log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev)) + continue - m := chi.NewMux() - m.Use(options.Middleware...) + } + + b, err := marshal(auditEvent, c.Format) + if err != nil { + log.Error().Err(err).Msg("error marshaling the event") + continue + } + + if c.LogToConsole { + log.Error().Msg(string(b)) + } + + if c.LogToFile { + err := writeToFile(c.FilePath, b) + if err != nil { + log.Error().Err(err).Msg("error writing audit log file") + } + } - svc := Audit{ - logger: options.Logger, - config: options.Config, - mux: m, } - go svc.ListenForEvents() - return svc } -// Audit defines implements the business logic for Service. -type Audit struct { - logger log.Logger - config *config.Config - mux *chi.Mux -} - -// ListenForEvents hooks into event queue and logs interesting events -func (g Audit) ListenForEvents() { - log := g.logger - ch, err := startConsumer(g.config.Eventstream, log) +func writeToFile(path string, ev []byte) error { + file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { - log.Fatal().Err(err).Msg("can't listen for events") - return + return err + } + defer file.Close() + if _, err := fmt.Fprintln(file, string(ev)); err != nil { + return err + } + return nil +} + +func marshal(ev interface{}, format string) ([]byte, error) { + switch format { + default: + return nil, fmt.Errorf("unsupported format '%s'", format) + case "json": + return json.Marshal(ev) } - - startAuditLogger(g.config.Auditlog, ch, log) } diff --git a/audit/pkg/service/tracing.go b/audit/pkg/service/tracing.go deleted file mode 100644 index 87b5ac392b..0000000000 --- a/audit/pkg/service/tracing.go +++ /dev/null @@ -1,17 +0,0 @@ -package svc - -// NewTracing returns a service that instruments traces. -func NewTracing(next Service) Service { - return tracing{ - next: next, - } -} - -type tracing struct { - next Service -} - -// ListenForEvents implements service interface -func (t tracing) ListenForEvents() { - t.next.ListenForEvents() -} diff --git a/ocis-pkg/config/config.go b/ocis-pkg/config/config.go index 2f0495b1f8..5b5dee900d 100644 --- a/ocis-pkg/config/config.go +++ b/ocis-pkg/config/config.go @@ -4,6 +4,7 @@ import ( "github.com/owncloud/ocis/ocis-pkg/shared" accounts "github.com/owncloud/ocis/accounts/pkg/config" + audit "github.com/owncloud/ocis/audit/pkg/config" glauth "github.com/owncloud/ocis/glauth/pkg/config" graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/config" graph "github.com/owncloud/ocis/graph/pkg/config" @@ -58,6 +59,7 @@ type Config struct { TokenManager TokenManager `ocisConfig:"token_manager"` Runtime Runtime `ocisConfig:"runtime"` + Audit *audit.Config `ocsiConfig:"audit"` Accounts *accounts.Config `ocisConfig:"accounts"` GLAuth *glauth.Config `ocisConfig:"glauth"` Graph *graph.Config `ocisConfig:"graph"` diff --git a/ocis-pkg/config/defaultconfig.go b/ocis-pkg/config/defaultconfig.go index 222b04b0fb..64e4df1829 100644 --- a/ocis-pkg/config/defaultconfig.go +++ b/ocis-pkg/config/defaultconfig.go @@ -2,6 +2,7 @@ package config import ( accounts "github.com/owncloud/ocis/accounts/pkg/config" + audit "github.com/owncloud/ocis/audit/pkg/config" glauth "github.com/owncloud/ocis/glauth/pkg/config" graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/config" graph "github.com/owncloud/ocis/graph/pkg/config" @@ -28,6 +29,7 @@ func DefaultConfig() *Config { Port: "9250", Host: "localhost", }, + Audit: audit.DefaultConfig(), Accounts: accounts.DefaultConfig(), GLAuth: glauth.DefaultConfig(), Graph: graph.DefaultConfig(), diff --git a/ocis/pkg/command/audit.go b/ocis/pkg/command/audit.go new file mode 100644 index 0000000000..02fbb7a314 --- /dev/null +++ b/ocis/pkg/command/audit.go @@ -0,0 +1,26 @@ +package command + +import ( + "github.com/owncloud/ocis/audit/pkg/command" + "github.com/owncloud/ocis/ocis-pkg/config" + "github.com/owncloud/ocis/ocis-pkg/config/parser" + "github.com/owncloud/ocis/ocis/pkg/register" + "github.com/urfave/cli/v2" +) + +// AuditCommand is the entrypoint for the audit command. +func AuditCommand(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "audit", + Usage: "start audit service", + Category: "extensions", + Before: func(ctx *cli.Context) error { + return parser.ParseConfig(cfg) + }, + Subcommands: command.GetCommands(cfg.Audit), + } +} + +func init() { + register.AddCommand(AuditCommand) +} diff --git a/ocis/pkg/runtime/service/service.go b/ocis/pkg/runtime/service/service.go index c055f31046..139de8b5bb 100644 --- a/ocis/pkg/runtime/service/service.go +++ b/ocis/pkg/runtime/service/service.go @@ -18,7 +18,9 @@ import ( mzlog "github.com/asim/go-micro/plugins/logger/zerolog/v4" "github.com/mohae/deepcopy" "github.com/olekukonko/tablewriter" + accounts "github.com/owncloud/ocis/accounts/pkg/command" + audit "github.com/owncloud/ocis/audit/pkg/command" glauth "github.com/owncloud/ocis/glauth/pkg/command" graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/command" graph "github.com/owncloud/ocis/graph/pkg/command" @@ -93,6 +95,7 @@ func NewService(options ...Option) (*Service, error) { cfg: opts.Config, } + s.ServicesRegistry["audit"] = audit.NewSutureService s.ServicesRegistry["settings"] = settings.NewSutureService s.ServicesRegistry["nats"] = nats.NewSutureService s.ServicesRegistry["storage-metadata"] = storage.NewStorageMetadata From 773ada68738c9671989a7900daa2944a5a7d4484 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Tue, 8 Mar 2022 15:41:49 +0100 Subject: [PATCH 3/6] refactor audit logging Signed-off-by: jkoberg --- audit/pkg/command/server.go | 2 +- audit/pkg/service/service.go | 76 ++++++++++++++++++++++++------------ 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/audit/pkg/command/server.go b/audit/pkg/command/server.go index b88ab633f9..66609780a3 100644 --- a/audit/pkg/command/server.go +++ b/audit/pkg/command/server.go @@ -39,7 +39,7 @@ func Server(cfg *config.Config) *cli.Command { return err } - svc.StartAuditLogger(cfg.Auditlog, evts, logger) + svc.AuditLoggerFromConfig(cfg.Auditlog, evts, logger) return nil }, } diff --git a/audit/pkg/service/service.go b/audit/pkg/service/service.go index 0fc90ae590..b0f8703f82 100644 --- a/audit/pkg/service/service.go +++ b/audit/pkg/service/service.go @@ -11,8 +11,30 @@ import ( "github.com/owncloud/ocis/ocis-pkg/log" ) -// StartAuditLogger starts the audit logger -func StartAuditLogger(c config.Auditlog, ch <-chan interface{}, log log.Logger) { +// Log is used to log to different outputs +type Log func([]byte) + +// Marshaller is used to marshal events +type Marshaller func(interface{}) ([]byte, error) + +// AuditLoggerFromConfig will start a new AuditLogger generated from the config +func AuditLoggerFromConfig(cfg config.Auditlog, ch <-chan interface{}, log log.Logger) { + var logs []Log + + if cfg.LogToConsole { + logs = append(logs, WriteToStdout()) + } + + if cfg.LogToFile { + logs = append(logs, WriteToFile(cfg.FilePath, log)) + } + + StartAuditLogger(ch, log, Marshal(cfg.Format, log), logs...) + +} + +// StartAuditLogger will block. run in seperate go routine +func StartAuditLogger(ch <-chan interface{}, log log.Logger, marshaller Marshaller, logto ...Log) { for { i := <-ch @@ -26,44 +48,48 @@ func StartAuditLogger(c config.Auditlog, ch <-chan interface{}, log log.Logger) } - b, err := marshal(auditEvent, c.Format) + b, err := marshaller(auditEvent) if err != nil { log.Error().Err(err).Msg("error marshaling the event") continue } - if c.LogToConsole { - log.Error().Msg(string(b)) + for _, l := range logto { + l(b) } - - if c.LogToFile { - err := writeToFile(c.FilePath, b) - if err != nil { - log.Error().Err(err).Msg("error writing audit log file") - } - } - } } -func writeToFile(path string, ev []byte) error { - file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) - if err != nil { - return err +// WriteToFile returns a Log function writing to a file +func WriteToFile(path string, log log.Logger) Log { + return func(content []byte) { + file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + log.Error().Err(err).Msgf("error opening file '%s'", path) + return + } + defer file.Close() + if _, err := fmt.Fprintln(file, string(content)); err != nil { + log.Error().Err(err).Msgf("error writing to file '%s'", path) + } } - defer file.Close() - if _, err := fmt.Fprintln(file, string(ev)); err != nil { - return err - } - return nil } -func marshal(ev interface{}, format string) ([]byte, error) { +// WriteToStdout return a Log function writing to Stdout +func WriteToStdout() Log { + return func(content []byte) { + fmt.Println(string(content)) + } +} + +// Marshal returns a Marshaller from the `format` string +func Marshal(format string, log log.Logger) Marshaller { switch format { default: - return nil, fmt.Errorf("unsupported format '%s'", format) + log.Error().Msgf("unknown format '%s'", format) + return nil case "json": - return json.Marshal(ev) + return json.Marshal } } From 70afcf52eb9e8e5e8c84f4a9e397af58813cd507 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Tue, 8 Mar 2022 16:16:55 +0100 Subject: [PATCH 4/6] unit test for audit service Signed-off-by: jkoberg --- audit/pkg/service/service.go | 42 +++++++++-------- audit/pkg/service/service_test.go | 76 +++++++++++++++++++++++++++++++ go.mod | 2 +- 3 files changed, 100 insertions(+), 20 deletions(-) create mode 100644 audit/pkg/service/service_test.go diff --git a/audit/pkg/service/service.go b/audit/pkg/service/service.go index b0f8703f82..5042b716bf 100644 --- a/audit/pkg/service/service.go +++ b/audit/pkg/service/service.go @@ -1,6 +1,7 @@ package svc import ( + "context" "encoding/json" "fmt" "os" @@ -29,33 +30,36 @@ func AuditLoggerFromConfig(cfg config.Auditlog, ch <-chan interface{}, log log.L logs = append(logs, WriteToFile(cfg.FilePath, log)) } - StartAuditLogger(ch, log, Marshal(cfg.Format, log), logs...) + StartAuditLogger(context.TODO(), ch, log, Marshal(cfg.Format, log), logs...) } // StartAuditLogger will block. run in seperate go routine -func StartAuditLogger(ch <-chan interface{}, log log.Logger, marshaller Marshaller, logto ...Log) { +func StartAuditLogger(ctx context.Context, ch <-chan interface{}, log log.Logger, marshaller Marshaller, logto ...Log) { for { - i := <-ch + select { + case <-ctx.Done(): + return + case i := <-ch: + var auditEvent interface{} + switch ev := i.(type) { + case events.ShareCreated: + auditEvent = types.ShareCreated(ev) + default: + log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev)) + continue - var auditEvent interface{} - switch ev := i.(type) { - case events.ShareCreated: - auditEvent = types.ShareCreated(ev) - default: - log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev)) - continue + } - } + b, err := marshaller(auditEvent) + if err != nil { + log.Error().Err(err).Msg("error marshaling the event") + continue + } - b, err := marshaller(auditEvent) - if err != nil { - log.Error().Err(err).Msg("error marshaling the event") - continue - } - - for _, l := range logto { - l(b) + for _, l := range logto { + l(b) + } } } diff --git a/audit/pkg/service/service_test.go b/audit/pkg/service/service_test.go new file mode 100644 index 0000000000..a4cd2e00e6 --- /dev/null +++ b/audit/pkg/service/service_test.go @@ -0,0 +1,76 @@ +package svc + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/cs3org/reva/v2/pkg/events" + "github.com/owncloud/ocis/audit/pkg/types" + "github.com/owncloud/ocis/ocis-pkg/log" + "github.com/test-go/testify/require" + + group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" + user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + rtypes "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" +) + +var testCases = []struct { + Alias string + SystemEvent interface{} + CheckAuditEvent func(t *testing.T) Log +}{ + { + Alias: "ShareCreated", + SystemEvent: events.ShareCreated{ + Sharer: &user.UserId{ + OpaqueId: "sharing-userid", + Idp: "idp", + }, + GranteeUserID: &user.UserId{ + OpaqueId: "beshared-userid", + Idp: "idp", + }, + GranteeGroupID: &group.GroupId{}, + Sharee: &provider.Grantee{}, + ItemID: &provider.ResourceId{ + StorageId: "storage-1", + OpaqueId: "itemid-1", + }, + CTime: &rtypes.Timestamp{ + Seconds: 0, + Nanos: 0, + }, + }, + CheckAuditEvent: func(t *testing.T) Log { + return func(b []byte) { + ev := types.AuditEventShareCreated{} + err := json.Unmarshal(b, &ev) + require.NoError(t, err) + + require.Equal(t, ev.User, "sharing-userid") + require.Equal(t, ev.ShareWith, "beshared-userid") + require.Equal(t, ev.FileID, "itemid-1") + require.Equal(t, ev.Time, "1970-01-01T01:00:00+01:00") + + } + }, + }, +} + +func TestAuditLogging(t *testing.T) { + log := log.NewLogger() + + for _, tc := range testCases { + ch := make(chan interface{}) + ctx, cancel := context.WithCancel(context.TODO()) + go StartAuditLogger(ctx, ch, log, Marshal("json", log), tc.CheckAuditEvent(t)) + ch <- tc.SystemEvent + cancel() + } + + // wait for events to be checked + time.Sleep(time.Second) +} diff --git a/go.mod b/go.mod index 538439d5cf..1d478fd73e 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,6 @@ require ( github.com/cs3org/reva/v2 v2.0.0-20220304131900-b8be80d1ba81 github.com/disintegration/imaging v1.6.2 github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733 - github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/cors v1.2.0 github.com/go-chi/render v1.0.1 @@ -62,6 +61,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.7.0 + github.com/test-go/testify v1.1.4 github.com/thejerf/suture/v4 v4.0.2 github.com/urfave/cli/v2 v2.3.0 go-micro.dev/v4 v4.6.0 From 7c85fafb54d04d3712bbea1ec39720e73b65edfc Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 9 Mar 2022 10:11:27 +0100 Subject: [PATCH 5/6] final touches Signed-off-by: jkoberg --- audit/pkg/command/server.go | 13 ++++++--- audit/pkg/service/service.go | 4 +-- audit/pkg/service/service_test.go | 46 +++++++++++++++++-------------- audit/pkg/types/events.go | 12 ++++++++ 4 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 audit/pkg/types/events.go diff --git a/audit/pkg/command/server.go b/audit/pkg/command/server.go index 66609780a3..e74f09ff4b 100644 --- a/audit/pkg/command/server.go +++ b/audit/pkg/command/server.go @@ -1,6 +1,7 @@ package command import ( + "context" "fmt" "github.com/asim/go-micro/plugins/events/nats/v4" @@ -10,6 +11,7 @@ import ( "github.com/owncloud/ocis/audit/pkg/config/parser" "github.com/owncloud/ocis/audit/pkg/logging" svc "github.com/owncloud/ocis/audit/pkg/service" + "github.com/owncloud/ocis/audit/pkg/types" "github.com/urfave/cli/v2" ) @@ -25,21 +27,24 @@ func Server(cfg *config.Config) *cli.Command { Action: func(c *cli.Context) error { logger := logging.Configure(cfg.Service.Name, cfg.Log) - evs := []events.Unmarshaller{ - events.ShareCreated{}, + ctx := cfg.Context + if ctx == nil { + ctx = context.Background() } + ctx, cancel := context.WithCancel(ctx) + defer cancel() evtsCfg := cfg.Events client, err := server.NewNatsStream(nats.Address(evtsCfg.Endpoint), nats.ClusterID(evtsCfg.Cluster)) if err != nil { return err } - evts, err := events.Consume(client, evtsCfg.ConsumerGroup, evs...) + evts, err := events.Consume(client, evtsCfg.ConsumerGroup, types.RegisteredEvents()...) if err != nil { return err } - svc.AuditLoggerFromConfig(cfg.Auditlog, evts, logger) + svc.AuditLoggerFromConfig(ctx, cfg.Auditlog, evts, logger) return nil }, } diff --git a/audit/pkg/service/service.go b/audit/pkg/service/service.go index 5042b716bf..4f1f4b1aab 100644 --- a/audit/pkg/service/service.go +++ b/audit/pkg/service/service.go @@ -19,7 +19,7 @@ type Log func([]byte) type Marshaller func(interface{}) ([]byte, error) // AuditLoggerFromConfig will start a new AuditLogger generated from the config -func AuditLoggerFromConfig(cfg config.Auditlog, ch <-chan interface{}, log log.Logger) { +func AuditLoggerFromConfig(ctx context.Context, cfg config.Auditlog, ch <-chan interface{}, log log.Logger) { var logs []Log if cfg.LogToConsole { @@ -30,7 +30,7 @@ func AuditLoggerFromConfig(cfg config.Auditlog, ch <-chan interface{}, log log.L logs = append(logs, WriteToFile(cfg.FilePath, log)) } - StartAuditLogger(context.TODO(), ch, log, Marshal(cfg.Format, log), logs...) + StartAuditLogger(ctx, ch, log, Marshal(cfg.Format, log), logs...) } diff --git a/audit/pkg/service/service_test.go b/audit/pkg/service/service_test.go index a4cd2e00e6..0724acc397 100644 --- a/audit/pkg/service/service_test.go +++ b/audit/pkg/service/service_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "testing" - "time" "github.com/cs3org/reva/v2/pkg/events" "github.com/owncloud/ocis/audit/pkg/types" @@ -20,7 +19,7 @@ import ( var testCases = []struct { Alias string SystemEvent interface{} - CheckAuditEvent func(t *testing.T) Log + CheckAuditEvent func(*testing.T, []byte) }{ { Alias: "ShareCreated", @@ -44,18 +43,16 @@ var testCases = []struct { Nanos: 0, }, }, - CheckAuditEvent: func(t *testing.T) Log { - return func(b []byte) { - ev := types.AuditEventShareCreated{} - err := json.Unmarshal(b, &ev) - require.NoError(t, err) + CheckAuditEvent: func(t *testing.T, b []byte) { + ev := types.AuditEventShareCreated{} + err := json.Unmarshal(b, &ev) + require.NoError(t, err) - require.Equal(t, ev.User, "sharing-userid") - require.Equal(t, ev.ShareWith, "beshared-userid") - require.Equal(t, ev.FileID, "itemid-1") - require.Equal(t, ev.Time, "1970-01-01T01:00:00+01:00") + require.Equal(t, ev.User, "sharing-userid") + require.Equal(t, ev.ShareWith, "beshared-userid") + require.Equal(t, ev.FileID, "itemid-1") + require.Equal(t, ev.Time, "1970-01-01T01:00:00+01:00") - } }, }, } @@ -63,14 +60,21 @@ var testCases = []struct { func TestAuditLogging(t *testing.T) { log := log.NewLogger() - for _, tc := range testCases { - ch := make(chan interface{}) - ctx, cancel := context.WithCancel(context.TODO()) - go StartAuditLogger(ctx, ch, log, Marshal("json", log), tc.CheckAuditEvent(t)) - ch <- tc.SystemEvent - cancel() - } + inch := make(chan interface{}) + defer close(inch) - // wait for events to be checked - time.Sleep(time.Second) + outch := make(chan []byte) + defer close(outch) + + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + + go StartAuditLogger(ctx, inch, log, Marshal("json", log), func(b []byte) { + outch <- b + }) + + for _, tc := range testCases { + inch <- tc.SystemEvent + tc.CheckAuditEvent(t, <-outch) + } } diff --git a/audit/pkg/types/events.go b/audit/pkg/types/events.go new file mode 100644 index 0000000000..7a9825ef0f --- /dev/null +++ b/audit/pkg/types/events.go @@ -0,0 +1,12 @@ +package types + +import ( + "github.com/cs3org/reva/v2/pkg/events" +) + +// RegisteredEvents returns the events the service is registered for +func RegisteredEvents() []events.Unmarshaller { + return []events.Unmarshaller{ + events.ShareCreated{}, + } +} From cb5e38f4cb7fd8fb1c9dfdbcf11460950a6141c1 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 9 Mar 2022 10:50:19 +0100 Subject: [PATCH 6/6] review suggestions I Signed-off-by: jkoberg --- audit/pkg/config/config.go | 14 +++++++------- audit/pkg/config/debug.go | 8 ++++---- audit/pkg/config/log.go | 8 ++++---- ocis/pkg/runtime/service/service.go | 2 -- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/audit/pkg/config/config.go b/audit/pkg/config/config.go index 3f72ddab0f..2041e52bcc 100644 --- a/audit/pkg/config/config.go +++ b/audit/pkg/config/config.go @@ -23,15 +23,15 @@ type Config struct { // Events combines the configuration options for the event bus. type Events struct { - Endpoint string `ocisConfig:"events_endpoint" env:"AUDIT_EVENTS_ENDPOINT"` - Cluster string `ocisConfig:"events_cluster" env:"AUDIT_EVENTS_CLUSTER"` - ConsumerGroup string `ocisConfig:"events_group" env:"AUDIT_EVENTS_GROUP"` + Endpoint string `ocisConfig:"events_endpoint" env:"AUDIT_EVENTS_ENDPOINT" desc:"the address of the streaming service"` + Cluster string `ocisConfig:"events_cluster" env:"AUDIT_EVENTS_CLUSTER" desc:"the clusterID of the streaming service. Mandatory when using nats"` + ConsumerGroup string `ocisConfig:"events_group" env:"AUDIT_EVENTS_GROUP" desc:"the customergroup of the service. One group will only get one vopy of an event"` } // Auditlog holds audit log information type Auditlog struct { - LogToConsole bool `ocisConfig:"log_to_console" env:"AUDIT_LOG_TO_CONSOLE"` - LogToFile bool `ocisConfig:"log_to_file" env:"AUDIT_LOG_TO_FILE"` - FilePath string `ocisConfig:"filepath" env:"AUDIT_FILEPATH"` - Format string `ocisConfig:"format" env:"AUDIT_FORMAT"` + LogToConsole bool `ocisConfig:"log_to_console" env:"AUDIT_LOG_TO_CONSOLE" desc:"logs to Stdout if true"` + LogToFile bool `ocisConfig:"log_to_file" env:"AUDIT_LOG_TO_FILE" desc:"logs to file if true"` + FilePath string `ocisConfig:"filepath" env:"AUDIT_FILEPATH" desc:"filepath to the logfile. Mandatory if LogToFile is true"` + Format string `ocisConfig:"format" env:"AUDIT_FORMAT" desc:"log format. using json is advised"` } diff --git a/audit/pkg/config/debug.go b/audit/pkg/config/debug.go index da6d2d5906..0176145c03 100644 --- a/audit/pkg/config/debug.go +++ b/audit/pkg/config/debug.go @@ -2,8 +2,8 @@ package config // Debug defines the available debug configuration. type Debug struct { - Addr string `ocisConfig:"addr" env:"NOTIFICATIONS_DEBUG_ADDR"` - Token string `ocisConfig:"token" env:"NOTIFICATIONS_DEBUG_TOKEN"` - Pprof bool `ocisConfig:"pprof" env:"NOTIFICATIONS_DEBUG_PPROF"` - Zpages bool `ocisConfig:"zpages" env:"NOTIFICATIONS_DEBUG_ZPAGES"` + Addr string `ocisConfig:"addr" env:"AUDIT_DEBUG_ADDR"` + Token string `ocisConfig:"token" env:"AUDIT_DEBUG_TOKEN"` + Pprof bool `ocisConfig:"pprof" env:"AUDIT_DEBUG_PPROF"` + Zpages bool `ocisConfig:"zpages" env:"AUDIT_DEBUG_ZPAGES"` } diff --git a/audit/pkg/config/log.go b/audit/pkg/config/log.go index ddb4d391f0..3a39cd4ccb 100644 --- a/audit/pkg/config/log.go +++ b/audit/pkg/config/log.go @@ -2,8 +2,8 @@ package config // Log defines the available log configuration. type Log struct { - Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;NOTIFICATIONS_LOG_LEVEL"` - Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;NOTIFICATIONS_LOG_PRETTY"` - Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;NOTIFICATIONS_LOG_COLOR"` - File string `mapstructure:"file" env:"OCIS_LOG_FILE;NOTIFICATIONS_LOG_FILE"` + Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;AUDIT_LOG_LEVEL"` + Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;AUDIT_LOG_PRETTY"` + Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;AUDIT_LOG_COLOR"` + File string `mapstructure:"file" env:"OCIS_LOG_FILE;AUDIT_LOG_FILE"` } diff --git a/ocis/pkg/runtime/service/service.go b/ocis/pkg/runtime/service/service.go index 139de8b5bb..55acba22b9 100644 --- a/ocis/pkg/runtime/service/service.go +++ b/ocis/pkg/runtime/service/service.go @@ -20,7 +20,6 @@ import ( "github.com/olekukonko/tablewriter" accounts "github.com/owncloud/ocis/accounts/pkg/command" - audit "github.com/owncloud/ocis/audit/pkg/command" glauth "github.com/owncloud/ocis/glauth/pkg/command" graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/command" graph "github.com/owncloud/ocis/graph/pkg/command" @@ -95,7 +94,6 @@ func NewService(options ...Option) (*Service, error) { cfg: opts.Config, } - s.ServicesRegistry["audit"] = audit.NewSutureService s.ServicesRegistry["settings"] = settings.NewSutureService s.ServicesRegistry["nats"] = nats.NewSutureService s.ServicesRegistry["storage-metadata"] = storage.NewStorageMetadata