Merge lp:~gz/juju-core/gosshnew_1312940 into lp:~go-bot/juju-core/trunk

Proposed by Martin Packman
Status: Work in progress
Proposed branch: lp:~gz/juju-core/gosshnew_1312940
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 291 lines (+70/-75)
4 files modified
dependencies.tsv (+1/-1)
utils/ssh/authorisedkeys.go (+5/-4)
utils/ssh/ssh_gocrypto.go (+23/-37)
utils/ssh/ssh_gocrypto_test.go (+41/-33)
To merge this branch: bzr merge lp:~gz/juju-core/gosshnew_1312940
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+217308@code.launchpad.net

Commit message

utils/ssh: Update to use latest go.crypto

Upstream go.crypto has a cleaned up ssh package in r192
and beyond. This has a few interface changes we need to
adapt to, but should make testing easier in future.

Also bumps dependencies.tsv to go.crypto tip.

https://codereview.appspot.com/95770045/

R=axwalk

Description of the change

utils/ssh: Update to use latest go.crypto

Upstream go.crypto has a cleaned up ssh package in r192
and beyond. This has a few interface changes we need to
adapt to, but should make testing easier in future.

Also bumps dependencies.tsv to go.crypto tip.

https://codereview.appspot.com/95770045/

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

Reviewers: mp+217308_code.launchpad.net,

Message:
Please take a look.

Description:
utils/ssh: Update to use latest go.crypto

Upstream go.crypto has a cleaned up ssh package in r192
and beyond. This has a few interface changes we need to
adapt to, but should make testing easier in future.

Also bumps dependencies.tsv to go.crypto tip.

https://code.launchpad.net/~gz/juju-core/gosshnew_1312940/+merge/217308

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/95770045/

Affected files (+62, -65 lines):
   A [revision details]
   M dependencies.tsv
   M utils/ssh/authorisedkeys.go
   M utils/ssh/ssh_gocrypto.go
   M utils/ssh/ssh_gocrypto_test.go

Revision history for this message
Andrew Wilkins (axwalk) wrote :

LGTM, with a few naming changes

Thanks for doing that, I keep on meaning to do it and then promptly
forget.

https://codereview.appspot.com/95770045/diff/1/utils/ssh/authorisedkeys.go
File utils/ssh/authorisedkeys.go (left):

