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  }