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  }