github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "github.com/juju/names" 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 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) assertEnvironKeys(c *gc.C, expected []string) { 116 envConfig, err := s.State.ModelConfig() 117 c.Assert(err, jc.ErrorIsNil) 118 keys := envConfig.AuthorizedKeys() 119 c.Assert(keys, gc.Equals, strings.Join(expected, "\n")) 120 } 121 122 func (s *keyManagerSuite) TestAddKeys(c *gc.C) { 123 key1 := sshtesting.ValidKeyOne.Key + " user@host" 124 key2 := sshtesting.ValidKeyTwo.Key 125 initialKeys := []string{key1, key2, "bad key"} 126 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 127 128 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 129 args := params.ModifyUserSSHKeys{ 130 User: s.AdminUserTag(c).Name(), 131 Keys: []string{key2, newKey, "invalid-key"}, 132 } 133 results, err := s.keymanager.AddKeys(args) 134 c.Assert(err, jc.ErrorIsNil) 135 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 136 Results: []params.ErrorResult{ 137 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 138 {Error: nil}, 139 {Error: apiservertesting.ServerError("invalid ssh key: invalid-key")}, 140 }, 141 }) 142 s.assertEnvironKeys(c, append(initialKeys, newKey)) 143 } 144 145 func (s *keyManagerSuite) TestBlockAddKeys(c *gc.C) { 146 key1 := sshtesting.ValidKeyOne.Key + " user@host" 147 key2 := sshtesting.ValidKeyTwo.Key 148 initialKeys := []string{key1, key2, "bad key"} 149 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 150 151 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 152 args := params.ModifyUserSSHKeys{ 153 User: s.AdminUserTag(c).Name(), 154 Keys: []string{key2, newKey, "invalid-key"}, 155 } 156 157 s.BlockAllChanges(c, "TestBlockAddKeys") 158 _, err := s.keymanager.AddKeys(args) 159 // Check that the call is blocked 160 s.AssertBlocked(c, err, "TestBlockAddKeys") 161 s.assertEnvironKeys(c, initialKeys) 162 } 163 164 func (s *keyManagerSuite) TestAddJujuSystemKey(c *gc.C) { 165 anAuthoriser := s.authoriser 166 anAuthoriser.EnvironManager = true 167 anAuthoriser.Tag = names.NewMachineTag("0") 168 var err error 169 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 170 c.Assert(err, jc.ErrorIsNil) 171 key1 := sshtesting.ValidKeyOne.Key + " user@host" 172 key2 := sshtesting.ValidKeyTwo.Key 173 initialKeys := []string{key1, key2} 174 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 175 176 newKey := sshtesting.ValidKeyThree.Key + " juju-system-key" 177 args := params.ModifyUserSSHKeys{ 178 User: "juju-system-key", 179 Keys: []string{newKey}, 180 } 181 results, err := s.keymanager.AddKeys(args) 182 c.Assert(err, jc.ErrorIsNil) 183 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 184 Results: []params.ErrorResult{ 185 {Error: nil}, 186 }, 187 }) 188 s.assertEnvironKeys(c, append(initialKeys, newKey)) 189 } 190 191 func (s *keyManagerSuite) TestAddJujuSystemKeyNotMachine(c *gc.C) { 192 anAuthoriser := s.authoriser 193 anAuthoriser.EnvironManager = true 194 anAuthoriser.Tag = names.NewUnitTag("wordpress/0") 195 var err error 196 s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser) 197 c.Assert(err, jc.ErrorIsNil) 198 key1 := sshtesting.ValidKeyOne.Key 199 s.setAuthorisedKeys(c, key1) 200 201 newKey := sshtesting.ValidKeyThree.Key + " juju-system-key" 202 args := params.ModifyUserSSHKeys{ 203 User: "juju-system-key", 204 Keys: []string{newKey}, 205 } 206 _, err = s.keymanager.AddKeys(args) 207 c.Assert(err, gc.ErrorMatches, "permission denied") 208 s.assertEnvironKeys(c, []string{key1}) 209 } 210 211 func (s *keyManagerSuite) TestDeleteKeys(c *gc.C) { 212 key1 := sshtesting.ValidKeyOne.Key + " user@host" 213 key2 := sshtesting.ValidKeyTwo.Key 214 initialKeys := []string{key1, key2, "bad key"} 215 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 216 217 args := params.ModifyUserSSHKeys{ 218 User: s.AdminUserTag(c).Name(), 219 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"}, 220 } 221 results, err := s.keymanager.DeleteKeys(args) 222 c.Assert(err, jc.ErrorIsNil) 223 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 224 Results: []params.ErrorResult{ 225 {Error: nil}, 226 {Error: apiservertesting.ServerError("invalid ssh key: " + sshtesting.ValidKeyThree.Fingerprint)}, 227 {Error: apiservertesting.ServerError("invalid ssh key: invalid-key")}, 228 }, 229 }) 230 s.assertEnvironKeys(c, []string{"bad key", key1}) 231 } 232 233 func (s *keyManagerSuite) TestBlockDeleteKeys(c *gc.C) { 234 key1 := sshtesting.ValidKeyOne.Key + " user@host" 235 key2 := sshtesting.ValidKeyTwo.Key 236 initialKeys := []string{key1, key2, "bad key"} 237 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 238 239 args := params.ModifyUserSSHKeys{ 240 User: s.AdminUserTag(c).Name(), 241 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"}, 242 } 243 244 s.BlockAllChanges(c, "TestBlockDeleteKeys") 245 _, err := s.keymanager.DeleteKeys(args) 246 // Check that the call is blocked 247 s.AssertBlocked(c, err, "TestBlockDeleteKeys") 248 s.assertEnvironKeys(c, initialKeys) 249 } 250 251 func (s *keyManagerSuite) TestCannotDeleteAllKeys(c *gc.C) { 252 key1 := sshtesting.ValidKeyOne.Key + " user@host" 253 key2 := sshtesting.ValidKeyTwo.Key 254 initialKeys := []string{key1, key2} 255 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 256 257 args := params.ModifyUserSSHKeys{ 258 User: s.AdminUserTag(c).Name(), 259 Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, "user@host"}, 260 } 261 _, err := s.keymanager.DeleteKeys(args) 262 c.Assert(err, gc.ErrorMatches, "cannot delete all keys") 263 s.assertEnvironKeys(c, initialKeys) 264 } 265 266 func (s *keyManagerSuite) assertInvalidUserOperation(c *gc.C, runTestLogic func(args params.ModifyUserSSHKeys) error) { 267 initialKey := sshtesting.ValidKeyOne.Key + " user@host" 268 s.setAuthorisedKeys(c, initialKey) 269 270 // Set up the params. 271 newKey := sshtesting.ValidKeyThree.Key + " newuser@host" 272 args := params.ModifyUserSSHKeys{ 273 User: "invalid", 274 Keys: []string{newKey}, 275 } 276 // Run the required test code and check the error. 277 err := runTestLogic(args) 278 c.Assert(err, gc.DeepEquals, apiservertesting.ErrUnauthorized) 279 280 // No environ changes. 281 s.assertEnvironKeys(c, []string{initialKey}) 282 } 283 284 func (s *keyManagerSuite) TestAddKeysInvalidUser(c *gc.C) { 285 c.Skip("no user validation done yet") 286 s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error { 287 _, err := s.keymanager.AddKeys(args) 288 return err 289 }) 290 } 291 292 func (s *keyManagerSuite) TestDeleteKeysInvalidUser(c *gc.C) { 293 c.Skip("no user validation done yet") 294 s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error { 295 _, err := s.keymanager.DeleteKeys(args) 296 return err 297 }) 298 } 299 300 func (s *keyManagerSuite) TestImportKeys(c *gc.C) { 301 s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport) 302 303 key1 := sshtesting.ValidKeyOne.Key + " user@host" 304 key2 := sshtesting.ValidKeyTwo.Key 305 key3 := sshtesting.ValidKeyThree.Key 306 key4 := sshtesting.ValidKeyFour.Key 307 keymv := strings.Split(sshtesting.ValidKeyMulti, "\n") 308 keymp := strings.Split(sshtesting.PartValidKeyMulti, "\n") 309 keymi := strings.Split(sshtesting.MultiInvalid, "\n") 310 initialKeys := []string{key1, key2, "bad key"} 311 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 312 313 args := params.ModifyUserSSHKeys{ 314 User: s.AdminUserTag(c).Name(), 315 Keys: []string{ 316 "lp:existing", 317 "lp:validuser", 318 "invalid-key", 319 "lp:multi", 320 "lp:multiempty", 321 "lp:multipartial", 322 "lp:multiinvalid", 323 "lp:multionedup", 324 }, 325 } 326 results, err := s.keymanager.ImportKeys(args) 327 c.Assert(err, jc.ErrorIsNil) 328 c.Assert(results.Results, gc.HasLen, 8) 329 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 330 Results: []params.ErrorResult{ 331 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 332 {Error: nil}, 333 {Error: apiservertesting.ServerError("invalid ssh key id: invalid-key")}, 334 {Error: nil}, 335 {Error: apiservertesting.ServerError("invalid ssh key id: lp:multiempty")}, 336 {Error: apiservertesting.ServerError(fmt.Sprintf( 337 `invalid ssh key for lp:multipartial: `+ 338 `generating key fingerprint: `+ 339 `invalid authorized_key "%s"`, keymp[1]))}, 340 {Error: apiservertesting.ServerError(fmt.Sprintf( 341 `invalid ssh key for lp:multiinvalid: `+ 342 `generating key fingerprint: `+ 343 `invalid authorized_key "%s"`+"\n"+ 344 `invalid ssh key for lp:multiinvalid: `+ 345 `generating key fingerprint: `+ 346 `invalid authorized_key "%s"`, keymi[0], keymi[1]))}, 347 {Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))}, 348 }, 349 }) 350 s.assertEnvironKeys(c, append(initialKeys, key3, keymv[0], keymv[1], keymp[0], key4)) 351 } 352 353 func (s *keyManagerSuite) TestBlockImportKeys(c *gc.C) { 354 s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport) 355 356 key1 := sshtesting.ValidKeyOne.Key + " user@host" 357 key2 := sshtesting.ValidKeyTwo.Key 358 initialKeys := []string{key1, key2, "bad key"} 359 s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n")) 360 361 args := params.ModifyUserSSHKeys{ 362 User: s.AdminUserTag(c).Name(), 363 Keys: []string{"lp:existing", "lp:validuser", "invalid-key"}, 364 } 365 366 s.BlockAllChanges(c, "TestBlockImportKeys") 367 _, err := s.keymanager.ImportKeys(args) 368 // Check that the call is blocked 369 s.AssertBlocked(c, err, "TestBlockImportKeys") 370 s.assertEnvironKeys(c, initialKeys) 371 }