github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/keymanager/keymanager_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package keymanager_test 5 6 import ( 7 "fmt" 8 "strings" 9 10 gc "launchpad.net/gocheck" 11 12 jujutesting "launchpad.net/juju-core/juju/testing" 13 "launchpad.net/juju-core/state/api/params" 14 "launchpad.net/juju-core/state/apiserver/common" 15 "launchpad.net/juju-core/state/apiserver/keymanager" 16 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing" 17 apiservertesting "launchpad.net/juju-core/state/apiserver/testing" 18 statetesting "launchpad.net/juju-core/state/testing" 19 "launchpad.net/juju-core/utils/ssh" 20 sshtesting "launchpad.net/juju-core/utils/ssh/testing" 21 ) 22 23 type keyManagerSuite struct { 24 jujutesting.JujuConnSuite 25 26 keymanager *keymanager.KeyManagerAPI 27 resources *common.Resources 28 authoriser apiservertesting.FakeAuthorizer 29 } 30 31 var _ = gc.Suite(&keyManagerSuite{}) 32 33 func (s *keyManagerSuite) SetUpTest(c *gc.C) { 34 s.JujuConnSuite.SetUpTest(c) 35 s.resources = common.NewResources() 36 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 37 38 s.authoriser = apiservertesting.FakeAuthorizer{ 39 Tag: "user-admin", 40 LoggedIn: true, 41 Client: true, 42 } 43 var err error 44 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, s.authoriser) 45 c.Assert(err, gc.IsNil) 46 } 47 48 func (s *keyManagerSuite) TestNewKeyManagerAPIAcceptsClient(c *gc.C) { 49 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, s.authoriser) 50 c.Assert(err, gc.IsNil) 51 c.Assert(endPoint, gc.NotNil) 52 } 53 54 func (s *keyManagerSuite) TestNewKeyManagerAPIAcceptsEnvironManager(c *gc.C) { 55 anAuthoriser := s.authoriser 56 anAuthoriser.EnvironManager = true 57 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 58 c.Assert(err, gc.IsNil) 59 c.Assert(endPoint, gc.NotNil) 60 } 61 62 func (s *keyManagerSuite) TestNewKeyManagerAPIRefusesNonClient(c *gc.C) { 63 anAuthoriser := s.authoriser 64 anAuthoriser.Client = false 65 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 66 c.Assert(endPoint, gc.IsNil) 67 c.Assert(err, gc.ErrorMatches, "permission denied") 68 } 69 70 func (s *keyManagerSuite) TestNewKeyManagerAPIRefusesNonEnvironManager(c *gc.C) { 71 anAuthoriser := s.authoriser 72 anAuthoriser.Client = false 73 anAuthoriser.MachineAgent = true 74 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 75 c.Assert(endPoint, gc.IsNil) 76 c.Assert(err, gc.ErrorMatches, "permission denied") 77 } 78 79 func (s *keyManagerSuite) setAuthorisedKeys(c *gc.C, keys string) { 80 err := statetesting.UpdateConfig(s.State, map[string]interface{}{"authorized-keys": keys}) 81 c.Assert(err, gc.IsNil) 82 envConfig, err := s.State.EnvironConfig() 83 c.Assert(err, gc.IsNil) 84 c.Assert(envConfig.AuthorizedKeys(), gc.Equals, keys) 85 } 86 87 func (s *keyManagerSuite) TestListKeys(c *gc.C) { 88 key1 := sshtesting.ValidKeyOne.Key + " user@host" 89 key2 := sshtesting.ValidKeyTwo.Key 90 s.setAuthorisedKeys(c, strings.Join([]string{key1, key2, "bad key"}, "\n")) 91 92 args := params.ListSSHKeys{ 93 Entities: params.Entities{[]params.Entity{ 94 {Tag: "admin"}, 95 {Tag: "invalid"}, 96 }}, 97 Mode: ssh.FullKeys, 98 } 99 results, err := s.keymanager.ListKeys(args) 100 c.Assert(err, gc.IsNil) 101 c.Assert(results, gc.DeepEquals, params.StringsResults{ 102 Results: []params.StringsResult{ 103 {Result: []string{key1, key2, "Invalid key: bad key"}}, 104 {Error: apiservertesting.ErrUnauthorized}, 105 }, 106 }) 107 } 108 109 func (s *keyManagerSuite) assertEnvironKeys(c *gc.C, expected []string) { 110 envConfig, err := s.State.EnvironConfig() 111 c.Assert(err, gc.IsNil) 112 keys := envConfig.AuthorizedKeys() 113 c.Assert(keys, gc.Equals, strings.Join(expected, "\n")) 114 } 115 116 func (s *keyManagerSuite) TestAddKeys(c *gc.C) { 117 key1 := sshtesting.ValidKeyOne.Key + " user@host" 118 key2 := sshtesting.ValidKeyTwo.Key 119 initialKeys := []string{key1, key2, "bad key"} 120 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 121 122 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 123 args := params.ModifyUserSSHKeys{ 124 User: "admin", 125 Keys: []string{key2, newKey, "invalid-key"}, 126 } 127 results, err := s.keymanager.AddKeys(args) 128 c.Assert(err, gc.IsNil) 129 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 130 Results: []params.ErrorResult{ 131 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 132 {Error: nil}, 133 {Error: apiservertesting.ServerError("invalid ssh key: invalid-key")}, 134 }, 135 }) 136 s.assertEnvironKeys(c, append(initialKeys, newKey)) 137 } 138 139 func (s *keyManagerSuite) TestAddJujuSystemKey(c *gc.C) { 140 anAuthoriser := s.authoriser 141 anAuthoriser.Client = false 142 anAuthoriser.EnvironManager = true 143 anAuthoriser.Tag = "machine-0" 144 var err error 145 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 146 c.Assert(err, gc.IsNil) 147 key1 := sshtesting.ValidKeyOne.Key + " user@host" 148 key2 := sshtesting.ValidKeyTwo.Key 149 initialKeys := []string{key1, key2} 150 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 151 152 newKey := sshtesting.ValidKeyThree.Key + " juju-system-key" 153 args := params.ModifyUserSSHKeys{ 154 User: "juju-system-key", 155 Keys: []string{newKey}, 156 } 157 results, err := s.keymanager.AddKeys(args) 158 c.Assert(err, gc.IsNil) 159 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 160 Results: []params.ErrorResult{ 161 {Error: nil}, 162 }, 163 }) 164 s.assertEnvironKeys(c, append(initialKeys, newKey)) 165 } 166 167 func (s *keyManagerSuite) TestAddJujuSystemKeyNotMachine(c *gc.C) { 168 anAuthoriser := s.authoriser 169 anAuthoriser.Client = false 170 anAuthoriser.EnvironManager = true 171 anAuthoriser.Tag = "unit-wordpress-0" 172 var err error 173 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 174 c.Assert(err, gc.IsNil) 175 key1 := sshtesting.ValidKeyOne.Key 176 s.setAuthorisedKeys(c, key1) 177 178 newKey := sshtesting.ValidKeyThree.Key + " juju-system-key" 179 args := params.ModifyUserSSHKeys{ 180 User: "juju-system-key", 181 Keys: []string{newKey}, 182 } 183 _, err = s.keymanager.AddKeys(args) 184 c.Assert(err, gc.ErrorMatches, "permission denied") 185 s.assertEnvironKeys(c, []string{key1}) 186 } 187 188 func (s *keyManagerSuite) TestDeleteKeys(c *gc.C) { 189 key1 := sshtesting.ValidKeyOne.Key + " user@host" 190 key2 := sshtesting.ValidKeyTwo.Key 191 initialKeys := []string{key1, key2, "bad key"} 192 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 193 194 args := params.ModifyUserSSHKeys{ 195 User: "admin", 196 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"}, 197 } 198 results, err := s.keymanager.DeleteKeys(args) 199 c.Assert(err, gc.IsNil) 200 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 201 Results: []params.ErrorResult{ 202 {Error: nil}, 203 {Error: apiservertesting.ServerError("invalid ssh key: " + sshtesting.ValidKeyThree.Fingerprint)}, 204 {Error: apiservertesting.ServerError("invalid ssh key: invalid-key")}, 205 }, 206 }) 207 s.assertEnvironKeys(c, []string{"bad key", key1}) 208 } 209 210 func (s *keyManagerSuite) TestCannotDeleteAllKeys(c *gc.C) { 211 key1 := sshtesting.ValidKeyOne.Key + " user@host" 212 key2 := sshtesting.ValidKeyTwo.Key 213 initialKeys := []string{key1, key2} 214 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 215 216 args := params.ModifyUserSSHKeys{ 217 User: "admin", 218 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, "user@host"}, 219 } 220 _, err := s.keymanager.DeleteKeys(args) 221 c.Assert(err, gc.ErrorMatches, "cannot delete all keys") 222 s.assertEnvironKeys(c, initialKeys) 223 } 224 225 func (s *keyManagerSuite) assertInvalidUserOperation(c *gc.C, runTestLogic func(args params.ModifyUserSSHKeys) error) { 226 initialKey := sshtesting.ValidKeyOne.Key + " user@host" 227 s.setAuthorisedKeys(c, initialKey) 228 229 // Set up the params. 230 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 231 args := params.ModifyUserSSHKeys{ 232 User: "invalid", 233 Keys: []string{newKey}, 234 } 235 // Run the required test code and check the error. 236 err := runTestLogic(args) 237 c.Assert(err, gc.DeepEquals, apiservertesting.ErrUnauthorized) 238 239 // No environ changes. 240 s.assertEnvironKeys(c, []string{initialKey}) 241 } 242 243 func (s *keyManagerSuite) TestAddKeysInvalidUser(c *gc.C) { 244 s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error { 245 _, err := s.keymanager.AddKeys(args) 246 return err 247 }) 248 } 249 250 func (s *keyManagerSuite) TestDeleteKeysInvalidUser(c *gc.C) { 251 s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error { 252 _, err := s.keymanager.DeleteKeys(args) 253 return err 254 }) 255 } 256 257 func (s *keyManagerSuite) TestImportKeys(c *gc.C) { 258 s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport) 259 260 key1 := sshtesting.ValidKeyOne.Key + " user@host" 261 key2 := sshtesting.ValidKeyTwo.Key 262 key3 := sshtesting.ValidKeyThree.Key 263 initialKeys := []string{key1, key2, "bad key"} 264 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 265 266 args := params.ModifyUserSSHKeys{ 267 User: "admin", 268 Keys: []string{"lp:existing", "lp:validuser", "invalid-key"}, 269 } 270 results, err := s.keymanager.ImportKeys(args) 271 c.Assert(err, gc.IsNil) 272 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 273 Results: []params.ErrorResult{ 274 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 275 {Error: nil}, 276 {Error: apiservertesting.ServerError("invalid ssh key id: invalid-key")}, 277 }, 278 }) 279 s.assertEnvironKeys(c, append(initialKeys, key3)) 280 } 281 282 func (s *keyManagerSuite) TestCallSSHImportId(c *gc.C) { 283 c.Skip("the landing bot does not run ssh-import-id successfully") 284 output, err := keymanager.RunSSHImportId("lp:wallyworld") 285 c.Assert(err, gc.IsNil) 286 lines := strings.Split(output, "\n") 287 var key string 288 for _, line := range lines { 289 if !strings.HasPrefix(line, "ssh-") { 290 continue 291 } 292 _, _, err := ssh.KeyFingerprint(line) 293 if err == nil { 294 key = line 295 } 296 } 297 c.Assert(key, gc.Not(gc.Equals), "") 298 }