mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-01 13:39:37 +08:00
158 lines
5.0 KiB
Go
158 lines
5.0 KiB
Go
// Copyright 2022 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 x11
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/gravitational/trace"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestXAuthCommands(t *testing.T) {
|
|
if os.Getenv("TELEPORT_XAUTH_TEST") == "" {
|
|
t.Skip("Skipping test as xauth is not enabled")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
tmpDir := t.TempDir()
|
|
xauthFile := filepath.Join(tmpDir, ".Xauthority")
|
|
display, err := ParseDisplay("unix:10")
|
|
require.NoError(t, err)
|
|
|
|
// New xauth file should have no entries
|
|
xauth := NewXAuthCommand(ctx, xauthFile)
|
|
xauthEntry, err := xauth.ReadEntry(display)
|
|
require.Error(t, err)
|
|
require.True(t, trace.IsNotFound(err))
|
|
require.Nil(t, xauthEntry)
|
|
|
|
// Add trusted xauth entry
|
|
trustedXauthEntry, err := NewFakeXAuthEntry(display)
|
|
require.NoError(t, err)
|
|
xauth = NewXAuthCommand(ctx, xauthFile)
|
|
err = xauth.AddEntry(*trustedXauthEntry)
|
|
require.NoError(t, err)
|
|
|
|
// Read back the xauth entry
|
|
xauth = NewXAuthCommand(ctx, xauthFile)
|
|
xauthEntry, err = xauth.ReadEntry(display)
|
|
require.NoError(t, err)
|
|
require.Equal(t, trustedXauthEntry, xauthEntry)
|
|
|
|
// Remove xauth entries
|
|
xauth = NewXAuthCommand(ctx, xauthFile)
|
|
err = xauth.RemoveEntries(xauthEntry.Display)
|
|
require.NoError(t, err)
|
|
|
|
xauth = NewXAuthCommand(ctx, xauthFile)
|
|
xauthEntry, err = xauth.ReadEntry(display)
|
|
require.Error(t, err)
|
|
require.True(t, trace.IsNotFound(err))
|
|
require.Nil(t, xauthEntry)
|
|
|
|
// TODO(Joerger): Currently this test will only run/pass locally if you have $DISPLAY
|
|
// set. We need to add Xorg to the buildbox and start an XServer in order to run
|
|
// this test in CI. Additionally, Xorg and x11-apps can be used to add more tests
|
|
// and rework current tests which depend on fake display listeners instead.
|
|
localDisplay, err := GetXDisplay()
|
|
if trace.IsBadParameter(err) {
|
|
t.Skip("skipping xauth generate test, DISPLAY isn't set")
|
|
}
|
|
xauth = NewXAuthCommand(ctx, xauthFile)
|
|
err = xauth.GenerateUntrustedCookie(localDisplay, 0)
|
|
require.NoError(t, err)
|
|
|
|
xauth = NewXAuthCommand(ctx, xauthFile)
|
|
xauthEntry, err = xauth.ReadEntry(localDisplay)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, xauthEntry)
|
|
}
|
|
|
|
func TestReadAndRewriteXAuthPacket(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
realXAuthEntry, err := NewFakeXAuthEntry(Display{})
|
|
require.NoError(t, err)
|
|
realXAuthPacket := mockXAuthPacket(t, realXAuthEntry)
|
|
|
|
spoofedXAuthEntry, err := realXAuthEntry.SpoofXAuthEntry()
|
|
require.NoError(t, err)
|
|
spoofedXAuthPacket := mockXAuthPacket(t, spoofedXAuthEntry)
|
|
|
|
otherXAuthEntry, err := NewFakeXAuthEntry(Display{})
|
|
require.NoError(t, err)
|
|
otherXAuthPacket := mockXAuthPacket(t, otherXAuthEntry)
|
|
|
|
t.Run("match and replace xauth packet", func(t *testing.T) {
|
|
in := bytes.NewBuffer(spoofedXAuthPacket)
|
|
out, err := ReadAndRewriteXAuthPacket(in, spoofedXAuthEntry, realXAuthEntry)
|
|
require.NoError(t, err)
|
|
require.Equal(t, realXAuthPacket, out)
|
|
})
|
|
|
|
t.Run("xauth packet doesn't match", func(t *testing.T) {
|
|
in := bytes.NewBuffer(otherXAuthPacket)
|
|
out, err := ReadAndRewriteXAuthPacket(in, spoofedXAuthEntry, realXAuthEntry)
|
|
require.True(t, trace.IsAccessDenied(err))
|
|
require.Empty(t, out)
|
|
})
|
|
|
|
t.Run("xauth packet missing xauth data", func(t *testing.T) {
|
|
in := bytes.NewBuffer(mockXAuthPacketInitial(len(mitMagicCookieProto), mitMagicCookieSize))
|
|
out, err := ReadAndRewriteXAuthPacket(in, spoofedXAuthEntry, realXAuthEntry)
|
|
require.Error(t, err)
|
|
require.Empty(t, out)
|
|
})
|
|
|
|
t.Run("xauth packet empty", func(t *testing.T) {
|
|
out, err := ReadAndRewriteXAuthPacket(bytes.NewBuffer([]byte{}), spoofedXAuthEntry, realXAuthEntry)
|
|
require.Error(t, err)
|
|
require.Empty(t, out)
|
|
})
|
|
}
|
|
|
|
// mockXAuthPacket creates an xauth packet for the given xauth entry.
|
|
func mockXAuthPacket(t *testing.T, entry *XAuthEntry) []byte {
|
|
authData, err := hex.DecodeString(entry.Cookie)
|
|
require.NoError(t, err)
|
|
|
|
var xauthPacket []byte
|
|
initPacket := mockXAuthPacketInitial(len(entry.Proto), len(authData))
|
|
xauthPacket = append(xauthPacket, initPacket...)
|
|
xauthPacket = append(xauthPacket, []byte(entry.Proto)...)
|
|
xauthPacket = append(xauthPacket, 0, 0)
|
|
xauthPacket = append(xauthPacket, authData...)
|
|
return xauthPacket
|
|
}
|
|
|
|
// mockXAuthPacketInitial creates the fixed size initial
|
|
// portion of an xauth packet, with little endian encoding.
|
|
func mockXAuthPacketInitial(authProtoLen, authDataLen int) []byte {
|
|
initData := make([]byte, 12)
|
|
initData[0] = 'l'
|
|
e := binary.LittleEndian
|
|
e.PutUint16(initData[6:8], uint16(authProtoLen))
|
|
e.PutUint16(initData[8:10], uint16(authDataLen))
|
|
return initData
|
|
}
|