2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-05-16 11:32:00 -04:00
|
|
|
package ssh
|
2022-03-22 11:03:15 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
|
2022-05-16 11:32:00 -04:00
|
|
|
"github.com/edgelesssys/constellation/internal/deploy/user"
|
2022-06-28 10:51:30 -04:00
|
|
|
"github.com/edgelesssys/constellation/internal/logger"
|
2022-03-22 11:03:15 -04:00
|
|
|
"github.com/spf13/afero"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2022-06-30 09:24:36 -04:00
|
|
|
"go.uber.org/goleak"
|
2022-03-22 11:03:15 -04:00
|
|
|
)
|
|
|
|
|
2022-06-30 09:24:36 -04:00
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
goleak.VerifyTestMain(m)
|
|
|
|
}
|
|
|
|
|
2022-08-09 03:05:05 -04:00
|
|
|
func TestGetAuthorizedKeys(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
authorized map[UserKey]bool
|
|
|
|
want []UserKey
|
|
|
|
}{
|
|
|
|
"success": {
|
|
|
|
authorized: map[UserKey]bool{
|
|
|
|
{Username: "user1", PublicKey: "ssh-rsa test1=="}: true,
|
|
|
|
{Username: "user2", PublicKey: "ssh-rsa test2=="}: true,
|
|
|
|
},
|
|
|
|
want: []UserKey{
|
|
|
|
{Username: "user1", PublicKey: "ssh-rsa test1=="},
|
|
|
|
{Username: "user2", PublicKey: "ssh-rsa test2=="},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"empty": {
|
|
|
|
authorized: map[UserKey]bool{},
|
|
|
|
want: []UserKey(nil),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
|
|
|
|
sshAccess := Access{authorized: tc.authorized}
|
|
|
|
|
|
|
|
keys := sshAccess.GetAuthorizedKeys()
|
|
|
|
assert.ElementsMatch(tc.want, keys)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeployAuthorizedKey(t *testing.T) {
|
2022-05-16 11:32:00 -04:00
|
|
|
authorizedKey := UserKey{
|
|
|
|
Username: "user",
|
|
|
|
PublicKey: "ssh-rsa testkey",
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
2022-04-26 10:54:05 -04:00
|
|
|
fs afero.Fs
|
|
|
|
passwdContents string
|
|
|
|
alreadyDeployed bool
|
|
|
|
readonly bool
|
|
|
|
wantErr bool
|
|
|
|
wantFile bool
|
|
|
|
wantFileContents string
|
2022-03-22 11:03:15 -04:00
|
|
|
}{
|
|
|
|
"deploy works": {
|
2022-04-26 10:54:05 -04:00
|
|
|
fs: afero.NewMemMapFs(),
|
|
|
|
wantErr: false,
|
|
|
|
wantFile: true,
|
2022-06-13 10:23:19 -04:00
|
|
|
wantFileContents: "ssh-rsa testkey\n",
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"appending ssh key works": {
|
2022-06-13 10:23:19 -04:00
|
|
|
fs: memMapFsWithFile("/var/home/user/.ssh/authorized_keys.d/constellation-ssh-keys", "ssh-rsa preexistingkey\n"),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: false,
|
|
|
|
wantFile: true,
|
2022-06-13 10:23:19 -04:00
|
|
|
wantFileContents: "ssh-rsa preexistingkey\nssh-rsa testkey\n",
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"redeployment avoided": {
|
|
|
|
fs: afero.NewMemMapFs(),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: false,
|
2022-03-22 11:03:15 -04:00
|
|
|
alreadyDeployed: true,
|
2022-04-26 10:54:05 -04:00
|
|
|
wantFile: false,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"readonly fs": {
|
2022-05-16 11:32:00 -04:00
|
|
|
fs: afero.NewMemMapFs(),
|
|
|
|
readonly: true,
|
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
2022-05-16 11:32:00 -04:00
|
|
|
userManager := user.NewLinuxUserManagerFake(tc.fs)
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-05-16 11:32:00 -04:00
|
|
|
assert.NoError(afero.WriteFile(userManager.Fs, "/etc/passwd", []byte(tc.passwdContents), 0o755))
|
2022-03-22 11:03:15 -04:00
|
|
|
if tc.readonly {
|
2022-05-16 11:32:00 -04:00
|
|
|
userManager.Fs = afero.NewReadOnlyFs(userManager.Fs)
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
2022-08-09 03:05:05 -04:00
|
|
|
authorized := map[UserKey]bool{}
|
2022-03-22 11:03:15 -04:00
|
|
|
if tc.alreadyDeployed {
|
2022-08-09 03:05:05 -04:00
|
|
|
authorized[UserKey{
|
|
|
|
Username: "user",
|
|
|
|
PublicKey: "ssh-rsa testkey",
|
|
|
|
}] = true
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
2022-06-13 10:23:19 -04:00
|
|
|
sshAccess := Access{
|
2022-06-28 10:51:30 -04:00
|
|
|
log: logger.NewTest(t),
|
2022-05-16 11:32:00 -04:00
|
|
|
userManager: userManager,
|
|
|
|
mux: sync.Mutex{},
|
|
|
|
authorized: authorized,
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
2022-06-13 10:23:19 -04:00
|
|
|
err := sshAccess.DeployAuthorizedKey(context.Background(), authorizedKey)
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-03-22 11:03:15 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantFile {
|
2022-06-13 10:23:19 -04:00
|
|
|
fileContents, err := afero.ReadFile(userManager.Fs, "/var/home/user/.ssh/authorized_keys.d/constellation-ssh-keys")
|
2022-03-22 11:03:15 -04:00
|
|
|
assert.NoError(err)
|
2022-04-26 10:54:05 -04:00
|
|
|
assert.Equal(tc.wantFileContents, string(fileContents))
|
2022-03-22 11:03:15 -04:00
|
|
|
} else {
|
2022-06-13 10:23:19 -04:00
|
|
|
exists, err := afero.Exists(userManager.Fs, "/var/home/user/.ssh/authorized_keys.d/constellation-ssh-keys")
|
2022-03-22 11:03:15 -04:00
|
|
|
assert.NoError(err)
|
|
|
|
assert.False(exists)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func memMapFsWithFile(path string, contents string) afero.Fs {
|
|
|
|
fs := afero.NewMemMapFs()
|
|
|
|
err := afero.WriteFile(fs, path, []byte(contents), 0o755)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return fs
|
|
|
|
}
|