github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/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/errors"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/common"
    16  	"github.com/juju/juju/apiserver/keymanager"
    17  	keymanagertesting "github.com/juju/juju/apiserver/keymanager/testing"
    18  	"github.com/juju/juju/apiserver/params"
    19  	apiservertesting "github.com/juju/juju/apiserver/testing"
    20  	jujutesting "github.com/juju/juju/juju/testing"
    21  	"github.com/juju/juju/utils/ssh"
    22  	sshtesting "github.com/juju/juju/utils/ssh/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  
    33  var _ = gc.Suite(&keyManagerSuite{})
    34  
    35  func (s *keyManagerSuite) SetUpTest(c *gc.C) {
    36  	s.JujuConnSuite.SetUpTest(c)
    37  	s.resources = common.NewResources()
    38  	s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() })
    39  
    40  	s.authoriser = apiservertesting.FakeAuthorizer{
    41  		Tag: s.AdminUserTag(c),
    42  	}
    43  	var err error
    44  	s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, s.authoriser)
    45  	c.Assert(err, jc.ErrorIsNil)
    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, jc.ErrorIsNil)
    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, jc.ErrorIsNil)
    59  	c.Assert(endPoint, gc.NotNil)
    60  }
    61  
    62  func (s *keyManagerSuite) TestNewKeyManagerAPIRefusesNonClient(c *gc.C) {
    63  	anAuthoriser := s.authoriser
    64  	anAuthoriser.Tag = names.NewUnitTag("mysql/0")
    65  	anAuthoriser.EnvironManager = false
    66  	endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser)
    67  	c.Assert(endPoint, gc.IsNil)
    68  	c.Assert(err, gc.ErrorMatches, "permission denied")
    69  }
    70  
    71  func (s *keyManagerSuite) TestNewKeyManagerAPIRefusesNonEnvironManager(c *gc.C) {
    72  	anAuthoriser := s.authoriser
    73  	anAuthoriser.Tag = names.NewMachineTag("99")
    74  	anAuthoriser.EnvironManager = false
    75  	endPoint, err := keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser)
    76  	c.Assert(endPoint, gc.IsNil)
    77  	c.Assert(err, gc.ErrorMatches, "permission denied")
    78  }
    79  
    80  func (s *keyManagerSuite) setAuthorisedKeys(c *gc.C, keys string) {
    81  	err := s.State.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keys}, nil, nil)
    82  	c.Assert(err, jc.ErrorIsNil)
    83  	envConfig, err := s.State.EnvironConfig()
    84  	c.Assert(err, jc.ErrorIsNil)
    85  	c.Assert(envConfig.AuthorizedKeys(), gc.Equals, keys)
    86  }
    87  
    88  func (s *keyManagerSuite) TestListKeys(c *gc.C) {
    89  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
    90  	key2 := sshtesting.ValidKeyTwo.Key
    91  	s.setAuthorisedKeys(c, strings.Join([]string{key1, key2, "bad key"}, "\n"))
    92  
    93  	args := params.ListSSHKeys{
    94  		Entities: params.Entities{[]params.Entity{
    95  			{Tag: s.AdminUserTag(c).Name()},
    96  			{Tag: "invalid"},
    97  		}},
    98  		Mode: ssh.FullKeys,
    99  	}
   100  	results, err := s.keymanager.ListKeys(args)
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	c.Assert(results, gc.DeepEquals, params.StringsResults{
   103  		Results: []params.StringsResult{
   104  			{Result: []string{key1, key2, "Invalid key: bad key"}},
   105  			{Result: []string{key1, key2, "Invalid key: bad key"}},
   106  		},
   107  	})
   108  }
   109  
   110  func (s *keyManagerSuite) assertEnvironKeys(c *gc.C, expected []string) {
   111  	envConfig, err := s.State.EnvironConfig()
   112  	c.Assert(err, jc.ErrorIsNil)
   113  	keys := envConfig.AuthorizedKeys()
   114  	c.Assert(keys, gc.Equals, strings.Join(expected, "\n"))
   115  }
   116  
   117  func (s *keyManagerSuite) TestAddKeys(c *gc.C) {
   118  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   119  	key2 := sshtesting.ValidKeyTwo.Key
   120  	initialKeys := []string{key1, key2, "bad key"}
   121  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   122  
   123  	newKey := sshtesting.ValidKeyThree.Key + " newuser@host"
   124  	args := params.ModifyUserSSHKeys{
   125  		User: s.AdminUserTag(c).Name(),
   126  		Keys: []string{key2, newKey, "invalid-key"},
   127  	}
   128  	results, err := s.keymanager.AddKeys(args)
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   131  		Results: []params.ErrorResult{
   132  			{Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))},
   133  			{Error: nil},
   134  			{Error: apiservertesting.ServerError("invalid ssh key: invalid-key")},
   135  		},
   136  	})
   137  	s.assertEnvironKeys(c, append(initialKeys, newKey))
   138  }
   139  
   140  func (s *keyManagerSuite) TestBlockAddKeys(c *gc.C) {
   141  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   142  	key2 := sshtesting.ValidKeyTwo.Key
   143  	initialKeys := []string{key1, key2, "bad key"}
   144  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   145  
   146  	newKey := sshtesting.ValidKeyThree.Key + " newuser@host"
   147  	args := params.ModifyUserSSHKeys{
   148  		User: s.AdminUserTag(c).Name(),
   149  		Keys: []string{key2, newKey, "invalid-key"},
   150  	}
   151  
   152  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
   153  	_, err := s.keymanager.AddKeys(args)
   154  	// Check that the call is blocked
   155  	c.Assert(errors.Cause(err), gc.ErrorMatches, common.ErrOperationBlocked.Error())
   156  	s.assertEnvironKeys(c, initialKeys)
   157  }
   158  
   159  func (s *keyManagerSuite) TestAddJujuSystemKey(c *gc.C) {
   160  	anAuthoriser := s.authoriser
   161  	anAuthoriser.EnvironManager = true
   162  	anAuthoriser.Tag = names.NewMachineTag("0")
   163  	var err error
   164  	s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser)
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   167  	key2 := sshtesting.ValidKeyTwo.Key
   168  	initialKeys := []string{key1, key2}
   169  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   170  
   171  	newKey := sshtesting.ValidKeyThree.Key + " juju-system-key"
   172  	args := params.ModifyUserSSHKeys{
   173  		User: "juju-system-key",
   174  		Keys: []string{newKey},
   175  	}
   176  	results, err := s.keymanager.AddKeys(args)
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   179  		Results: []params.ErrorResult{
   180  			{Error: nil},
   181  		},
   182  	})
   183  	s.assertEnvironKeys(c, append(initialKeys, newKey))
   184  }
   185  
   186  func (s *keyManagerSuite) TestAddJujuSystemKeyNotMachine(c *gc.C) {
   187  	anAuthoriser := s.authoriser
   188  	anAuthoriser.EnvironManager = true
   189  	anAuthoriser.Tag = names.NewUnitTag("wordpress/0")
   190  	var err error
   191  	s.keymanager, err = keymanager.NewKeyManagerAPI(s.State, s.resources, anAuthoriser)
   192  	c.Assert(err, jc.ErrorIsNil)
   193  	key1 := sshtesting.ValidKeyOne.Key
   194  	s.setAuthorisedKeys(c, key1)
   195  
   196  	newKey := sshtesting.ValidKeyThree.Key + " juju-system-key"
   197  	args := params.ModifyUserSSHKeys{
   198  		User: "juju-system-key",
   199  		Keys: []string{newKey},
   200  	}
   201  	_, err = s.keymanager.AddKeys(args)
   202  	c.Assert(err, gc.ErrorMatches, "permission denied")
   203  	s.assertEnvironKeys(c, []string{key1})
   204  }
   205  
   206  func (s *keyManagerSuite) TestDeleteKeys(c *gc.C) {
   207  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   208  	key2 := sshtesting.ValidKeyTwo.Key
   209  	initialKeys := []string{key1, key2, "bad key"}
   210  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   211  
   212  	args := params.ModifyUserSSHKeys{
   213  		User: s.AdminUserTag(c).Name(),
   214  		Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"},
   215  	}
   216  	results, err := s.keymanager.DeleteKeys(args)
   217  	c.Assert(err, jc.ErrorIsNil)
   218  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   219  		Results: []params.ErrorResult{
   220  			{Error: nil},
   221  			{Error: apiservertesting.ServerError("invalid ssh key: " + sshtesting.ValidKeyThree.Fingerprint)},
   222  			{Error: apiservertesting.ServerError("invalid ssh key: invalid-key")},
   223  		},
   224  	})
   225  	s.assertEnvironKeys(c, []string{"bad key", key1})
   226  }
   227  
   228  func (s *keyManagerSuite) TestBlockDeleteKeys(c *gc.C) {
   229  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   230  	key2 := sshtesting.ValidKeyTwo.Key
   231  	initialKeys := []string{key1, key2, "bad key"}
   232  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   233  
   234  	args := params.ModifyUserSSHKeys{
   235  		User: s.AdminUserTag(c).Name(),
   236  		Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, sshtesting.ValidKeyThree.Fingerprint, "invalid-key"},
   237  	}
   238  
   239  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
   240  	_, err := s.keymanager.DeleteKeys(args)
   241  	// Check that the call is blocked
   242  	c.Assert(errors.Cause(err), gc.ErrorMatches, common.ErrOperationBlocked.Error())
   243  	s.assertEnvironKeys(c, initialKeys)
   244  }
   245  
   246  func (s *keyManagerSuite) TestCannotDeleteAllKeys(c *gc.C) {
   247  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   248  	key2 := sshtesting.ValidKeyTwo.Key
   249  	initialKeys := []string{key1, key2}
   250  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   251  
   252  	args := params.ModifyUserSSHKeys{
   253  		User: s.AdminUserTag(c).Name(),
   254  		Keys: []string{sshtesting.ValidKeyTwo.Fingerprint, "user@host"},
   255  	}
   256  	_, err := s.keymanager.DeleteKeys(args)
   257  	c.Assert(err, gc.ErrorMatches, "cannot delete all keys")
   258  	s.assertEnvironKeys(c, initialKeys)
   259  }
   260  
   261  func (s *keyManagerSuite) assertInvalidUserOperation(c *gc.C, runTestLogic func(args params.ModifyUserSSHKeys) error) {
   262  	initialKey := sshtesting.ValidKeyOne.Key + " user@host"
   263  	s.setAuthorisedKeys(c, initialKey)
   264  
   265  	// Set up the params.
   266  	newKey := sshtesting.ValidKeyThree.Key + " newuser@host"
   267  	args := params.ModifyUserSSHKeys{
   268  		User: "invalid",
   269  		Keys: []string{newKey},
   270  	}
   271  	// Run the required test code and check the error.
   272  	err := runTestLogic(args)
   273  	c.Assert(err, gc.DeepEquals, apiservertesting.ErrUnauthorized)
   274  
   275  	// No environ changes.
   276  	s.assertEnvironKeys(c, []string{initialKey})
   277  }
   278  
   279  func (s *keyManagerSuite) TestAddKeysInvalidUser(c *gc.C) {
   280  	c.Skip("no user validation done yet")
   281  	s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error {
   282  		_, err := s.keymanager.AddKeys(args)
   283  		return err
   284  	})
   285  }
   286  
   287  func (s *keyManagerSuite) TestDeleteKeysInvalidUser(c *gc.C) {
   288  	c.Skip("no user validation done yet")
   289  	s.assertInvalidUserOperation(c, func(args params.ModifyUserSSHKeys) error {
   290  		_, err := s.keymanager.DeleteKeys(args)
   291  		return err
   292  	})
   293  }
   294  
   295  func (s *keyManagerSuite) TestImportKeys(c *gc.C) {
   296  	s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport)
   297  
   298  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   299  	key2 := sshtesting.ValidKeyTwo.Key
   300  	key3 := sshtesting.ValidKeyThree.Key
   301  	initialKeys := []string{key1, key2, "bad key"}
   302  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   303  
   304  	args := params.ModifyUserSSHKeys{
   305  		User: s.AdminUserTag(c).Name(),
   306  		Keys: []string{"lp:existing", "lp:validuser", "invalid-key"},
   307  	}
   308  	results, err := s.keymanager.ImportKeys(args)
   309  	c.Assert(err, jc.ErrorIsNil)
   310  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   311  		Results: []params.ErrorResult{
   312  			{Error: apiservertesting.ServerError(fmt.Sprintf("duplicate ssh key: %s", key2))},
   313  			{Error: nil},
   314  			{Error: apiservertesting.ServerError("invalid ssh key id: invalid-key")},
   315  		},
   316  	})
   317  	s.assertEnvironKeys(c, append(initialKeys, key3))
   318  }
   319  
   320  func (s *keyManagerSuite) TestBlockImportKeys(c *gc.C) {
   321  	s.PatchValue(&keymanager.RunSSHImportId, keymanagertesting.FakeImport)
   322  
   323  	key1 := sshtesting.ValidKeyOne.Key + " user@host"
   324  	key2 := sshtesting.ValidKeyTwo.Key
   325  	initialKeys := []string{key1, key2, "bad key"}
   326  	s.setAuthorisedKeys(c, strings.Join(initialKeys, "\n"))
   327  
   328  	args := params.ModifyUserSSHKeys{
   329  		User: s.AdminUserTag(c).Name(),
   330  		Keys: []string{"lp:existing", "lp:validuser", "invalid-key"},
   331  	}
   332  
   333  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
   334  	_, err := s.keymanager.ImportKeys(args)
   335  	// Check that the call is blocked
   336  	c.Assert(errors.Cause(err), gc.ErrorMatches, common.ErrOperationBlocked.Error())
   337  	s.assertEnvironKeys(c, initialKeys)
   338  }