Ctrl K
ComunidadGuías…

tests/agent_single_user_test.go

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package main

import (
	"testing"
	"time"

	"github.com/moby/moby/api/types/container"
	"github.com/shellhub-io/shellhub/pkg/models"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/testcontainers/testcontainers-go"
	"golang.org/x/crypto/ssh"
)

const (
	singleUserPassword = "single-user-password"
	singleUserHash     = "$6$e2esingleuser$.sfZR6UlxyHc3YTk7m.S8yMCSvao0kjGSX.mLOKMwJhoEzws3YUFzBN3PzHwxAQ2ZfvZNzXkEDMnuGvdt6EqL/"
	singleUserAccount  = "nobody"
)

func NewAgentContainerInSingleUserMode() NewAgentContainerOption {
	return func(envs map[string]string) {
		envs["SHELLHUB_SINGLE_USER_PASSWORD"] = singleUserHash
		envs["SHELL"] = "/bin/sh"
	}
}

func asUser(user string) func(*testcontainers.ContainerRequest) {
	return func(req *testcontainers.ContainerRequest) {
		req.ConfigModifier = func(config *container.Config) {
			config.User = user
		}
	}
}

// TestAgentSingleUserMode runs the agent unprivileged with SHELLHUB_SINGLE_USER_PASSWORD, where it
// checks every login against that hash instead of the system's accounts and runs every session as
// the account it runs as, whatever user the client names.
func TestAgentSingleUserMode(t *testing.T) {
	t.Parallel()

	compose := newSSHEnvironment(t, t.Context(), legacyNamespace)

	t.Run("an agent running as root refuses to start", func(t *testing.T) {
		agent := startAgent(t, t.Context(), compose, NewAgentContainerInSingleUserMode())

		var state *container.State

		require.EventuallyWithT(t, func(tt *assert.CollectT) {
			var err error

			state, err = agent.State(t.Context())
			if assert.NoError(tt, err) {
				assert.False(tt, state.Running, "the agent is still running")
			}
		}, 30*time.Second, time.Second)

		assert.Equal(t, 1, state.ExitCode)

		logs, err := agentLogs(t.Context(), agent)
		require.NoError(t, err)
		assert.Contains(t, string(logs), "cannot run as root when single-user mode is enabled")

		assert.Empty(t, compose.ListDevices(t, models.DeviceStatusEmpty), "the refused agent enrolled a device")
	})

	startCustomAgent(t, t.Context(), compose, asUser(singleUserAccount), NewAgentContainerInSingleUserMode())

	device := acceptPendingDevice(t, compose)

	passwordConfig := func(password string) *ssh.ClientConfig {
		return &ssh.ClientConfig{
			User:            deviceSSHID(device),
			Auth:            []ssh.AuthMethod{ssh.Password(password)},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(), //nolint:gosec // the test stack's host key is ephemeral
		}
	}

	t.Run("the configured password logs root in as the agent's own account", func(t *testing.T) {
		conn := dialClientWithin(t, t.Context(), compose.SSHAddress(), passwordConfig(singleUserPassword), 30*time.Second)
		defer conn.Close() //nolint:errcheck // the test is over once the command answered

		assert.Equal(t, singleUserAccount, runOnDevice(t, conn, "echo -n $(id -un)"))
		assert.Equal(t, singleUserAccount, runOnDevice(t, conn, "echo -n $USER"))
	})

	t.Run("a password other than the configured one is refused", func(t *testing.T) {
		err := handshakeWith(t.Context(), compose.SSHAddress(), passwordConfig(ShellHubAgentPassword))
		require.ErrorContains(t, err, "ssh: unable to authenticate")
	})
}