github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 jc "github.com/juju/testing/checkers" 11 "github.com/juju/utils/ssh" 12 sshtesting "github.com/juju/utils/ssh/testing" 13 gc "gopkg.in/check.v1" 14 "gopkg.in/juju/names.v2" 15 16 "github.com/juju/juju/apiserver/common" 17 commontesting "github.com/juju/juju/apiserver/common/testing" 18 "github.com/juju/juju/apiserver/keymanager" 19 keymanagertesting "github.com/juju/juju/apiserver/keymanager/testing" 20 "github.com/juju/juju/apiserver/params" 21 apiservertesting "github.com/juju/juju/apiserver/testing" 22 jujutesting "github.com/juju/juju/juju/testing" 23 ) 24 25 type keyManagerSuite struct { 26 jujutesting.JujuConnSuite 27 28 keymanager *keymanager.KeyManagerAPI 29 resources *common.Resources 30 authoriser apiservertesting.FakeAuthorizer 31 32 commontesting.BlockHelper 33 } 34 35 var _ = gc.Suite(&keyManagerSuite{}) 36 37 func (s *keyManagerSuite) SetUpTest(c *gc.C) { 38 s.JujuConnSuite.SetUpTest(c) 39 s.resources = common.NewResources() 40 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 41 42 s.authoriser = apiservertesting.FakeAuthorizer{ 43 Tag: s.AdminUserTag(c), 44 } 45 var err error 46 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, s.authoriser) 47 c.Assert(err, jc.ErrorIsNil) 48 49 s.BlockHelper = commontesting.NewBlockHelper(s.APIState) 50 s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() }) 51 } 52 53 func (s *keyManagerSuite) TestNewKeyManagerAPIAcceptsClient(c *gc.C) { 54 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, s.authoriser) 55 c.Assert(err, jc.ErrorIsNil) 56 c.Assert(endPoint, gc.NotNil) 57 } 58 59 func (s *keyManagerSuite) TestNewKeyManagerAPIAcceptsEnvironManager(c *gc.C) { 60 anAuthoriser := s.authoriser 61 anAuthoriser.EnvironManager = true 62 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 63 c.Assert(err, jc.ErrorIsNil) 64 c.Assert(endPoint, gc.NotNil) 65 } 66 67 func (s *keyManagerSuite) TestNewKeyManagerAPIRefusesNonClient(c *gc.C) { 68 anAuthoriser := s.authoriser 69 anAuthoriser.Tag = names.NewUnitTag("mysql/0") 70 anAuthoriser.EnvironManager = false 71 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 72 c.Assert(endPoint, gc.IsNil) 73 c.Assert(err, gc.ErrorMatches, "permission denied") 74 } 75 76 func (s *keyManagerSuite) TestNewKeyManagerAPIRefusesNonEnvironManager(c *gc.C) { 77 anAuthoriser := s.authoriser 78 anAuthoriser.Tag = names.NewMachineTag("99") 79 anAuthoriser.EnvironManager = false 80 endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 81 c.Assert(endPoint, gc.IsNil) 82 c.Assert(err, gc.ErrorMatches, "permission denied") 83 } 84 85 func (s *keyManagerSuite) setAuthorisedKeys(c *gc.C, keys string) { 86 err := s.State.UpdateModelConfig(map[string]interface{}{"authorized-keys": keys}, nil, nil) 87 c.Assert(err, jc.ErrorIsNil) 88 envConfig, err := s.State.ModelConfig() 89 c.Assert(err, jc.ErrorIsNil) 90 c.Assert(envConfig.AuthorizedKeys(), gc.Equals, keys) 91 } 92 93 func (s *keyManagerSuite) TestListKeys(c *gc.C) { 94 key1 := sshtesting.ValidKeyOne.Key + " user@host" 95 key2 := sshtesting.ValidKeyTwo.Key 96 s.setAuthorisedKeys(c, strings.Join([]string{key1, key2, "bad key"}, "\n")) 97 98 args := params.ListSSHKeys{ 99 Entities: params.Entities{[]params.Entity{ 100 {Tag: s.AdminUserTag(c).Name()}, 101 {Tag: "invalid"}, 102 }}, 103 Mode: ssh.FullKeys, 104 } 105 results, err := s.keymanager.ListKeys(args) 106 c.Assert(err, jc.ErrorIsNil) 107 c.Assert(results, gc.DeepEquals, params.StringsResults{ 108 Results: []params.StringsResult{ 109 {Result: []string{key1, key2, "Invalid key: bad key"}}, 110 {Result: []string{key1, key2, "Invalid key: bad key"}}, 111 }, 112 }) 113 } 114 115 func (s *keyManagerSuite) TestListKeysHidesJujuInternal(c *gc.C) { 116 key1 := sshtesting.ValidKeyOne.Key + " juju-client-key" 117 key2 := sshtesting.ValidKeyTwo.Key + " juju-system-key" 118 s.setAuthorisedKeys(c, strings.Join([]string{key1, key2}, "\n")) 119 120 args := params.ListSSHKeys{ 121 Entities: params.Entities{[]params.Entity{ 122 {Tag: s.AdminUserTag(c).Name()}, 123 }}, 124 Mode: ssh.FullKeys, 125 } 126 results, err := s.keymanager.ListKeys(args) 127 c.Assert(err, jc.ErrorIsNil) 128 c.Assert(results, gc.DeepEquals, params.StringsResults{ 129 Results: []params.StringsResult{ 130 {Result: nil}, 131 }, 132 }) 133 } 134 135 func (s *keyManagerSuite) assertEnvironKeys(c *gc.C, expected []string) { 136 envConfig, err := s.State.ModelConfig() 137 c.Assert(err, jc.ErrorIsNil) 138 keys := envConfig.AuthorizedKeys() 139 c.Assert(keys, gc.Equals, strings.Join(expected, "\n")) 140 } 141 142 func (s *keyManagerSuite) TestAddKeys(c *gc.C) { 143 key1 := sshtesting.ValidKeyOne.Key + " user@host" 144 key2 := sshtesting.ValidKeyTwo.Key 145 initialKeys := []string{key1, key2, "bad key"} 146 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 147 148 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 149 args := params.ModifyUserSSHKeys{ 150 User: s.AdminUserTag(c).Name(), 151 Keys: []string{key2, newKey, "invalid-key"}, 152 } 153 results, err := s.keymanager.AddKeys(args) 154 c.Assert(err, jc.ErrorIsNil) 155 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 156 Results: []params.ErrorResult{ 157 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 158 {Error: nil}, 159 {Error: apiservertesting.ServerError("invalid ssh key: invalid-key")}, 160 }, 161 }) 162 s.assertEnvironKeys(c, append(initialKeys, newKey)) 163 } 164 165 func (s *keyManagerSuite) TestBlockAddKeys(c *gc.C) { 166 key1 := sshtesting.ValidKeyOne.Key + " user@host" 167 key2 := sshtesting.ValidKeyTwo.Key 168 initialKeys := []string{key1, key2, "bad key"} 169 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 170 171 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 172 args := params.ModifyUserSSHKeys{ 173 User: s.AdminUserTag(c).Name(), 174 Keys: []string{key2, newKey, "invalid-key"}, 175 } 176 177 s.BlockAllChanges(c, "TestBlockAddKeys") 178 _, err := s.keymanager.AddKeys(args) 179 // Check that the call is blocked 180 s.AssertBlocked(c, err, "TestBlockAddKeys") 181 s.assertEnvironKeys(c, initialKeys) 182 } 183 184 func (s *keyManagerSuite) TestAddJujuSystemKey(c *gc.C) { 185 anAuthoriser := s.authoriser 186 anAuthoriser.EnvironManager = true 187 anAuthoriser.Tag = names.NewMachineTag("0") 188 var err error 189 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 190 c.Assert(err, jc.ErrorIsNil) 191 key1 := sshtesting.ValidKeyOne.Key + " user@host" 192 key2 := sshtesting.ValidKeyTwo.Key 193 initialKeys := []string{key1, key2} 194 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 195 196 newKey := sshtesting.ValidKeyThree.Key + " juju-system-key" 197 args := params.ModifyUserSSHKeys{ 198 User: "juju-system-key", 199 Keys: []string{newKey}, 200 } 201 results, err := s.keymanager.AddKeys(args) 202 c.Assert(err, jc.ErrorIsNil) 203 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 204 Results: []params.ErrorResult{ 205 {Error: nil}, 206 }, 207 }) 208 s.assertEnvironKeys(c, append(initialKeys, newKey)) 209 } 210 211 func (s *keyManagerSuite) TestAddJujuSystemKeyNotMachine(c *gc.C) { 212 anAuthoriser := s.authoriser 213 anAuthoriser.EnvironManager = true 214 anAuthoriser.Tag = names.NewUnitTag("wordpress/0") 215 var err error 216 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 217 c.Assert(err, jc.ErrorIsNil) 218 key1 := sshtesting.ValidKeyOne.Key 219 s.setAuthorisedKeys(c, key1) 220 221 newKey := sshtesting.ValidKeyThree.Key + " juju-system-key" 222 args := params.ModifyUserSSHKeys{ 223 User: "juju-system-key", 224 Keys: []string{newKey}, 225 } 226 _, err = s.keymanager.AddKeys(args) 227 c.Assert(err, gc.ErrorMatches, "permission denied") 228 c.Assert(params.ErrCode(err), gc.Equals, params.CodeUnauthorized) 229 s.assertEnvironKeys(c, []string{key1}) 230 } 231 232 func (s *keyManagerSuite) TestDeleteKeys(c *gc.C) { 233 key1 := sshtesting.ValidKeyOne.Key + " user@host" 234 key2 := sshtesting.ValidKeyTwo.Key 235 initialKeys := []string{key1, key2, "bad key"} 236 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 237 238 args := params.ModifyUserSSHKeys{ 239 User: s.AdminUserTag(c).Name(), 240 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"}, 241 } 242 results, err := s.keymanager.DeleteKeys(args) 243 c.Assert(err, jc.ErrorIsNil) 244 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 245 Results: []params.ErrorResult{ 246 {Error: nil}, 247 {Error: apiservertesting.ServerError("invalid ssh key: " + sshtesting.ValidKeyThree.Fingerprint)}, 248 {Error: apiservertesting.ServerError("invalid ssh key: invalid-key")}, 249 }, 250 }) 251 s.assertEnvironKeys(c, []string{key1, "bad key"}) 252 } 253 254 func (s *keyManagerSuite) TestDeleteKeysNotJujuInternal(c *gc.C) { 255 key1 := sshtesting.ValidKeyOne.Key + " juju-client-key" 256 key2 := sshtesting.ValidKeyTwo.Key + " juju-system-key" 257 key3 := sshtesting.ValidKeyThree.Key + " a user key" 258 initialKeys := []string{key1, key2, key3} 259 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 260 261 args := params.ModifyUserSSHKeys{ 262 User: s.AdminUserTag(c).Name(), 263 Keys: []string{"juju-client-key", "juju-system-key"}, 264 } 265 results, err := s.keymanager.DeleteKeys(args) 266 c.Check(results, gc.DeepEquals, params.ErrorResults{ 267 Results: []params.ErrorResult{ 268 {Error: apiservertesting.ServerError("may not delete internal key: juju-client-key")}, 269 {Error: apiservertesting.ServerError("may not delete internal key: juju-system-key")}, 270 }, 271 }) 272 c.Assert(err, jc.ErrorIsNil) 273 s.assertEnvironKeys(c, initialKeys) 274 } 275 276 func (s *keyManagerSuite) TestBlockDeleteKeys(c *gc.C) { 277 key1 := sshtesting.ValidKeyOne.Key + " user@host" 278 key2 := sshtesting.ValidKeyTwo.Key 279 initialKeys := []string{key1, key2, "bad key"} 280 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 281 282 args := params.ModifyUserSSHKeys{ 283 User: s.AdminUserTag(c).Name(), 284 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"}, 285 } 286 287 s.BlockAllChanges(c, "TestBlockDeleteKeys") 288 _, err := s.keymanager.DeleteKeys(args) 289 // Check that the call is blocked 290 s.AssertBlocked(c, err, "TestBlockDeleteKeys") 291 s.assertEnvironKeys(c, initialKeys) 292 } 293 294 func (s *keyManagerSuite) TestCannotDeleteAllKeys(c *gc.C) { 295 key1 := sshtesting.ValidKeyOne.Key + " user@host" 296 key2 := sshtesting.ValidKeyTwo.Key 297 initialKeys := []string{key1, key2} 298 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 299 300 args := params.ModifyUserSSHKeys{ 301 User: s.AdminUserTag(c).Name(), 302 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, "user@host"}, 303 } 304 _, err := s.keymanager.DeleteKeys(args) 305 c.Assert(err, gc.ErrorMatches, "cannot delete all keys") 306 s.assertEnvironKeys(c, initialKeys) 307 } 308 309 func (s *keyManagerSuite) assertInvalidUserOperation(c *gc.C, runTestLogic func(args params.ModifyUserSSHKeys) error) { 310 initialKey := sshtesting.ValidKeyOne.Key + " user@host" 311 s.setAuthorisedKeys(c, initialKey) 312 313 // Set up the params. 314 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 315 args := params.ModifyUserSSHKeys{ 316 User: "invalid", 317 Keys: []string{newKey}, 318 } 319 // Run the required test code and check the error. 320 err := runTestLogic(args) 321 c.Assert(err, gc.DeepEquals, apiservertesting.ErrUnauthorized) 322 323 // No environ changes. 324 s.assertEnvironKeys(c, []string{initialKey}) 325 } 326 327 func (s *keyManagerSuite) TestAddKeysInvalidUser(c *gc.C) { 328 c.Skip("no user validation done yet") 329 s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error { 330 _, err := s.keymanager.AddKeys(args) 331 return err 332 }) 333 } 334 335 func (s *keyManagerSuite) TestDeleteKeysInvalidUser(c *gc.C) { 336 c.Skip("no user validation done yet") 337 s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error { 338 _, err := s.keymanager.DeleteKeys(args) 339 return err 340 }) 341 } 342 343 func (s *keyManagerSuite) TestImportKeys(c *gc.C) { 344 s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport) 345 346 key1 := sshtesting.ValidKeyOne.Key + " user@host" 347 key2 := sshtesting.ValidKeyTwo.Key 348 key3 := sshtesting.ValidKeyThree.Key 349 key4 := sshtesting.ValidKeyFour.Key 350 keymv := strings.Split(sshtesting.ValidKeyMulti, "\n") 351 keymp := strings.Split(sshtesting.PartValidKeyMulti, "\n") 352 keymi := strings.Split(sshtesting.MultiInvalid, "\n") 353 initialKeys := []string{key1, key2, "bad key"} 354 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 355 356 args := params.ModifyUserSSHKeys{ 357 User: s.AdminUserTag(c).Name(), 358 Keys: []string{ 359 "lp:existing", 360 "lp:validuser", 361 "invalid-key", 362 "lp:multi", 363 "lp:multiempty", 364 "lp:multipartial", 365 "lp:multiinvalid", 366 "lp:multionedup", 367 }, 368 } 369 results, err := s.keymanager.ImportKeys(args) 370 c.Assert(err, jc.ErrorIsNil) 371 c.Assert(results.Results, gc.HasLen, 8) 372 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 373 Results: []params.ErrorResult{ 374 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 375 {Error: nil}, 376 {Error: apiservertesting.ServerError("invalid ssh key id: invalid-key")}, 377 {Error: nil}, 378 {Error: apiservertesting.ServerError("invalid ssh key id: lp:multiempty")}, 379 {Error: apiservertesting.ServerError(fmt.Sprintf( 380 `invalid ssh key for lp:multipartial: `+ 381 `generating key fingerprint: `+ 382 `invalid authorized_key "%s"`, keymp[1]))}, 383 {Error: apiservertesting.ServerError(fmt.Sprintf( 384 `invalid ssh key for lp:multiinvalid: `+ 385 `generating key fingerprint: `+ 386 `invalid authorized_key "%s"`+"\n"+ 387 `invalid ssh key for lp:multiinvalid: `+ 388 `generating key fingerprint: `+ 389 `invalid authorized_key "%s"`, keymi[0], keymi[1]))}, 390 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 391 }, 392 }) 393 s.assertEnvironKeys(c, append(initialKeys, key3, keymv[0], keymv[1], keymp[0], key4)) 394 } 395 396 func (s *keyManagerSuite) TestBlockImportKeys(c *gc.C) { 397 s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport) 398 399 key1 := sshtesting.ValidKeyOne.Key + " user@host" 400 key2 := sshtesting.ValidKeyTwo.Key 401 initialKeys := []string{key1, key2, "bad key"} 402 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 403 404 args := params.ModifyUserSSHKeys{ 405 User: s.AdminUserTag(c).Name(), 406 Keys: []string{"lp:existing", "lp:validuser", "invalid-key"}, 407 } 408 409 s.BlockAllChanges(c, "TestBlockImportKeys") 410 _, err := s.keymanager.ImportKeys(args) 411 // Check that the call is blocked 412 s.AssertBlocked(c, err, "TestBlockImportKeys") 413 s.assertEnvironKeys(c, initialKeys) 414 }