Skip to content

Commit

Permalink
implement user and group audit events
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Apr 5, 2022
1 parent 804470e commit 2722454
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 2 deletions.
14 changes: 14 additions & 0 deletions audit/pkg/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ func StartAuditLogger(ctx context.Context, ch <-chan interface{}, log log.Logger
auditEvent = types.SpaceEnabled(ev)
case events.SpaceDeleted:
auditEvent = types.SpaceDeleted(ev)
case events.UserCreated:
auditEvent = types.UserCreated(ev)
case events.UserDeleted:
auditEvent = types.UserDeleted(ev)
case events.UserFeatureChanged:
auditEvent = types.UserFeatureChanged(ev)
case events.GroupCreated:
auditEvent = types.GroupCreated(ev)
case events.GroupDeleted:
auditEvent = types.GroupDeleted(ev)
case events.GroupMemberAdded:
auditEvent = types.GroupMemberAdded(ev)
case events.GroupMemberRemoved:
auditEvent = types.GroupMemberRemoved(ev)
default:
log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev))
continue
Expand Down
46 changes: 46 additions & 0 deletions audit/pkg/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ const (
ActionSpaceDisabled = "space_disabled"
ActionSpaceEnabled = "space_enabled"
ActionSpaceDeleted = "space_deleted"

// Users
ActionUserCreated = "user_created"
ActionUserDeleted = "user_deleted"
ActionUserFeatureChanged = "user_feature_changed"

// Groups
ActionGroupCreated = "group_created"
ActionGroupDeleted = "group_deleted"
ActionGroupMemberAdded = "group_member_added"
ActionGroupMemberRemoved = "group_member_removed"
)

// MessageShareCreated returns the human readable string that describes the action
Expand Down Expand Up @@ -136,3 +147,38 @@ func MessageSpaceEnabled(spaceID string) string {
func MessageSpaceDeleted(spaceID string) string {
return fmt.Sprintf("Space '%s' was deleted", spaceID)
}

// MessageUserCreated returns the human readable string that describes the action
func MessageUserCreated(userID string) string {
return fmt.Sprintf("User '%s' was created", userID)
}

// MessageUserDeleted returns the human readable string that describes the action
func MessageUserDeleted(userID string) string {
return fmt.Sprintf("User '%s' was deleted", userID)
}

// MessageUserFeatureChanged returns the human readable string that describes the action
func MessageUserFeatureChanged(userID, feature, value string) string {
return fmt.Sprintf("User '%s's' feature '%s' was changed to '%s'", userID, feature, value)
}

// MessageGroupCreated returns the human readable string that describes the action
func MessageGroupCreated(groupID string) string {
return fmt.Sprintf("Group '%s' was created", groupID)
}

// MessageGroupDeleted returns the human readable string that describes the action
func MessageGroupDeleted(groupID string) string {
return fmt.Sprintf("Group '%s' was deleted", groupID)
}

// MessageGroupMemberAdded returns the human readable string that describes the action
func MessageGroupMemberAdded(userID, groupID string) string {
return fmt.Sprintf("User '%s' was added to group '%s'", userID, groupID)
}

// MessageGroupMemberRemoved returns the human readable string that describes the action
func MessageGroupMemberRemoved(userID, groupID string) string {
return fmt.Sprintf("User '%s' was removed from group '%s'", userID, groupID)
}
70 changes: 70 additions & 0 deletions audit/pkg/types/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,76 @@ func SpaceDeleted(ev events.SpaceDeleted) AuditEventSpaceDeleted {
}
}

// UserCreated converts a UserCreated event to an AuditEventUserCreated
func UserCreated(ev events.UserCreated) AuditEventUserCreated {
base := BasicAuditEvent("", "", MessageUserCreated(ev.UserID), ActionUserCreated)
return AuditEventUserCreated{
AuditEvent: base,
UserID: ev.UserID,
}
}

// UserDeleted converts a UserCreated event to an AuditEventUserDeleted
func UserDeleted(ev events.UserDeleted) AuditEventUserDeleted {
base := BasicAuditEvent("", "", MessageUserDeleted(ev.UserID), ActionUserDeleted)
return AuditEventUserDeleted{
AuditEvent: base,
UserID: ev.UserID,
}
}

// UserFeatureChanged converts a UserFeatureChanged event to an AuditEventUserFeatureChanged
func UserFeatureChanged(ev events.UserFeatureChanged) AuditEventUserFeatureChanged {
msg := MessageUserFeatureChanged(ev.UserID, ev.Feature, ev.Value)
base := BasicAuditEvent("", "", msg, ActionUserFeatureChanged)
return AuditEventUserFeatureChanged{
AuditEvent: base,
UserID: ev.UserID,
Feature: ev.Feature,
Value: ev.Value,
}
}

// GroupCreated converts a GroupCreated event to an AuditEventGroupCreated
func GroupCreated(ev events.GroupCreated) AuditEventGroupCreated {
base := BasicAuditEvent("", "", MessageGroupCreated(ev.GroupID), ActionGroupCreated)
return AuditEventGroupCreated{
AuditEvent: base,
GroupID: ev.GroupID,
}
}

