Commit Graph
4 Commits
Author SHA1 Message Date
rosstimothy 07e2ca13e4 Prevent race from causing remote clients from being closed (#19010)
* Prevent race from causing remote clients from being closed

`web.SessionContext` was susceptible to races retrieving `auth.ClientI`
for remote sites. The mutex on the remote client cache was not held for
the duration of the `GetUserClient` which meant two simultaneous requests
could find no client existed in the cache, create one and then add it to
the cache. When the second client is added to the cache it would close the
first client created, which results in the `use of closed network connection`
error displaying on the web UI as described in #17173.

To remedy this the portion of `GetUserClient` that retrieves the remote client
is now protected by a `singleflight.Group`. This ensures that races on creating
a client no longer happen.

`web.SessionContext` was slightly refactored to make it easier to test, to
remove some unnecessary operations, and to provide `context.Context` to `GetUserClient`.
Additionally, all `web.SessionContext` variables which were named `ctx` in `lib/web`
have been renamed to avoid confusion as that often refers to a `context.Context`.

Fixes #17173
2022-12-05 20:10:01 +00:00
Jakub Nyckowski 0ee91f6c37 Enable GCI linter (#17894) 2022-10-28 20:20:28 +00:00
Isaiah Becker-Mayer 231e2b337d Wrap desktopplayback endpoint with WithClusterAuth rather than WithAuth (#16113) 2022-09-09 16:13:49 +00:00
c84b7f8142 Desktop session recording/playback (#9583)
* Record desktop sessions

Here we introduce a new protobuf type (DesktopRecording) that contains
an encoded TDP message, and update AuditWriter to treat these similarly
to SessionPrint events (which are used for SSH session recordings).

We also add desktop session playback endpoint, temporarily located at
/webapi/sites/:site/desktopplaybacktest/:session
which streams TDP messages from a recorded session over
a websocket interface.

* update session end (#9795)

* Updates SessionEnd event with fields needed for frontend

* removes the clock which didn't need to be passed

* Add `Recorded` field to `WindowsDesktopSessionEnd` (#9839)

* Adds the SessionRecording field to WindowsDesktopSessionEnd event to mimic SessionEnd events (useful for easy integration with frontend).

* 14 should have been 12

* removing test logic

* switches SessionRecording to simple boolean Recorded

* session recording websocket (#9908)

* Adds the SessionRecording field to WindowsDesktopSessionEnd event to mimic SessionEnd events (useful for easy integration with frontend).

* 14 should have been 12

* removing test logic

* switches SessionRecording to simple boolean Recorded

* Updates the websocket address

* updates desktopPlaybackHandle to restart playback once it reaches the end

* adds playback state and synchronization logic for ensuring that goroutines aren't leaked

* adds toggle functionality for play/pause

* fix for the fact that urls are case insensitive

* moves desktop_playback to its own file, fixes mistaken comment about how websocket.JSON.Receive works, fixes error messaging, wraps playbackState.Close in a sync.Once

* Adds a cond variable for the two goroutines, but doesn't solve the spinning loop problem for the hanging logic

* Adds a cancel-able context which is cancelled in ps.Close() in order to avoid a spinning loop in the websocket.Handler

* Moves the majority of playback logic into the playbackState, which is now renamed to the more accurate playbackPlayer.

* changes pp.hangWhilePaused to pp.waitWhilePaused

* Moves the context out of NewPlaybackPlayer and the playbackPlayer
struct, wraps playback goroutines in playbackPlayer.Play(ctx) in
order to comply with context semantics.

* removing unnecessary warnings

* touchups

* record screen size (#9992)

* Adds the SessionRecording field to WindowsDesktopSessionEnd event to mimic SessionEnd events (useful for easy integration with frontend).

* 14 should have been 12

* removing test logic

* switches SessionRecording to simple boolean Recorded

* Updates the websocket address

* updates desktopPlaybackHandle to restart playback once it reaches the end

* adds playback state and synchronization logic for ensuring that goroutines aren't leaked

* adds toggle functionality for play/pause

* fix for the fact that urls are case insensitive

* moves desktop_playback to its own file, fixes mistaken comment about how websocket.JSON.Receive works, fixes error messaging, wraps playbackState.Close in a sync.Once

* Adds a cond variable for the two goroutines, but doesn't solve the spinning loop problem for the hanging logic

* Adds a cancel-able context which is cancelled in ps.Close() in order to avoid a spinning loop in the websocket.Handler

* Moves the majority of playback logic into the playbackState, which is now renamed to the more accurate playbackPlayer.

* changes pp.hangWhilePaused to pp.waitWhilePaused

* Moves the context out of NewPlaybackPlayer and the playbackPlayer
struct, wraps playback goroutines in playbackPlayer.Play(ctx) in
order to comply with context semantics.

* removing unnecessary warnings

* Adds an OnRecv that's similar to OnSend, for emitting audit events for particular incoming tdp messages

* Send full `DesktopRecording` event as json over playback websocket. (#10052)

* playback websocket now sends a json representation of the DesktopRecording event rather than just the raw tdp message, in order for us to have timing data on the frontend

* updating json.Marshal to utils.FastMarshal

* Removing unnecessary comment

* playback end event (#10088)

* Adds an end event so that the playback player knows to set the progress bar to its end state

* making the end message a json

* if the marshal fails we don't want to send a message over websocket

* Use a static string

Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>

Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>

* Add participants to session end event

Desktop sessions are not joinable, so the participants list always
has a single member - the user who started the session.

This will ensure that our example role for RBAC for sessions
(which depends on the participants field) will work for desktop
sessions.

* Minor cleanup

* Only record sessions when enabled

In order for desktop sessions to be recorded, session recording
must be enabled in the cluster's session recording config and
at least one of the user's roles must enable it.

* Cleanup

* Start to address review comments

* Move TDP event handlers out of connectRDP

* Address more review comments and add some tests

* Add playback streaming test

* Consistent comments

* Fix tests

* Don't log PNG frames that exceed the size of a protobuf

Since the PNG frame message in our desktop protocol is unbounded,
it is theoretically possible for a message to exceed the size limit
of a single protobuf.

In practice, this is unlikely to occur with any legitimate RDP traffic,
as the bitmaps are at most 64x64 pixels and compressed in PNG form.
Rather than complicating the protocol to allow for PNGs to be split
across events, we simply refuse to log anything this big.

* Mark RFD 48 implemented

Co-authored-by: Isaiah Becker-Mayer <isaiah@goteleport.com>
Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>
2022-02-11 15:39:14 -07:00