do not use 22 port by default when ssh from web ui

This commit is contained in:
Alexey Kontsevoy 2018-04-26 11:54:59 -04:00
parent 4e395c8f48
commit feefffcd8c
3 changed files with 194 additions and 87 deletions

View file

@ -45,9 +45,6 @@ const (
// run behind an environment/firewall which only allows outgoing connections)
SSHProxyTunnelListenPort = 3024
// Default SSH port
SSHDefaultPort = 22
// When running as a "SSH Proxy" this port will be used to
// serve auth requests.
AuthListenPort = 3025

View file

@ -755,47 +755,181 @@ func (s *WebSuite) TestSiteNodeConnectInvalidSessionID(c *C) {
c.Assert(err, NotNil)
}
func (s *WebSuite) TestResolveServerHostPort(c *C) {
sampleNode := services.ServerV2{}
sampleNode.SetName("eca53e45-86a9-11e7-a893-0242ac0a0101")
sampleNode.Spec.Hostname = "nodehostname"
// valid cases
validCases := []struct {
server string
nodes []services.Server
expectedHost string
expectedPort int
}{
{
server: "localhost",
expectedHost: "localhost",
expectedPort: 0,
},
{
server: "localhost:8080",
expectedHost: "localhost",
expectedPort: 8080,
},
{
server: "eca53e45-86a9-11e7-a893-0242ac0a0101",
nodes: []services.Server{&sampleNode},
expectedHost: "nodehostname",
expectedPort: 0,
},
}
// invalid cases
invalidCases := []struct {
server string
expectedErr string
}{
{
server: ":22",
expectedErr: "empty hostname",
},
{
server: ":",
expectedErr: "empty hostname",
},
{
server: "",
expectedErr: "empty server name",
},
{
server: "host:",
expectedErr: "invalid port",
},
{
server: "host:port",
expectedErr: "invalid port",
},
}
for _, testCase := range validCases {
host, port, err := resolveServerHostPort(testCase.server, testCase.nodes)
c.Assert(err, IsNil, Commentf(testCase.server))
c.Assert(host, Equals, testCase.expectedHost)
c.Assert(port, Equals, testCase.expectedPort)
}
for _, testCase := range invalidCases {
_, _, err := resolveServerHostPort(testCase.server, nil)
c.Assert(err, NotNil, Commentf(testCase.expectedErr))
c.Assert(err, ErrorMatches, ".*"+testCase.expectedErr+".*")
}
}
func (s *WebSuite) TestNewTerminalHandler(c *C) {
var emptyNodes = []services.ServerV2{}
validNode := services.ServerV2{}
validNode.SetName("eca53e45-86a9-11e7-a893-0242ac0a0101")
validNode.Spec.Hostname = "nodehostname"
v2node := services.ServerV2{}
v2node.SetName("nodename")
v2node.Spec.Hostname = "nodehostname"
validServer := "localhost"
validLogin := "root"
validSID := session.ID("eca53e45-86a9-11e7-a893-0242ac0a0101")
validParams := session.TerminalParams{
H: 1,
W: 1,
}
// valid inputs
handler, err := s.makeTerminalHandler("root", "localhost", emptyNodes)
c.Assert(err, IsNil)
c.Assert(handler.params.Login, Equals, "root")
c.Assert(handler.hostName, Equals, "localhost")
c.Assert(handler.hostPort, Equals, 22)
makeProvider := func(server services.ServerV2) NodeProvider {
return nodeProviderMock(func() []services.Server {
return []services.Server{&server}
})
}
handler, err = s.makeTerminalHandler("root", "localhost:8080", emptyNodes)
c.Assert(err, IsNil)
c.Assert(handler.hostName, Equals, "localhost")
c.Assert(handler.hostPort, Equals, 8080)
// valid cases
validCases := []struct {
req TerminalRequest
nodeProvider NodeProvider
expectedHost string
expectedPort int
}{
{
req: TerminalRequest{
Login: validLogin,
Server: validServer,
SessionID: validSID,
Term: validParams,
},
nodeProvider: makeProvider(validNode),
expectedHost: validServer,
expectedPort: 0,
},
{
req: TerminalRequest{
Login: validLogin,
Server: "eca53e45-86a9-11e7-a893-0242ac0a0101",
SessionID: validSID,
Term: validParams,
},
nodeProvider: makeProvider(validNode),
expectedHost: "nodehostname",
expectedPort: 0,
},
}
handler, err = s.makeTerminalHandler("root", "nodename", []services.ServerV2{v2node})
c.Assert(err, IsNil)
c.Assert(handler.hostName, Equals, "nodehostname")
c.Assert(handler.hostPort, Equals, 0)
// invalid cases
invalidCases := []struct {
req TerminalRequest
nodeProvider NodeProvider
expectedErr string
}{
{
expectedErr: "invalid session",
nodeProvider: makeProvider(validNode),
req: TerminalRequest{
SessionID: "",
Login: validLogin,
Server: validServer,
Term: validParams,
},
},
{
expectedErr: "bad term dimensions",
nodeProvider: makeProvider(validNode),
req: TerminalRequest{
SessionID: validSID,
Login: validLogin,
Server: validServer,
Term: session.TerminalParams{
H: -1,
W: 0,
},
},
},
{
expectedErr: "invalid server name",
nodeProvider: makeProvider(validNode),
req: TerminalRequest{
Server: "localhost:port",
SessionID: validSID,
Login: validLogin,
Term: validParams,
},
},
}
handler, err = s.makeTerminalHandler("root", "nodehostname", []services.ServerV2{v2node})
c.Assert(err, IsNil)
c.Assert(handler.hostName, Equals, "nodehostname")
c.Assert(handler.hostPort, Equals, 0)
for _, testCase := range validCases {
term, err := NewTerminal(testCase.req, testCase.nodeProvider, nil)
c.Assert(err, IsNil)
c.Assert(term.params, DeepEquals, testCase.req)
c.Assert(term.hostName, Equals, testCase.expectedHost)
c.Assert(term.hostPort, Equals, testCase.expectedPort)
}
handler, err = s.makeTerminalHandler("root", "NODEhostname", []services.ServerV2{v2node})
c.Assert(err, IsNil)
c.Assert(handler.hostName, Equals, "nodehostname")
c.Assert(handler.hostPort, Equals, 0)
// invalid inputs
handler, err = s.makeTerminalHandler("", "localhost", emptyNodes)
c.Assert(err, NotNil)
handler, err = s.makeTerminalHandler("root", "", emptyNodes)
c.Assert(err, NotNil)
handler, err = s.makeTerminalHandler("root", "locahost:invalid_port", emptyNodes)
c.Assert(err, NotNil)
for _, testCase := range invalidCases {
_, err := NewTerminal(testCase.req, testCase.nodeProvider, nil)
c.Assert(err, ErrorMatches, ".*"+testCase.expectedErr+".*")
}
}
func (s *WebSuite) makeTerminal(pack *authPack, opts ...session.ID) (*websocket.Conn, error) {
@ -1347,27 +1481,6 @@ func (mock nodeProviderMock) GetNodes(namespace string) ([]services.Server, erro
return mock(), nil
}
func (s *WebSuite) makeTerminalHandler(login string, server string, v2Servers []services.ServerV2) (*TerminalHandler, error) {
var req = TerminalRequest{
Login: login,
Server: server,
}
req.SessionID = "eca53e45-86a9-11e7-a893-0242ac0a0101"
req.Term.H = 1
req.Term.W = 1
var servers = []services.Server{}
return NewTerminal(req, nodeProviderMock(func() []services.Server {
for _, s := range v2Servers {
servers = append(servers, &s)
}
return servers
}), nil)
}
func (s *WebSuite) login(clt *client.WebClient, cookieToken string, reqToken string, reqData interface{}) (*roundtrip.Response, error) {
return httplib.ConvertResponse(clt.RoundTrip(func() (*http.Response, error) {
data, err := json.Marshal(reqData)

View file

@ -26,7 +26,6 @@ import (
"strings"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/session"
"github.com/gravitational/teleport/lib/sshutils"
@ -73,10 +72,6 @@ func NewTerminal(req TerminalRequest, provider NodeProvider, ctx *SessionContext
return nil, trace.BadParameter("sid: invalid session id")
}
if req.Server == "" {
return nil, trace.BadParameter("server: missing server")
}
if req.Login == "" {
return nil, trace.BadParameter("login: missing login")
}
@ -89,9 +84,9 @@ func NewTerminal(req TerminalRequest, provider NodeProvider, ctx *SessionContext
return nil, trace.Wrap(err)
}
hostName, hostPort, err := resolveHostPort(req.Server, servers)
hostName, hostPort, err := resolveServerHostPort(req.Server, servers)
if err != nil {
return nil, trace.Wrap(err)
return nil, trace.BadParameter("invalid server name %q: %v", req.Server, err)
}
return &TerminalHandler{
@ -238,35 +233,37 @@ func (t *TerminalHandler) Run(w http.ResponseWriter, r *http.Request) {
ws.ServeHTTP(w, r)
}
// resolveHostPort parses an input value and attempts to resolve hostname and port of requested server
func resolveHostPort(value string, existingServers []services.Server) (string, int, error) {
var hostName = ""
// resolveServerHostPort parses server name and attempts to resolve hostname and port
func resolveServerHostPort(servername string, existingServers []services.Server) (string, int, error) {
// if port is 0, it means the client wants us to figure out which port to use
var hostPort = 0
var defaultPort = 0
// check if server exists by comparing its UUID or hostname
if servername == "" {
return "", defaultPort, trace.BadParameter("empty server name")
}
// check if servername is UUID
for i := range existingServers {
node := existingServers[i]
if node.GetName() == value || strings.EqualFold(node.GetHostname(), value) {
hostName = node.GetHostname()
break
if node.GetName() == servername {
return node.GetHostname(), defaultPort, nil
}
}
// if server is not found, parse SSH connection string (for joining an unlisted SSH server)
if hostName == "" {
hostName = value
host, port, err := net.SplitHostPort(value)
if err != nil {
hostPort = defaults.SSHDefaultPort
} else {
hostName = host
hostPort, err = strconv.Atoi(port)
if err != nil {
return "", 0, trace.BadParameter("server: invalid port", err)
}
}
if !strings.Contains(servername, ":") {
return servername, defaultPort, nil
}
return hostName, hostPort, nil
// check for explicitly specified port
host, portString, err := utils.SplitHostPort(servername)
if err != nil {
return "", defaultPort, trace.Wrap(err)
}
port, err := strconv.Atoi(portString)
if err != nil {
return "", defaultPort, trace.BadParameter("invalid port: %v", err)
}
return host, port, nil
}