launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/utils/ssh/ssh_gocrypto_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package ssh_test 5 6 import ( 7 "encoding/binary" 8 "net" 9 "sync" 10 11 cryptossh "code.google.com/p/go.crypto/ssh" 12 gc "launchpad.net/gocheck" 13 14 jc "launchpad.net/juju-core/testing/checkers" 15 "launchpad.net/juju-core/testing/testbase" 16 "launchpad.net/juju-core/utils/ssh" 17 ) 18 19 var ( 20 testCommand = []string{"echo", "$abc"} 21 testCommandFlat = `echo "\$abc"` 22 ) 23 24 type sshServer struct { 25 cfg *cryptossh.ServerConfig 26 *cryptossh.Listener 27 } 28 29 func newServer(c *gc.C) *sshServer { 30 private, _, err := ssh.GenerateKey("test-server") 31 c.Assert(err, gc.IsNil) 32 key, err := cryptossh.ParsePrivateKey([]byte(private)) 33 c.Assert(err, gc.IsNil) 34 server := &sshServer{ 35 cfg: &cryptossh.ServerConfig{}, 36 } 37 server.cfg.AddHostKey(key) 38 server.Listener, err = cryptossh.Listen("tcp", "127.0.0.1:0", server.cfg) 39 c.Assert(err, gc.IsNil) 40 return server 41 } 42 43 func (s *sshServer) run(c *gc.C) { 44 conn, err := s.Accept() 45 c.Assert(err, gc.IsNil) 46 defer func() { 47 err = conn.Close() 48 c.Assert(err, gc.IsNil) 49 }() 50 err = conn.Handshake() 51 c.Assert(err, gc.IsNil) 52 var wg sync.WaitGroup 53 defer wg.Wait() 54 for { 55 channel, err := conn.Accept() 56 c.Assert(err, gc.IsNil) 57 c.Assert(channel.ChannelType(), gc.Equals, "session") 58 channel.Accept() 59 wg.Add(1) 60 go func() { 61 defer wg.Done() 62 defer channel.Close() 63 _, err := channel.Read(nil) 64 c.Assert(err, gc.FitsTypeOf, cryptossh.ChannelRequest{}) 65 req := err.(cryptossh.ChannelRequest) 66 c.Assert(req.Request, gc.Equals, "exec") 67 c.Assert(req.WantReply, jc.IsTrue) 68 n := binary.BigEndian.Uint32(req.Payload[:4]) 69 command := string(req.Payload[4 : n+4]) 70 c.Assert(command, gc.Equals, testCommandFlat) 71 // TODO(axw) when gosshnew is ready, send reply to client. 72 }() 73 } 74 } 75 76 type SSHGoCryptoCommandSuite struct { 77 testbase.LoggingSuite 78 client ssh.Client 79 } 80 81 var _ = gc.Suite(&SSHGoCryptoCommandSuite{}) 82 83 func (s *SSHGoCryptoCommandSuite) SetUpTest(c *gc.C) { 84 s.LoggingSuite.SetUpTest(c) 85 client, err := ssh.NewGoCryptoClient() 86 c.Assert(err, gc.IsNil) 87 s.client = client 88 } 89 90 func (s *SSHGoCryptoCommandSuite) TestNewGoCryptoClient(c *gc.C) { 91 _, err := ssh.NewGoCryptoClient() 92 c.Assert(err, gc.IsNil) 93 private, _, err := ssh.GenerateKey("test-client") 94 c.Assert(err, gc.IsNil) 95 key, err := cryptossh.ParsePrivateKey([]byte(private)) 96 c.Assert(err, gc.IsNil) 97 _, err = ssh.NewGoCryptoClient(key) 98 c.Assert(err, gc.IsNil) 99 } 100 101 func (s *SSHGoCryptoCommandSuite) TestClientNoKeys(c *gc.C) { 102 client, err := ssh.NewGoCryptoClient() 103 c.Assert(err, gc.IsNil) 104 cmd := client.Command("0.1.2.3", []string{"echo", "123"}, nil) 105 _, err = cmd.Output() 106 c.Assert(err, gc.ErrorMatches, "no private keys available") 107 defer ssh.ClearClientKeys() 108 err = ssh.LoadClientKeys(c.MkDir()) 109 c.Assert(err, gc.IsNil) 110 cmd = client.Command("0.1.2.3", []string{"echo", "123"}, nil) 111 _, err = cmd.Output() 112 // error message differs based on whether using cgo or not 113 c.Assert(err, gc.ErrorMatches, `(dial tcp )?0\.1\.2\.3:22: invalid argument`) 114 } 115 116 func (s *SSHGoCryptoCommandSuite) TestCommand(c *gc.C) { 117 private, _, err := ssh.GenerateKey("test-server") 118 c.Assert(err, gc.IsNil) 119 key, err := cryptossh.ParsePrivateKey([]byte(private)) 120 client, err := ssh.NewGoCryptoClient(key) 121 c.Assert(err, gc.IsNil) 122 server := newServer(c) 123 var opts ssh.Options 124 opts.SetPort(server.Addr().(*net.TCPAddr).Port) 125 cmd := client.Command("127.0.0.1", testCommand, &opts) 126 checkedKey := false 127 server.cfg.PublicKeyCallback = func(conn *cryptossh.ServerConn, user, algo string, pubkey []byte) bool { 128 c.Check(pubkey, gc.DeepEquals, cryptossh.MarshalPublicKey(key.PublicKey())) 129 checkedKey = true 130 return true 131 } 132 go server.run(c) 133 out, err := cmd.Output() 134 c.Assert(err, gc.ErrorMatches, "ssh: could not execute command.*") 135 // TODO(axw) when gosshnew is ready, expect reply from server. 136 c.Assert(out, gc.IsNil) 137 c.Assert(checkedKey, jc.IsTrue) 138 } 139 140 func (s *SSHGoCryptoCommandSuite) TestCopy(c *gc.C) { 141 client, err := ssh.NewGoCryptoClient() 142 c.Assert(err, gc.IsNil) 143 err = client.Copy("0.1.2.3:b", c.MkDir(), nil) 144 c.Assert(err, gc.ErrorMatches, "Copy is not implemented") 145 }