mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-02 06:08:23 +08:00
Subsystem events did not include ServerMetadata, which results in any events generated for agentless hosts to contain limited information. For example, any sftp subsystem requests made in response to tsh scp for agentless nodes provided information about the proxy forwarding the requests, but no information about the target host. Additionally, the way ServerMetadata information was being populated by using the ServerContext overrode only a subset of the information that was available. This lead to SessionData events emitted when an sftp operation was completed not populating any relevant information about agentless nodes either. To avoid this going forward, the GetServerMetadata receiver has been removed from ServerContext and instead the TargetMetadata must be used from the appropriate SSH server, which already populates the relevant information without omitting any.
162 lines
4.9 KiB
Go
162 lines
4.9 KiB
Go
/*
|
|
* Teleport
|
|
* Copyright (C) 2023 Gravitational, Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package srv
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/user"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
"github.com/gravitational/teleport"
|
|
apievents "github.com/gravitational/teleport/api/types/events"
|
|
"github.com/gravitational/teleport/lib/events"
|
|
"github.com/gravitational/teleport/lib/modules"
|
|
"github.com/gravitational/teleport/lib/sshutils"
|
|
"github.com/gravitational/teleport/lib/utils"
|
|
)
|
|
|
|
// TestMain will re-execute Teleport to run a command if "exec" is passed to
|
|
// it as an argument. Otherwise, it will run tests as normal.
|
|
func TestMain(m *testing.M) {
|
|
utils.InitLoggerForTests()
|
|
modules.SetInsecureTestMode(true)
|
|
// If the test is re-executing itself, execute the command that comes over
|
|
// the pipe.
|
|
if IsReexec() {
|
|
RunAndExit(os.Args[1])
|
|
return
|
|
}
|
|
|
|
// Otherwise run tests as normal.
|
|
code := m.Run()
|
|
os.Exit(code)
|
|
}
|
|
|
|
// TestEmitExecAuditEvent make sure the full command and exit code for a
|
|
// command is always recorded.
|
|
func TestEmitExecAuditEvent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
srv := newMockServer(t)
|
|
scx := newExecServerContext(t, srv)
|
|
|
|
rec, ok := scx.session.recorder.(*mockRecorder)
|
|
require.True(t, ok)
|
|
|
|
scx.GetServer().TargetMetadata()
|
|
|
|
expectedUsr, err := user.Current()
|
|
require.NoError(t, err)
|
|
expectedHostname := "testHost"
|
|
|
|
expectedMeta := apievents.UserMetadata{
|
|
User: "teleportUser",
|
|
Login: expectedUsr.Username,
|
|
Impersonator: "",
|
|
AWSRoleARN: "",
|
|
AccessRequests: []string(nil),
|
|
UserKind: apievents.UserKind_USER_KIND_HUMAN,
|
|
XXX_NoUnkeyedLiteral: struct{}{},
|
|
XXX_unrecognized: []uint8(nil),
|
|
XXX_sizecache: 0,
|
|
}
|
|
|
|
tests := []struct {
|
|
inCommand string
|
|
inError error
|
|
outCommand string
|
|
outCode string
|
|
}{
|
|
// Successful execution.
|
|
{
|
|
inCommand: "exit 0",
|
|
inError: nil,
|
|
outCommand: "exit 0",
|
|
outCode: strconv.Itoa(teleport.RemoteCommandSuccess),
|
|
},
|
|
// Exited with error.
|
|
{
|
|
inCommand: "exit 255",
|
|
inError: fmt.Errorf("unknown error"),
|
|
outCommand: "exit 255",
|
|
outCode: strconv.Itoa(teleport.RemoteCommandFailure),
|
|
},
|
|
// Command injection.
|
|
{
|
|
inCommand: "/bin/teleport scp --remote-addr=127.0.0.1:50862 --local-addr=127.0.0.1:54895 -f ~/file.txt && touch /tmp/new.txt",
|
|
inError: fmt.Errorf("unknown error"),
|
|
outCommand: "/bin/teleport scp --remote-addr=127.0.0.1:50862 --local-addr=127.0.0.1:54895 -f ~/file.txt && touch /tmp/new.txt",
|
|
outCode: strconv.Itoa(teleport.RemoteCommandFailure),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
emitExecAuditEvent(scx, tt.inCommand, tt.inError)
|
|
execEvent := rec.emitter.LastEvent().(*apievents.Exec)
|
|
require.Equal(t, tt.outCommand, execEvent.Command)
|
|
require.Equal(t, tt.outCode, execEvent.ExitCode)
|
|
require.Equal(t, expectedMeta, execEvent.UserMetadata)
|
|
require.Equal(t, "123", execEvent.ServerID)
|
|
require.Equal(t, "abc", execEvent.ForwardedBy)
|
|
require.Equal(t, expectedHostname, execEvent.ServerHostname)
|
|
require.Equal(t, "testNamespace", execEvent.ServerNamespace)
|
|
require.Equal(t, "xxx", execEvent.SessionID)
|
|
require.Equal(t, "10.0.0.5:4817", execEvent.RemoteAddr)
|
|
require.Equal(t, "127.0.0.1:3022", execEvent.LocalAddr)
|
|
require.NotZero(t, events.EventID)
|
|
}
|
|
}
|
|
|
|
func TestLoginDefsParser(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expectedEnvSuPath := "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/bar"
|
|
expectedSuPath := "PATH=/usr/local/bin:/usr/bin:/bin:/foo"
|
|
|
|
require.Equal(t, expectedEnvSuPath, getDefaultEnvPath("0", "../../fixtures/login.defs"))
|
|
require.Equal(t, expectedSuPath, getDefaultEnvPath("1000", "../../fixtures/login.defs"))
|
|
require.Equal(t, defaultEnvPath, getDefaultEnvPath("1000", "bad/file"))
|
|
}
|
|
|
|
func newExecServerContext(t *testing.T, srv Server) *ServerContext {
|
|
scx := newTestServerContext(t, srv, nil)
|
|
|
|
term, err := newLocalTerminal(scx)
|
|
require.NoError(t, err)
|
|
term.SetTermType("xterm")
|
|
|
|
rec := &mockRecorder{done: false}
|
|
scx.session = &session{
|
|
id: "xxx",
|
|
term: term,
|
|
emitter: rec,
|
|
recorder: rec,
|
|
}
|
|
err = scx.SetSSHRequest(&ssh.Request{Type: sshutils.ExecRequest})
|
|
require.NoError(t, err)
|
|
|
|
t.Cleanup(func() { require.NoError(t, scx.session.term.Close()) })
|
|
|
|
return scx
|
|
}
|