-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Added support for OpenSSH compatibility flags for interactivity (-t and -T) and version information (-V). This is for customers that alias "ssh" to "tsh ssh".
- Loading branch information
Showing
3 changed files
with
159 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6047,3 +6047,117 @@ func TestResolve(t *testing.T) { | |
}) | ||
} | ||
} | ||
|
||
// TestInteractiveCompatibilityFlags verifies that "tsh ssh -t" and "tsh ssh -T" | ||
// behave similar to OpenSSH. | ||
func TestInteractiveCompatibilityFlags(t *testing.T) { | ||
// Require the "tty" program exist somewhere in $PATH, otherwise fail. | ||
tty, err := exec.LookPath("tty") | ||
require.NoError(t, err) | ||
|
||
// Create roles and users that will be used in test. | ||
local, err := user.Current() | ||
require.NoError(t, err) | ||
nodeAccess, err := types.NewRole("foo", types.RoleSpecV6{ | ||
Allow: types.RoleConditions{ | ||
Logins: []string{local.Username}, | ||
NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, | ||
}, | ||
}) | ||
require.NoError(t, err) | ||
user, err := types.NewUser("[email protected]") | ||
require.NoError(t, err) | ||
user.SetRoles([]string{"access", "foo"}) | ||
|
||
// Create Auth, Proxy, and Node Service used in tests. | ||
hostname := uuid.NewString() | ||
connector := mockConnector(t) | ||
authProcess, proxyProcess := makeTestServers(t, | ||
withBootstrap(connector, nodeAccess, user), | ||
withConfig(func(cfg *servicecfg.Config) { | ||
cfg.Hostname = hostname | ||
cfg.SSH.Enabled = true | ||
cfg.SSH.Addr = utils.NetAddr{ | ||
AddrNetwork: "tcp", | ||
Addr: net.JoinHostPort("127.0.0.1", ports.Pop()), | ||
} | ||
})) | ||
|
||
// Extract Auth Service and Proxy Service address. | ||
authServer := authProcess.GetAuthServer() | ||
require.NotNil(t, authServer) | ||
proxyAddr, err := proxyProcess.ProxyWebAddr() | ||
require.NoError(t, err) | ||
|
||
// Run "tsh login". | ||
home := t.TempDir() | ||
err = Run(context.Background(), []string{ | ||
"login", | ||
"--insecure", | ||
"--debug", | ||
"--proxy", proxyAddr.String()}, | ||
setHomePath(home), | ||
setMockSSOLogin(authServer, user, connector.GetName())) | ||
require.NoError(t, err) | ||
|
||
// Test compatibility with OpenSSH "-T" and "-t" flags. Note that multiple | ||
// -t options is still not supported. | ||
// | ||
// From "man 1 ssh". | ||
// | ||
// -T Disable pseudo-terminal allocation. | ||
// -t Force pseudo-terminal allocation. This can be used to execute | ||
// arbitrary screen-based programs on a remote machine, which can | ||
// be very useful, e.g. when implementing menu services. Multiple | ||
// -t options force tty allocation, even if ssh has no local tty. | ||
tests := []struct { | ||
name string | ||
flag string | ||
assertError require.ErrorAssertionFunc | ||
}{ | ||
{ | ||
name: "disable pseudo-terminal allocation", | ||
flag: "-T", | ||
assertError: func(t require.TestingT, err error, i ...interface{}) { | ||
var exiterr *exec.ExitError | ||
if errors.As(err, &exiterr) { | ||
require.Equal(t, 1, exiterr.ExitCode()) | ||
} else { | ||
require.Fail(t, "Non *exec.ExitError type: %T.", err) | ||
} | ||
}, | ||
}, | ||
{ | ||
name: "force pseudo-terminal allocation", | ||
flag: "-t", | ||
assertError: require.NoError, | ||
}, | ||
} | ||
|
||
// Turn the binary running tests into a fake "tsh" binary so it can | ||
// re-execute itself. | ||
t.Setenv(types.HomeEnvVar, home) | ||
t.Setenv(tshBinMainTestEnv, "1") | ||
tshBin, err := os.Executable() | ||
require.NoError(t, err) | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
err := exec.Command(tshBin, "ssh", tt.flag, hostname, tty).Run() | ||
tt.assertError(t, err) | ||
}) | ||
} | ||
} | ||
|
||
// TestVersionCompatibilityFlags verifies that "tsh ssh -V" returns Teleport | ||
// version similar to OpenSSH. | ||
func TestVersionCompatibilityFlags(t *testing.T) { | ||
t.Setenv(tshBinMainTestEnv, "1") | ||
tshBin, err := os.Executable() | ||
require.NoError(t, err) | ||
|
||
output, err := exec.Command(tshBin, "ssh", "-V").CombinedOutput() | ||
require.NoError(t, err, output) | ||
require.Equal(t, "Teleport CLI", string(bytes.TrimSpace(output))) | ||
} |