// ReadAuthorizedKeys implements the standard juju behaviour for finding // authorized_keys. It returns a set of keys in in authorized_keys format // (see sshd(8) for a description). If path is non-empty, it names the // file to use; otherwise the user's .ssh directory will be searched. // Home directory expansion will be performed on the path if it starts with // a ~; if the expanded path is relative, it will be interpreted relative // to $HOME/.ssh. // // The result of utils/ssh.PublicKeyFiles will always be prepended to the // result. In practice, this means ReadAuthorizedKeys never returns an // error when the call originates in the CLI. // // If no SSH keys are found, ReadAuthorizedKeys returns // ErrNoAuthorizedKeys. func ReadAuthorizedKeys(ctx *cmd.Context, path string) (string, error) { files := ssh.PublicKeyFiles() if path == "" { files = append(files, "id_dsa.pub", "id_rsa.pub", "identity.pub") } else { files = append(files, path) } var firstError error var keyData []byte for _, f := range files { f, err := utils.NormalizePath(f) if err != nil { if firstError == nil { firstError = err } continue } if !filepath.IsAbs(f) { f = filepath.Join(utils.Home(), ".ssh", f) } data, err := ioutil.ReadFile(f) if err != nil { if firstError == nil && !os.IsNotExist(err) { firstError = err } continue } keyData = append(keyData, bytes.Trim(data, "\n")...) keyData = append(keyData, '\n') ctx.Verbosef("Adding contents of %q to authorized-keys", f) } if len(keyData) == 0 { if firstError == nil { firstError = ErrNoAuthorizedKeys } return "", firstError } return string(keyData), nil }
func (s *AuthKeysSuite) TestReadAuthorizedKeysClientKeys(c *gc.C) { keydir := filepath.Join(s.dotssh, "juju") err := ssh.LoadClientKeys(keydir) // auto-generates a key pair c.Assert(err, jc.ErrorIsNil) pubkeyFiles := ssh.PublicKeyFiles() c.Assert(pubkeyFiles, gc.HasLen, 1) data, err := ioutil.ReadFile(pubkeyFiles[0]) c.Assert(err, jc.ErrorIsNil) prefix := strings.Trim(string(data), "\n") + "\n" writeFile(c, filepath.Join(s.dotssh, "id_rsa.pub"), "id_rsa") writeFile(c, filepath.Join(s.dotssh, "test.pub"), "test") keys, err := config.ReadAuthorizedKeys("") c.Assert(err, jc.ErrorIsNil) c.Assert(keys, gc.Equals, prefix+"id_rsa\n") keys, err = config.ReadAuthorizedKeys("test.pub") c.Assert(err, jc.ErrorIsNil) c.Assert(keys, gc.Equals, prefix+"test\n") keys, err = config.ReadAuthorizedKeys("notthere.pub") c.Assert(err, jc.ErrorIsNil) c.Assert(keys, gc.Equals, prefix) }
func checkPublicKeyFiles(c *gc.C, expected ...string) { keys := ssh.PublicKeyFiles() checkFiles(c, keys, expected) }