// GroupDeleted converts a GroupDeleted event to an AuditEventGroupDeleted
func GroupDeleted(ev events.GroupDeleted) AuditEventGroupDeleted {
base := BasicAuditEvent("", "", MessageGroupDeleted(ev.GroupID), ActionGroupDeleted)
return AuditEventGroupDeleted{
AuditEvent: base,
GroupID: ev.GroupID,
}
}

// GroupMemberAdded converts a GroupMemberAdded event to an AuditEventGroupMemberAdded
func GroupMemberAdded(ev events.GroupMemberAdded) AuditEventGroupMemberAdded {
msg := MessageGroupMemberAdded(ev.GroupID, ev.UserID)
base := BasicAuditEvent("", "", msg, ActionGroupMemberAdded)
return AuditEventGroupMemberAdded{
AuditEvent: base,
GroupID: ev.GroupID,
UserID: ev.UserID,
}
}

// GroupMemberRemoved converts a GroupMemberRemoved event to an AuditEventGroupMemberRemove
func GroupMemberRemoved(ev events.GroupMemberRemoved) AuditEventGroupMemberRemoved {
msg := MessageGroupMemberRemoved(ev.GroupID, ev.UserID)
base := BasicAuditEvent("", "", msg, ActionGroupMemberRemoved)
return AuditEventGroupMemberRemoved{
AuditEvent: base,
GroupID: ev.GroupID,
UserID: ev.UserID,
}
}

func extractGrantee(uid *user.UserId, gid *group.GroupId) (string, string) {
switch {
case uid != nil && uid.OpaqueId != "":
Expand Down
7 changes: 7 additions & 0 deletions audit/pkg/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,12 @@ func RegisteredEvents() []events.Unmarshaller {
events.SpaceEnabled{},
events.SpaceDisabled{},
events.SpaceDeleted{},
events.UserCreated{},
events.UserDeleted{},
events.UserFeatureChanged{},
events.GroupCreated{},
events.GroupDeleted{},
events.GroupMemberAdded{},
events.GroupMemberRemoved{},
}
}
46 changes: 46 additions & 0 deletions audit/pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,49 @@ type AuditEventSpaceEnabled struct {
type AuditEventSpaceDeleted struct {
AuditEventSpaces
}

// AuditEventUserCreated is the event logged when a user is created
type AuditEventUserCreated struct {
AuditEvent
UserID string
}

// AuditEventUserDeleted is the event logged when a user is deleted
type AuditEventUserDeleted struct {
AuditEvent
UserID string
}

// AuditEventUserFeatureChanged is the event logged when a user feature is changed
type AuditEventUserFeatureChanged struct {
AuditEvent
UserID string
Feature string
Value string
}

// AuditEventGroupCreated is the event logged when a group is created
type AuditEventGroupCreated struct {
AuditEvent
GroupID string
}

// AuditEventGroupDeleted is the event logged when a group is deleted
type AuditEventGroupDeleted struct {
AuditEvent
GroupID string
}

// AuditEventGroupMemberAdded is the event logged when a group member is added
type AuditEventGroupMemberAdded struct {
AuditEvent
GroupID string
UserID string
}

// AuditEventGroupMemberRemoved is the event logged when a group member is removed
type AuditEventGroupMemberRemoved struct {
AuditEvent
GroupID string
UserID string
}
12 changes: 12 additions & 0 deletions changelog/unreleased/user-group-audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Enhancement: Implement audit events for user and groups

Added audit events for users and groups. This will log:
* User creation
* User deletion
* User property change (currently only email)
* Group creation
* Group deletion
* Group member add
* Group member remove

https://github.com/owncloud/ocis/pull/3467
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,5 @@ require (

// we need to use a fork to make the windows build pass
replace github.com/pkg/xattr => github.com/micbar/xattr v0.4.6-0.20220215112335-88e74d648fb7

replace github.com/cs3org/reva/v2 => github.com/c0rby/reva/v2 v2.0.0-20220405162342-c89800919b67
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/c0rby/reva/v2 v2.0.0-20220405162342-c89800919b67 h1:0jWkpLmG9b/nkz+TyPiT7vyWjPTS+ZF4BBwa8j12KPw=
github.com/c0rby/reva/v2 v2.0.0-20220405162342-c89800919b67/go.mod h1:1siLO6MV57uSyzQxPbfM6qNA9NP6aagN3/yKOE/FwtM=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
Expand Down Expand Up @@ -337,8 +339,6 @@ github.com/crewjam/saml v0.4.6/go.mod h1:ZBOXnNPFzB3CgOkRm7Nd6IVdkG+l/wF+0ZXLqD9
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20220328105952-297bef33e13f h1:emnlOWc1s2gx77MViLnZH9yh5TRHKsykRu6rJjx3lkM=
github.com/cs3org/go-cs3apis v0.0.0-20220328105952-297bef33e13f/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva/v2 v2.0.0-20220404075659-19fd0b28297b h1:CqHYID4t286wle5kXcFfUtxxw6Vz0XlbGCiB/Z8rDbI=
github.com/cs3org/reva/v2 v2.0.0-20220404075659-19fd0b28297b/go.mod h1:1siLO6MV57uSyzQxPbfM6qNA9NP6aagN3/yKOE/FwtM=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
Expand Down
7 changes: 7 additions & 0 deletions graph/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Config struct {

Spaces Spaces `yaml:"spaces"`
Identity Identity `yaml:"identity"`
Events Events `yaml:"events"`

Context context.Context `yaml:"-"`
}
Expand Down Expand Up @@ -62,3 +63,9 @@ type Identity struct {
Backend string `yaml:"backend" env:"GRAPH_IDENTITY_BACKEND"`
LDAP LDAP `yaml:"ldap"`
}

// Events combines the configuration options for the event bus.
type Events struct {
Endpoint string `yaml:"events_endpoint" env:"GRAPH_EVENTS_ENDPOINT" desc:"the address of the streaming service"`
Cluster string `yaml:"events_cluster" env:"GRAPH_EVENTS_CLUSTER" desc:"the clusterID of the streaming service. Mandatory when using nats"`
}
4 changes: 4 additions & 0 deletions graph/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ func DefaultConfig() *config.Config {
GroupIDAttribute: "owncloudUUID",
},
},
Events: config.Events{
Endpoint: "127.0.0.1:9233",
Cluster: "ocis-cluster",
},
}
}

Expand Down
10 changes: 10 additions & 0 deletions graph/pkg/service/v0/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/ReneKroon/ttlcache/v2"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/go-chi/chi/v5"
"github.com/owncloud/ocis/graph/pkg/config"
"github.com/owncloud/ocis/graph/pkg/identity"
Expand Down Expand Up @@ -69,6 +70,7 @@ type Graph struct {
httpClient HTTPClient
roleService settingssvc.RoleService
spacePropertiesCache *ttlcache.Cache
eventsPublisher events.Publisher
}

// ServeHTTP implements the Service interface.
Expand All @@ -86,6 +88,14 @@ func (g Graph) GetHTTPClient() HTTPClient {
return g.httpClient
}

func (g Graph) publishEvent(ev interface{}) {
if err := events.Publish(g.eventsPublisher, ev); err != nil {
g.logger.Error().
Err(err).
Msg("could not publish user created event")
}
}

type listResponse struct {
Value interface{} `json:"value,omitempty"`
}
Expand Down
7 changes: 7 additions & 0 deletions graph/pkg/service/v0/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"

"github.com/cs3org/reva/v2/pkg/events"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
)
Expand Down Expand Up @@ -81,6 +82,7 @@ func (g Graph) PostGroup(w http.ResponseWriter, r *http.Request) {
return
}

g.publishEvent(events.GroupCreated{GroupID: *grp.Id})
render.Status(r, http.StatusOK)
render.JSON(w, r, grp)
}
Expand Down Expand Up @@ -197,6 +199,8 @@ func (g Graph) DeleteGroup(w http.ResponseWriter, r *http.Request) {
}
return
}

g.publishEvent(events.GroupDeleted{GroupID: groupID})
render.Status(r, http.StatusNoContent)
render.NoContent(w, r)
}
Expand Down Expand Up @@ -279,6 +283,8 @@ func (g Graph) PostGroupMember(w http.ResponseWriter, r *http.Request) {
}
return
}

g.publishEvent(events.GroupMemberAdded{GroupID: groupID, UserID: id})
render.Status(r, http.StatusNoContent)
render.NoContent(w, r)
}
Expand Down Expand Up @@ -322,6 +328,7 @@ func (g Graph) DeleteGroupMember(w http.ResponseWriter, r *http.Request) {
}
return
}
g.publishEvent(events.GroupMemberRemoved{GroupID: groupID, UserID: memberID})
render.Status(r, http.StatusNoContent)
render.NoContent(w, r)
}
Expand Down
13 changes: 13 additions & 0 deletions graph/pkg/service/v0/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"time"

"github.com/ReneKroon/ttlcache/v2"
"github.com/asim/go-micro/plugins/events/natsjs/v4"
"github.com/cs3org/reva/v2/pkg/events/server"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
Expand Down Expand Up @@ -90,12 +92,23 @@ func NewService(opts ...Option) Service {
return nil
}

publisher, err := server.NewNatsStream(
natsjs.Address(options.Config.Events.Endpoint),
natsjs.ClusterID(options.Config.Events.Cluster),
)
if err != nil {
options.Logger.Error().
Err(err).
Msg("Error initializing events publisher")
}

svc := Graph{
config: options.Config,
mux: m,
logger: &options.Logger,
identityBackend: backend,
spacePropertiesCache: ttlcache.NewCache(),
eventsPublisher: publisher,
}
if options.GatewayClient == nil {
var err error
Expand Down
Loading

0 comments on commit 2722454

Please sign in to comment.