Files
teleport/api/utils/route_test.go
T
rosstimothy a39c21716b Fix routing to public addresses (#36617)
#36584 allowed routing to work for public addresses, however it
used GetPublicAddr to retrieve the public address. types.Server can
have multiple public addresses though which means routing was only
ever considering the first public address defined. This updates
the routing logic to use GetPublicAddrs so they are all considered.
2024-01-12 15:35:29 +00:00

247 lines
5.8 KiB
Go

// Copyright 2023 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 utils
import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)
// NOTE: much of the details of the behavior of this type is tested in lib/proxy as part
// of the main router test coverage.
// TestSSHRouteMatcherHostnameMatching verifies the expected behavior of the custom ssh
// hostname matching logic.
func TestSSHRouteMatcherHostnameMatching(t *testing.T) {
tts := []struct {
desc string
principal string
target string
insensitive bool
match bool
}{
{
desc: "upper-eq",
principal: "Foo",
target: "Foo",
insensitive: true,
match: true,
},
{
desc: "lower-eq",
principal: "foo",
target: "foo",
insensitive: true,
match: true,
},
{
desc: "lower-target-match",
principal: "Foo",
target: "foo",
insensitive: true,
match: true,
},
{
desc: "upper-target-mismatch",
principal: "foo",
target: "Foo",
insensitive: true,
match: false,
},
{
desc: "upper-mismatch",
principal: "Foo",
target: "fOO",
insensitive: true,
match: false,
},
{
desc: "non-ascii-match",
principal: "🌲",
target: "🌲",
insensitive: true,
match: true,
},
{
desc: "non-ascii-mismatch",
principal: "🌲",
target: "🔥",
insensitive: true,
match: false,
},
{
desc: "sensitive-match",
principal: "Foo",
target: "Foo",
insensitive: false,
match: true,
},
{
desc: "sensitive-mismatch",
principal: "Foo",
target: "foo",
insensitive: false,
match: false,
},
}
for _, tt := range tts {
matcher := NewSSHRouteMatcher(tt.target, "", tt.insensitive)
require.Equal(t, tt.match, matcher.routeToHostname(tt.principal), "desc=%q", tt.desc)
}
}
type mockRouteableServer struct {
name string
hostname string
addr string
useTunnel bool
publicAddr []string
}
func (m mockRouteableServer) GetName() string {
return m.name
}
func (m mockRouteableServer) GetHostname() string {
return m.hostname
}
func (m mockRouteableServer) GetAddr() string {
return m.addr
}
func (m mockRouteableServer) GetUseTunnel() bool {
return m.useTunnel
}
func (m mockRouteableServer) GetPublicAddrs() []string {
return m.publicAddr
}
func TestRouteToServer(t *testing.T) {
t.Parallel()
testUUID := uuid.NewString()
matchAddrServer := mockRouteableServer{
name: "test",
addr: "example.com:1111",
publicAddr: []string{"node:1234", "public.example.com:1111"},
}
tests := []struct {
name string
matcher SSHRouteMatcher
server RouteableServer
assert require.BoolAssertionFunc
}{
{
name: "no match",
matcher: NewSSHRouteMatcher(testUUID, "", true),
server: mockRouteableServer{
name: "test",
addr: "localhost",
hostname: "example.com",
publicAddr: []string{"example.com"},
},
assert: require.False,
},
{
name: "match by server name",
matcher: NewSSHRouteMatcher(testUUID, "", true),
server: mockRouteableServer{
name: testUUID,
addr: "localhost",
hostname: "example.com",
publicAddr: []string{"example.com"},
},
assert: require.True,
},
{
name: "match by hostname over tunnel",
matcher: NewSSHRouteMatcher("example.com", "", true),
server: mockRouteableServer{
name: testUUID,
addr: "addr.example.com",
hostname: "example.com",
publicAddr: []string{"public.example.com"},
useTunnel: true,
},
assert: require.True,
},
{
name: "mismatch hostname over tunnel",
matcher: NewSSHRouteMatcher("example.com", "", true),
server: mockRouteableServer{
name: testUUID,
addr: "example.com",
hostname: "fake.example.com",
publicAddr: []string{"example.com"},
useTunnel: true,
},
assert: require.False,
},
{
name: "match addr",
matcher: NewSSHRouteMatcher("example.com", "1111", true),
server: matchAddrServer,
assert: require.True,
},
{
name: "match addr with empty port",
matcher: NewSSHRouteMatcher("example.com", "", true),
server: matchAddrServer,
assert: require.True,
},
{
name: "mismatch addr with wrong port",
matcher: NewSSHRouteMatcher("example.com", "2222", true),
server: matchAddrServer,
assert: require.False,
},
{
name: "match first public addr",
matcher: NewSSHRouteMatcher("node", "1234", true),
server: matchAddrServer,
assert: require.True,
},
{
name: "match second public addr",
matcher: NewSSHRouteMatcher("public.example.com", "1111", true),
server: matchAddrServer,
assert: require.True,
},
{
name: "match public addr with empty port",
matcher: NewSSHRouteMatcher("public.example.com", "", true),
server: matchAddrServer,
assert: require.True,
},
{
name: "mismatch public addr with wrong port",
matcher: NewSSHRouteMatcher("public.example.com", "2222", true),
server: matchAddrServer,
assert: require.False,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tc.assert(t, tc.matcher.RouteToServer(tc.server))
})
}
}