diff --git a/lib/events/dynamoevents/dynamoevents.go b/lib/events/dynamoevents/dynamoevents.go index 8bc6a4cc425..840b4b53962 100644 --- a/lib/events/dynamoevents/dynamoevents.go +++ b/lib/events/dynamoevents/dynamoevents.go @@ -1021,7 +1021,7 @@ func getSubPageCheckpoint(e *event) (string, error) { // SearchSessionEvents returns session related events only. This is used to // find completed session. func (l *Log) SearchSessionEvents(fromUTC time.Time, toUTC time.Time, limit int, order types.EventOrder, startKey string, cond *types.WhereExpr) ([]apievents.AuditEvent, string, error) { - filter := searchEventsFilter{eventTypes: []string{events.SessionEndEvent}} + filter := searchEventsFilter{eventTypes: []string{events.SessionEndEvent, events.WindowsDesktopSessionEndEvent}} if cond != nil { params := condFilterParams{attrValues: make(map[string]interface{}), attrNames: make(map[string]string)} expr, err := fromWhereExpr(cond, ¶ms) diff --git a/lib/events/filelog.go b/lib/events/filelog.go index b2f8a01ba78..1b4ba80486c 100644 --- a/lib/events/filelog.go +++ b/lib/events/filelog.go @@ -360,7 +360,7 @@ func getCheckpointFromEvent(event apievents.AuditEvent) (string, error) { func (l *FileLog) SearchSessionEvents(fromUTC, toUTC time.Time, limit int, order types.EventOrder, startKey string, cond *types.WhereExpr) ([]apievents.AuditEvent, string, error) { l.Debugf("SearchSessionEvents(%v, %v, order=%v, limit=%v, cond=%q)", fromUTC, toUTC, order, limit, cond) - filter := searchEventsFilter{eventTypes: []string{SessionEndEvent}} + filter := searchEventsFilter{eventTypes: []string{SessionEndEvent, WindowsDesktopSessionEndEvent}} if cond != nil { condFn, err := utils.ToFieldsCondition(cond) if err != nil { diff --git a/lib/events/filelog_test.go b/lib/events/filelog_test.go index 53ae66e98a0..c3717e56833 100644 --- a/lib/events/filelog_test.go +++ b/lib/events/filelog_test.go @@ -37,7 +37,7 @@ func TestFileLogPagination(t *testing.T) { RotationPeriod: time.Hour * 24, Clock: clock, }) - require.Nil(t, err) + require.NoError(t, err) err = log.EmitAuditEvent(context.TODO(), &events.SessionJoin{ Metadata: events.Metadata{ @@ -49,7 +49,7 @@ func TestFileLogPagination(t *testing.T) { User: "bob", }, }) - require.Nil(t, err) + require.NoError(t, err) err = log.EmitAuditEvent(context.TODO(), &events.SessionJoin{ Metadata: events.Metadata{ @@ -61,7 +61,7 @@ func TestFileLogPagination(t *testing.T) { User: "alice", }, }) - require.Nil(t, err) + require.NoError(t, err) err = log.EmitAuditEvent(context.TODO(), &events.SessionJoin{ Metadata: events.Metadata{ @@ -73,17 +73,94 @@ func TestFileLogPagination(t *testing.T) { User: "dave", }, }) - require.Nil(t, err) + require.NoError(t, err) from := clock.Now().Add(-time.Hour).UTC() to := clock.Now().Add(time.Hour).UTC() eventArr, checkpoint, err := log.SearchEvents(from, to, apidefaults.Namespace, nil, 2, types.EventOrderAscending, "") - require.Nil(t, err) + require.NoError(t, err) require.Len(t, eventArr, 2) - require.NotEqual(t, checkpoint, "") + require.NotEmpty(t, checkpoint) eventArr, checkpoint, err = log.SearchEvents(from, to, apidefaults.Namespace, nil, 2, types.EventOrderAscending, checkpoint) require.Nil(t, err) require.Len(t, eventArr, 1) - require.Equal(t, checkpoint, "") + require.Empty(t, checkpoint) +} + +func TestSearchSessionEvents(t *testing.T) { + clock := clockwork.NewFakeClock() + start := clock.Now() + + log, err := NewFileLog(FileLogConfig{ + Dir: t.TempDir(), + RotationPeriod: time.Hour * 24, + Clock: clock, + }) + require.Nil(t, err) + clock.Advance(1 * time.Minute) + + require.NoError(t, log.EmitAuditEvent(context.Background(), &events.SessionEnd{ + Metadata: events.Metadata{ + ID: "a", + Type: SessionEndEvent, + Time: clock.Now(), + }, + })) + clock.Advance(1 * time.Minute) + + result, _, err := log.SearchSessionEvents(start, clock.Now(), + 10, // limit + types.EventOrderAscending, + "", // startKey + nil, // cond + ) + require.NoError(t, err) + require.Len(t, result, 1) + require.Equal(t, result[0].GetType(), SessionEndEvent) + require.Equal(t, result[0].GetID(), "a") + + // emit a non-session event, it should not show up in the next query + require.NoError(t, log.EmitAuditEvent(context.Background(), &events.SessionJoin{ + Metadata: events.Metadata{ + ID: "b", + Type: SessionJoinEvent, + Time: clock.Now(), + }, + })) + clock.Advance(1 * time.Minute) + + result, _, err = log.SearchSessionEvents(start, clock.Now(), + 10, // limit + types.EventOrderAscending, + "", // startKey + nil, // cond + ) + require.NoError(t, err) + require.Len(t, result, 1) + require.Equal(t, result[0].GetType(), SessionEndEvent) + require.Equal(t, result[0].GetID(), "a") + + // emit a desktop session event, it should show up in the next query + require.NoError(t, log.EmitAuditEvent(context.Background(), &events.WindowsDesktopSessionEnd{ + Metadata: events.Metadata{ + ID: "c", + Type: WindowsDesktopSessionEndEvent, + Time: clock.Now(), + }, + })) + clock.Advance(1 * time.Minute) + + result, _, err = log.SearchSessionEvents(start, clock.Now(), + 10, // limit + types.EventOrderAscending, + "", // startKey + nil, // cond + ) + require.NoError(t, err) + require.Len(t, result, 2) + require.Equal(t, result[0].GetType(), SessionEndEvent) + require.Equal(t, result[0].GetID(), "a") + require.Equal(t, result[1].GetType(), WindowsDesktopSessionEndEvent) + require.Equal(t, result[1].GetID(), "c") } diff --git a/lib/events/firestoreevents/firestoreevents.go b/lib/events/firestoreevents/firestoreevents.go index c447a099bb1..f6d113fa289 100644 --- a/lib/events/firestoreevents/firestoreevents.go +++ b/lib/events/firestoreevents/firestoreevents.go @@ -628,7 +628,7 @@ func (l *Log) searchEventsOnce(fromUTC, toUTC time.Time, namespace string, limit // SearchSessionEvents returns session related events only. This is used to // find completed sessions. func (l *Log) SearchSessionEvents(fromUTC, toUTC time.Time, limit int, order types.EventOrder, startKey string, cond *types.WhereExpr) ([]apievents.AuditEvent, string, error) { - filter := searchEventsFilter{eventTypes: []string{events.SessionEndEvent}} + filter := searchEventsFilter{eventTypes: []string{events.SessionEndEvent, events.WindowsDesktopSessionEndEvent}} if cond != nil { condFn, err := utils.ToFieldsCondition(cond) if err != nil { diff --git a/lib/events/multilog.go b/lib/events/multilog.go index c6319dc9d81..bf4625a1def 100644 --- a/lib/events/multilog.go +++ b/lib/events/multilog.go @@ -147,7 +147,7 @@ func (m *MultiLog) SearchEvents(fromUTC, toUTC time.Time, namespace string, even } // SearchSessionEvents is a flexible way to find session events. -// Only session.end events are returned by this function. +// Only session.end and windows.desktop.session.end events are returned by this function. // This is used to find completed sessions. // // Event types to filter can be specified and pagination is handled by an iterator key that allows diff --git a/lib/events/writer.go b/lib/events/writer.go index 7b2ac40e25c..ff376c0f761 100644 --- a/lib/events/writer.go +++ b/lib/events/writer.go @@ -117,7 +117,7 @@ func (w *WriterLog) SearchEvents(fromUTC, toUTC time.Time, namespace string, eve } // SearchSessionEvents is a flexible way to find session events. -// Only session.end events are returned by this function. +// Only session.end and windows.desktop.session.end events are returned by this function. // This is used to find completed sessions. // // Event types to filter can be specified and pagination is handled by an iterator key that allows