https://codereview.appspot.com/95770045/diff/1/utils/ssh/authorisedkeys.go#oldcode48
utils/ssh/authorisedkeys.go:48: return nil, fmt.Errorf("invalid
authorized_key %q", line)
Include the ParseAuthorizedKey error in the message?

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto.go
File utils/ssh/ssh_gocrypto.go (right):

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto.go#newcode84
utils/ssh/ssh_gocrypto.go:84: conn *ssh.Client
s/conn/client/
(and wherever else we refer to Client as conn)
?

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto.go#newcode152
utils/ssh/ssh_gocrypto.go:152: conn.Conn.Close()
ssh.Client embeds Conn, so conn.Close (or client.Close) would be better
IMO

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto_test.go
File utils/ssh/ssh_gocrypto_test.go (right):

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto_test.go#newcode31
utils/ssh/ssh_gocrypto_test.go:31: Listener net.Listener
s/Listener/listener/
?
(I would prefer we don't export fields unless we need to for reflection
or whatever.)

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto_test.go#newcode154
utils/ssh/ssh_gocrypto_test.go:154: c.Assert(string(out), gc.Equals,
"abc value\n")
Yay! Thanks.

https://codereview.appspot.com/95770045/

Revision history for this message
Martin Packman (gz) wrote :

Please take a look.

https://codereview.appspot.com/95770045/diff/1/utils/ssh/authorisedkeys.go
File utils/ssh/authorisedkeys.go (left):

https://codereview.appspot.com/95770045/diff/1/utils/ssh/authorisedkeys.go#oldcode48
utils/ssh/authorisedkeys.go:48: return nil, fmt.Errorf("invalid
authorized_key %q", line)
On 2014/04/26 02:09:29, axw wrote:
> Include the ParseAuthorizedKey error in the message?

Was going to errgo wrap it, but the error we get is always "ssh: no key
found" which would actually make our message *worse* if we included it.

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto.go
File utils/ssh/ssh_gocrypto.go (right):

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto.go#newcode84
utils/ssh/ssh_gocrypto.go:84: conn *ssh.Client
On 2014/04/26 02:09:29, axw wrote:
> s/conn/client/
> (and wherever else we refer to Client as conn)
> ?

Done.

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto.go#newcode152
utils/ssh/ssh_gocrypto.go:152: conn.Conn.Close()
On 2014/04/26 02:09:29, axw wrote:
> ssh.Client embeds Conn, so conn.Close (or client.Close) would be
better IMO

Done.

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto_test.go
File utils/ssh/ssh_gocrypto_test.go (right):

https://codereview.appspot.com/95770045/diff/1/utils/ssh/ssh_gocrypto_test.go#newcode31
utils/ssh/ssh_gocrypto_test.go:31: Listener net.Listener
On 2014/04/26 02:09:29, axw wrote:
> s/Listener/listener/
> ?
> (I would prefer we don't export fields unless we need to for
reflection or
> whatever.)

Okay. I guess really we don't need client in this struct, but I'll leave
that addition for now.

https://codereview.appspot.com/95770045/

Revision history for this message
Go Bot (go-bot) wrote :

The attempt to merge lp:~gz/juju-core/gosshnew_1312940 into lp:juju-core failed. Below is the output from the failed tests.

godeps: cannot update "/home/tarmac/trees/src/code.google.com/p/go.crypto": abort: unknown revision '5478be1963aafa9025e9bf0837aff6013eb92e5b'!
mongod: no process found

Revision history for this message
Go Bot (go-bot) wrote :

The attempt to merge lp:~gz/juju-core/gosshnew_1312940 into lp:juju-core failed. Below is the output from the failed tests.

# code.google.com/p/go.crypto/ssh
../../code.google.com/p/go.crypto/ssh/cipher.go:241: undefined: cipher.AEAD
../../code.google.com/p/go.crypto/ssh/cipher.go:253: undefined: cipher.NewGCM
mongod: no process found

Revision history for this message
Martin Packman (gz) wrote :

Blocked for now as golang 1.1.2 lacks a couple of cipher things that the newer go.crypto is using.

Revision history for this message
William Reade (fwereade) wrote :

Setting to WIP then.

Unmerged revisions

2672. By Martin Packman

Naming changes suggested by axw in review

2671. By Martin Packman

Update utils/ssh for gosshnew with latest go.crypto

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'dependencies.tsv'
2--- dependencies.tsv 2014-04-23 08:53:35 +0000
3+++ dependencies.tsv 2014-04-26 17:03:23 +0000
4@@ -1,4 +1,4 @@
5-code.google.com/p/go.crypto hg 6478cc9340cbbe6c04511280c5007722269108e9 184
6+code.google.com/p/go.crypto hg 5478be1963aafa9025e9bf0837aff6013eb92e5b 199
7 code.google.com/p/go.net hg c17ad62118ea511e1051721b429779fa40bddc74 116
8 github.com/errgo/errgo git 93d72bf813883d1054cae1c001d3a46603f7f559
9 github.com/joyent/gocommon git 98b151a080efe19bcde223d2d3b04389963d2347
10
11=== modified file 'utils/ssh/authorisedkeys.go'
12--- utils/ssh/authorisedkeys.go 2014-04-02 11:35:49 +0000
13+++ utils/ssh/authorisedkeys.go 2014-04-26 17:03:23 +0000
14@@ -35,6 +35,7 @@
15 )
16
17 type AuthorisedKey struct {
18+ Type string
19 Key []byte
20 Comment string
21 }
22@@ -43,13 +44,13 @@
23 // authorized_keys file and returns the constituent parts.
24 // Based on description in "man sshd".
25 func ParseAuthorisedKey(line string) (*AuthorisedKey, error) {
26- key, comment, _, _, ok := ssh.ParseAuthorizedKey([]byte(line))
27- if !ok {
28+ key, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(line))
29+ if err != nil {
30 return nil, fmt.Errorf("invalid authorized_key %q", line)
31 }
32- keyBytes := ssh.MarshalPublicKey(key)
33 return &AuthorisedKey{
34- Key: keyBytes,
35+ Type: key.Type(),
36+ Key: key.Marshal(),
37 Comment: comment,
38 }, nil
39 }
40
41=== modified file 'utils/ssh/ssh_gocrypto.go'
42--- utils/ssh/ssh_gocrypto.go 2014-04-14 19:19:59 +0000
43+++ utils/ssh/ssh_gocrypto.go 2014-04-26 17:03:23 +0000
44@@ -81,13 +81,13 @@
45 stdin io.Reader
46 stdout io.Writer
47 stderr io.Writer
48- conn *ssh.ClientConn
49+ client *ssh.Client
50 sess *ssh.Session
51 }
52
53 var sshDial = ssh.Dial
54
55-var sshDialWithProxy = func(addr string, proxyCommand []string, config *ssh.ClientConfig) (*ssh.ClientConn, error) {
56+var sshDialWithProxy = func(addr string, proxyCommand []string, config *ssh.ClientConfig) (*ssh.Client, error) {
57 if len(proxyCommand) == 0 {
58 return sshDial("tcp", addr, config)
59 }
60@@ -114,7 +114,11 @@
61 if err := cmd.Start(); err != nil {
62 return nil, err
63 }
64- return ssh.Client(client, config)
65+ conn, chans, reqs, err := ssh.NewClientConn(client, addr, config)
66+ if err != nil {
67+ return nil, err
68+ }
69+ return ssh.NewClient(conn, chans, reqs), nil
70 }
71
72 func (c *goCryptoCommand) ensureSession() (*ssh.Session, error) {
73@@ -133,20 +137,22 @@
74 }
75 config := &ssh.ClientConfig{
76 User: c.user,
77- Auth: []ssh.ClientAuth{
78- ssh.ClientAuthKeyring(keyring{c.signers}),
79+ Auth: []ssh.AuthMethod{
80+ ssh.PublicKeysCallback(func() ([]ssh.Signer, error) {
81+ return c.signers, nil
82+ }),
83 },
84 }
85- conn, err := sshDialWithProxy(c.addr, c.proxyCommand, config)
86- if err != nil {
87- return nil, err
88- }
89- sess, err := conn.NewSession()
90- if err != nil {
91- conn.Close()
92- return nil, err
93- }
94- c.conn = conn
95+ client, err := sshDialWithProxy(c.addr, c.proxyCommand, config)
96+ if err != nil {
97+ return nil, err
98+ }
99+ sess, err := client.NewSession()
100+ if err != nil {
101+ client.Close()
102+ return nil, err
103+ }
104+ c.client = client
105 c.sess = sess
106 c.sess.Stdin = c.stdin
107 c.sess.Stdout = c.stdout
108@@ -170,12 +176,12 @@
109 return nil
110 }
111 err0 := c.sess.Close()
112- err1 := c.conn.Close()
113+ err1 := c.client.Close()
114 if err0 == nil {
115 err0 = err1
116 }
117 c.sess = nil
118- c.conn = nil
119+ c.client = nil
120 return err0
121 }
122
123@@ -228,26 +234,6 @@
124 return ioutil.NopCloser(wc), sess.Stderr, err
125 }
126
127-// keyring implements ssh.ClientKeyring
128-type keyring struct {
129- signers []ssh.Signer
130-}
131-
132-func (k keyring) Key(i int) (ssh.PublicKey, error) {
133- if i < 0 || i >= len(k.signers) {
134- // nil key marks the end of the keyring; must not return an error.
135- return nil, nil
136- }
137- return k.signers[i].PublicKey(), nil
138-}
139-
140-func (k keyring) Sign(i int, rand io.Reader, data []byte) ([]byte, error) {
141- if i < 0 || i >= len(k.signers) {
142- return nil, fmt.Errorf("no key at position %d", i)
143- }
144- return k.signers[i].Sign(rand, data)
145-}
146-
147 func splitUserHost(s string) (user, host string) {
148 userHost := strings.SplitN(s, "@", 2)
149 if len(userHost) == 2 {
150
151=== modified file 'utils/ssh/ssh_gocrypto_test.go'
152--- utils/ssh/ssh_gocrypto_test.go 2014-04-25 23:47:12 +0000
153+++ utils/ssh/ssh_gocrypto_test.go 2014-04-26 17:03:23 +0000
154@@ -27,8 +27,9 @@
155 )
156
157 type sshServer struct {
158- cfg *cryptossh.ServerConfig
159- *cryptossh.Listener
160+ cfg *cryptossh.ServerConfig
161+ listener net.Listener
162+ client *cryptossh.Client
163 }
164
165 func newServer(c *gc.C) *sshServer {
166@@ -40,40 +41,49 @@
167 cfg: &cryptossh.ServerConfig{},
168 }
169 server.cfg.AddHostKey(key)
170- server.Listener, err = cryptossh.Listen("tcp", "127.0.0.1:0", server.cfg)
171+ server.listener, err = net.Listen("tcp", "127.0.0.1:0")
172 c.Assert(err, gc.IsNil)
173 return server
174 }
175
176 func (s *sshServer) run(c *gc.C) {
177- conn, err := s.Accept()
178+ netconn, err := s.listener.Accept()
179 c.Assert(err, gc.IsNil)
180 defer func() {
181- err = conn.Close()
182+ err = netconn.Close()
183 c.Assert(err, gc.IsNil)
184 }()
185- err = conn.Handshake()
186+ conn, chans, reqs, err := cryptossh.NewServerConn(netconn, s.cfg)
187 c.Assert(err, gc.IsNil)
188+ s.client = cryptossh.NewClient(conn, chans, reqs)
189 var wg sync.WaitGroup
190 defer wg.Wait()
191- for {
192- channel, err := conn.Accept()
193+ sessionChannels := s.client.HandleChannelOpen("session")
194+ c.Assert(sessionChannels, gc.NotNil)
195+ for newChannel := range sessionChannels {
196+ c.Assert(newChannel.ChannelType(), gc.Equals, "session")
197+ channel, reqs, err := newChannel.Accept()
198 c.Assert(err, gc.IsNil)
199- c.Assert(channel.ChannelType(), gc.Equals, "session")
200- channel.Accept()
201 wg.Add(1)
202 go func() {
203 defer wg.Done()
204 defer channel.Close()
205- _, err := channel.Read(nil)
206- c.Assert(err, gc.FitsTypeOf, cryptossh.ChannelRequest{})
207- req := err.(cryptossh.ChannelRequest)
208- c.Assert(req.Request, gc.Equals, "exec")
209- c.Assert(req.WantReply, jc.IsTrue)
210- n := binary.BigEndian.Uint32(req.Payload[:4])
211- command := string(req.Payload[4 : n+4])
212- c.Assert(command, gc.Equals, testCommandFlat)
213- // TODO(axw) when gosshnew is ready, send reply to client.
214+ for req := range reqs {
215+ switch req.Type {
216+ case "exec":
217+ c.Assert(req.WantReply, jc.IsTrue)
218+ n := binary.BigEndian.Uint32(req.Payload[:4])
219+ command := string(req.Payload[4 : n+4])
220+ c.Assert(command, gc.Equals, testCommandFlat)
221+ req.Reply(true, nil)
222+ channel.Write([]byte("abc value\n"))
223+ _, err := channel.SendRequest("exit-status", false, cryptossh.Marshal(&struct{ n uint32 }{0}))
224+ c.Assert(err, gc.IsNil)
225+ return
226+ default:
227+ c.Fatalf("Unexpected request type: %v", req.Type)
228+ }
229+ }
230 }()
231 }
232 }
233@@ -115,7 +125,7 @@
234 err = ssh.LoadClientKeys(c.MkDir())
235 c.Assert(err, gc.IsNil)
236
237- s.PatchValue(ssh.SSHDial, func(network, address string, cfg *cryptossh.ClientConfig) (*cryptossh.ClientConn, error) {
238+ s.PatchValue(ssh.SSHDial, func(network, address string, cfg *cryptossh.ClientConfig) (*cryptossh.Client, error) {
239 return nil, errors.New("ssh.Dial failed")
240 })
241 cmd = client.Command("0.1.2.3", []string{"echo", "123"}, nil)
242@@ -132,19 +142,18 @@
243 c.Assert(err, gc.IsNil)
244 server := newServer(c)
245 var opts ssh.Options
246- opts.SetPort(server.Addr().(*net.TCPAddr).Port)
247+ opts.SetPort(server.listener.Addr().(*net.TCPAddr).Port)
248 cmd := client.Command("127.0.0.1", testCommand, &opts)
249 checkedKey := false
250- server.cfg.PublicKeyCallback = func(conn *cryptossh.ServerConn, user, algo string, pubkey []byte) bool {
251- c.Check(pubkey, gc.DeepEquals, cryptossh.MarshalPublicKey(key.PublicKey()))
252+ server.cfg.PublicKeyCallback = func(conn cryptossh.ConnMetadata, pubkey cryptossh.PublicKey) (*cryptossh.Permissions, error) {
253+ c.Check(pubkey, gc.DeepEquals, key.PublicKey())
254 checkedKey = true
255- return true
256+ return nil, nil
257 }
258 go server.run(c)
259 out, err := cmd.Output()
260- c.Assert(err, gc.ErrorMatches, "ssh: could not execute command.*")
261- // TODO(axw) when gosshnew is ready, expect reply from server.
262- c.Assert(out, gc.IsNil)
263+ c.Assert(err, gc.IsNil)
264+ c.Assert(string(out), gc.Equals, "abc value\n")
265 c.Assert(checkedKey, jc.IsTrue)
266 }
267
268@@ -172,18 +181,17 @@
269 c.Assert(err, gc.IsNil)
270 server := newServer(c)
271 var opts ssh.Options
272- port := server.Addr().(*net.TCPAddr).Port
273+ port := server.listener.Addr().(*net.TCPAddr).Port
274 opts.SetProxyCommand(netcat, "-q0", "%h", "%p")
275 opts.SetPort(port)
276 cmd := client.Command("127.0.0.1", testCommand, &opts)
277- server.cfg.PublicKeyCallback = func(conn *cryptossh.ServerConn, user, algo string, pubkey []byte) bool {
278- return true
279+ server.cfg.PublicKeyCallback = func(_ cryptossh.ConnMetadata, pubkey cryptossh.PublicKey) (*cryptossh.Permissions, error) {
280+ return nil, nil
281 }
282 go server.run(c)
283 out, err := cmd.Output()
284- c.Assert(err, gc.ErrorMatches, "ssh: could not execute command.*")
285- // TODO(axw) when gosshnew is ready, expect reply from server.
286- c.Assert(out, gc.IsNil)
287+ c.Assert(err, gc.IsNil)
288+ c.Assert(string(out), gc.Equals, "abc value\n")
289 // Ensure the proxy command was executed with the appropriate arguments.
290 data, err := ioutil.ReadFile(netcat + ".args")
291 c.Assert(err, gc.IsNil)

Subscribers

People subscribed via source and target branches

to status/vote changes: