Files
teleport/lib/srv/app/session_test.go
T
Gavin FrazarandTobiasz Heller d9b80fb2a7 Emit new event for DynamoDB requests via app access (#17595)
* protobuf update

* Update proto to use dynamodb request event specific to app-access

We will include a similar event for dynamodb via database-access.
We split the events so that app and database access events are not coupled.
This way we do not have to include optional database/app metadata in one event too.

* Update protos

* Update oneof

* Move AppMetaData up with the other metadata and add a 'target' field

* Remove operation plane

* Fix typo

* Configure signing service with transport instead of http client

* Protect from resource exhaustion attacks

* Add IsDynamoDB to types.Application

* Add new event and code for dynamodb requests

* Add async emitter to app access

* Add audit.go to unify app access auditing

* Refactor auditing in app access

* Use the new audit's onSessionChunk/onRequest methods
* Put the session context in the session chunk
* Use a TeeStreamer to send AppSessionDynamoDBRequest directly to audit log as well as session file
* Change streamWriter to streamCloser in sessionChunk to clarify that it should only be used for closing

* Update handler test to test dynamodb events

* Update test to use streamCloser

* Update sever test

* Add doc strings

* Return error from audit interface methods so callers can choose what do to with it

* Move app session start/end into audit interface

* Configure tcpServer to use the server's emitter instead of auth
  client, as an Audit interface.
* Have tcpServer call onSessionStart/End instead of emitting events
  itself.

* Remove unneeded check type

* Rename Transport -> RoundTripper

* Fix test after renaming field

* Rename drainBody and defer body closing

* Fix subtle named return mistake

* Update lib/service/service.go

Co-authored-by: Tobiasz Heller <14020794+tobiaszheller@users.noreply.github.com>

* Update lib/service/service.go

Co-authored-by: Tobiasz Heller <14020794+tobiaszheller@users.noreply.github.com>

* Rename ok->shouldSkipCleanup to make the purpose of it more clear

* Refactor request body decoding into aws utils

* Use request instead of signed request for audit event

* Determine if req is for a dynamo endpoint instead of checking app uri

* Remove obsolete app func IsDynamoDB

* Update handler test

* Use generic console app uri to test that we differentiate request by endpoint instead of app uri
* Use a dynamodb request which has a body to test that we include the body in the audit event
* Test for expected body JSON

* fix lint

* Fixup merge

Co-authored-by: Tobiasz Heller <14020794+tobiaszheller@users.noreply.github.com>
2022-11-15 22:58:15 +00:00

86 lines
2.2 KiB
Go

// Copyright 2022 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package app
import (
"context"
"sync"
"testing"
"time"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/lib/events"
)
func newSessionChunk(timeout time.Duration) *sessionChunk {
return &sessionChunk{
id: uuid.New().String(),
closeC: make(chan struct{}),
inflightCond: sync.NewCond(&sync.Mutex{}),
closeTimeout: timeout,
log: logrus.NewEntry(logrus.StandardLogger()),
streamCloser: &events.DiscardStream{},
}
}
func TestSessionChunkCloseNormal(t *testing.T) {
const timeout = 1 * time.Second
sess := newSessionChunk(timeout)
err := sess.acquire()
require.NoError(t, err)
go sess.close(context.Background())
sess.release()
select {
case <-time.After(timeout / 2):
require.FailNow(t, "session chunk did not close, despite all requests ending")
case <-sess.closeC:
}
}
func TestSessionChunkCloseTimeout(t *testing.T) {
const timeout = 1 * time.Second
start := time.Now()
sess := newSessionChunk(timeout)
err := sess.acquire() // this is never released
require.NoError(t, err)
go sess.close(context.Background())
select {
case <-time.After(timeout * 2):
require.FailNow(t, "session chunk did not close, despite timeout elapsing")
case <-sess.closeC:
}
elapsed := time.Since(start)
require.True(t, elapsed > timeout, "expected to wait at least %s before closing, waited only %s", timeout, elapsed)
}
func TestSessionChunkCannotAcquireAfterClosing(t *testing.T) {
const timeout = 1 * time.Second
sess := newSessionChunk(timeout)
sess.close(context.Background())
require.Error(t, sess.acquire())
}