From 8c193d2d0209a08b5c51fc72f3ffb19e324fa0fb Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Wed, 23 Feb 2022 19:36:44 -0700 Subject: [PATCH] Fix desktop session playback RBAC The RBAC for sessions code was using SSH-specific queries to check for session end events. Migrate to the newer search, which is both more efficient and supports desktop events as well. Fixes #10507 --- lib/auth/auth_with_roles.go | 27 +++++++++++++-------------- lib/services/parser.go | 11 ++++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index 214e3d7188c05..e91bd1bbaf56c 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -198,7 +198,7 @@ func (a *ServerWithRoles) actionForKindSession(namespace, verb string, sid sessi return trace.Wrap(a.actionWithExtendedContext(namespace, types.KindSession, verb, extendContext)) } -// actionForKindSSHSession is a special checker that grants access to active +// actionForKindSSHSession is a special checker that grants access to active SSH // sessions. It can allow access to a specific session based on the `where` // section of the user's access rule for kind `ssh_session`. func (a *ServerWithRoles) actionForKindSSHSession(namespace, verb string, sid session.ID) error { @@ -2494,23 +2494,22 @@ func (a *ServerWithRoles) GetSessionEvents(namespace string, sid session.ID, aft return a.alog.GetSessionEvents(namespace, sid, afterN, includePrintEvents) } -func (a *ServerWithRoles) findSessionEndEvent(namespace string, sid session.ID) (*apievents.SessionEnd, error) { - sessionEvents, err := a.alog.GetSessionEvents(namespace, sid, 0, false) +func (a *ServerWithRoles) findSessionEndEvent(namespace string, sid session.ID) (apievents.AuditEvent, error) { + sessionEvents, _, err := a.alog.SearchSessionEvents(time.Time{}, a.authServer.clock.Now().UTC(), + defaults.EventsIterationLimit, types.EventOrderAscending, "", + &types.WhereExpr{Equals: types.WhereExpr2{ + L: &types.WhereExpr{Field: events.SessionEventID}, + R: &types.WhereExpr{Literal: sid.String()}, + }}, + ) if err != nil { return nil, trace.Wrap(err) } - for _, ef := range sessionEvents { - if ef.GetType() == events.SessionEndEvent { - event, err := events.FromEventFields(ef) - if err != nil { - return nil, trace.Wrap(err) - } - if sessionEnd, ok := event.(*apievents.SessionEnd); ok { - return sessionEnd, nil - } - } + if len(sessionEvents) == 1 { + return sessionEvents[0], nil } - return nil, trace.NotFound("session.end event not found for session ID %q", sid) + + return nil, trace.NotFound("session end event not found for session ID %q", sid) } // GetNamespaces returns a list of namespaces diff --git a/lib/services/parser.go b/lib/services/parser.go index a2e11f4b8ea58..ff29f7abd28ad 100644 --- a/lib/services/parser.go +++ b/lib/services/parser.go @@ -176,9 +176,9 @@ type Context struct { // Resource is an optional resource, in case if the rule // checks access to the resource Resource types.Resource - // Session is an optional session.end event. These events hold information - // about session recordings. - Session *events.SessionEnd + // Session is an optional session.end or windows.desktop.session.end event. + // These events hold information about session recordings. + Session events.AuditEvent // SSHSession is an optional (active) SSH session. SSHSession *session.Session } @@ -236,8 +236,9 @@ func (ctx *Context) GetIdentifier(fields []string) (interface{}, error) { } return predicate.GetFieldByTag(resource, teleport.JSON, fields[1:]) case SessionIdentifier: - session := &events.SessionEnd{} - if ctx.Session != nil { + var session events.AuditEvent = &events.SessionEnd{} + switch ctx.Session.(type) { + case *events.SessionEnd, *events.WindowsDesktopSessionEnd: session = ctx.Session } return predicate.GetFieldByTag(session, teleport.JSON, fields[1:])