1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
package authenticationworker_test
11
jc "github.com/juju/testing/checkers"
12
"github.com/juju/utils/ssh"
13
sshtesting "github.com/juju/utils/ssh/testing"
14
gc "gopkg.in/check.v1"
15
"gopkg.in/juju/names.v2"
17
"github.com/juju/juju/agent"
18
"github.com/juju/juju/api"
19
"github.com/juju/juju/api/keyupdater"
20
jujutesting "github.com/juju/juju/juju/testing"
21
"github.com/juju/juju/state"
22
coretesting "github.com/juju/juju/testing"
23
"github.com/juju/juju/worker"
24
"github.com/juju/juju/worker/authenticationworker"
27
type workerSuite struct {
28
jujutesting.JujuConnSuite
29
stateMachine *state.Machine
30
machine *state.Machine
31
keyupdaterApi *keyupdater.State
37
var _ = gc.Suite(&workerSuite{})
39
func (s *workerSuite) SetUpTest(c *gc.C) {
40
//TODO(bogdanteleaga): Fix this on windows
41
if runtime.GOOS == "windows" {
42
c.Skip("bug 1403084: authentication worker not implemented yet on windows")
44
s.JujuConnSuite.SetUpTest(c)
45
// Default ssh user is currently "ubuntu".
46
c.Assert(authenticationworker.SSHUser, gc.Equals, "ubuntu")
47
// Set the ssh user to empty (the current user) as required by the test infrastructure.
48
s.PatchValue(&authenticationworker.SSHUser, "")
50
// Replace the default dummy key in the test environment with a valid one.
51
// This will be added to the ssh authorised keys when the agent starts.
52
s.setAuthorisedKeys(c, sshtesting.ValidKeyOne.Key+" firstuser@host")
53
// Record the existing key with its prefix for testing later.
54
s.existingEnvKey = sshtesting.ValidKeyOne.Key + " Juju:firstuser@host"
56
// Set up an existing key (which is not in the environment) in the ssh authorised_keys file.
57
s.existingKeys = []string{sshtesting.ValidKeyTwo.Key + " existinguser@host"}
58
err := ssh.AddKeys(authenticationworker.SSHUser, s.existingKeys...)
59
c.Assert(err, jc.ErrorIsNil)
61
var apiRoot api.Connection
62
apiRoot, s.machine = s.OpenAPIAsNewMachine(c)
63
c.Assert(apiRoot, gc.NotNil)
64
s.keyupdaterApi = keyupdater.NewState(apiRoot)
65
c.Assert(s.keyupdaterApi, gc.NotNil)
68
func stop(c *gc.C, w worker.Worker) {
69
c.Assert(worker.Stop(w), gc.IsNil)
72
type mockConfig struct {
78
func (mock *mockConfig) Tag() names.Tag {
82
func agentConfig(c *gc.C, tag names.MachineTag) *mockConfig {
83
return &mockConfig{c: c, tag: tag}
86
func (s *workerSuite) setAuthorisedKeys(c *gc.C, keys ...string) {
87
keyStr := strings.Join(keys, "\n")
88
err := s.BackingState.UpdateModelConfig(map[string]interface{}{"authorized-keys": keyStr}, nil, nil)
89
c.Assert(err, jc.ErrorIsNil)
90
s.BackingState.StartSync()
93
func (s *workerSuite) waitSSHKeys(c *gc.C, expected []string) {
94
timeout := time.After(coretesting.LongWait)
98
c.Fatalf("timeout while waiting for authoirsed ssh keys to change")
99
case <-time.After(coretesting.ShortWait):
100
keys, err := ssh.ListKeys(authenticationworker.SSHUser, ssh.FullKeys)
101
c.Assert(err, jc.ErrorIsNil)
102
keysStr := strings.Join(keys, "\n")
103
expectedStr := strings.Join(expected, "\n")
104
if expectedStr != keysStr {
112
func (s *workerSuite) TestKeyUpdateRetainsExisting(c *gc.C) {
113
authWorker, err := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
114
c.Assert(err, jc.ErrorIsNil)
115
defer stop(c, authWorker)
117
newKey := sshtesting.ValidKeyThree.Key + " user@host"
118
s.setAuthorisedKeys(c, newKey)
119
newKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:user@host"
120
s.waitSSHKeys(c, append(s.existingKeys, newKeyWithCommentPrefix))
123
func (s *workerSuite) TestNewKeysInJujuAreSavedOnStartup(c *gc.C) {
124
newKey := sshtesting.ValidKeyThree.Key + " user@host"
125
s.setAuthorisedKeys(c, newKey)
127
authWorker, err := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
128
c.Assert(err, jc.ErrorIsNil)
129
defer stop(c, authWorker)
131
newKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:user@host"
132
s.waitSSHKeys(c, append(s.existingKeys, newKeyWithCommentPrefix))
135
func (s *workerSuite) TestDeleteKey(c *gc.C) {
136
authWorker, err := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
137
c.Assert(err, jc.ErrorIsNil)
138
defer stop(c, authWorker)
141
anotherKey := sshtesting.ValidKeyThree.Key + " another@host"
142
s.setAuthorisedKeys(c, s.existingEnvKey, anotherKey)
143
anotherKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:another@host"
144
s.waitSSHKeys(c, append(s.existingKeys, s.existingEnvKey, anotherKeyWithCommentPrefix))
146
// Delete the original key and check anotherKey plus the existing keys remain.
147
s.setAuthorisedKeys(c, anotherKey)
148
s.waitSSHKeys(c, append(s.existingKeys, anotherKeyWithCommentPrefix))
151
func (s *workerSuite) TestMultipleChanges(c *gc.C) {
152
authWorker, err := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
153
c.Assert(err, jc.ErrorIsNil)
154
defer stop(c, authWorker)
155
s.waitSSHKeys(c, append(s.existingKeys, s.existingEnvKey))
157
// Perform a set to add a key and delete a key.
159
// deleted: key 1 (existing env key)
160
s.setAuthorisedKeys(c, sshtesting.ValidKeyThree.Key+" yetanother@host")
161
yetAnotherKeyWithComment := sshtesting.ValidKeyThree.Key + " Juju:yetanother@host"
162
s.waitSSHKeys(c, append(s.existingKeys, yetAnotherKeyWithComment))
165
func (s *workerSuite) TestWorkerRestart(c *gc.C) {
166
authWorker, err := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
167
c.Assert(err, jc.ErrorIsNil)
168
defer stop(c, authWorker)
169
s.waitSSHKeys(c, append(s.existingKeys, s.existingEnvKey))
171
// Stop the worker and delete and add keys from the environment while it is down.
173
// deleted: key 1 (existing env key)
175
s.setAuthorisedKeys(c, sshtesting.ValidKeyThree.Key+" yetanother@host")
177
// Restart the worker and check that the ssh auth keys are as expected.
178
authWorker, err = authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
179
c.Assert(err, jc.ErrorIsNil)
180
defer stop(c, authWorker)
182
yetAnotherKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:yetanother@host"
183
s.waitSSHKeys(c, append(s.existingKeys, yetAnotherKeyWithCommentPrefix))