Merge lp:~axwalk/juju-core/ssh-authorized-keys-gocrypto into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2276
Proposed branch: lp:~axwalk/juju-core/ssh-authorized-keys-gocrypto
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 222 lines (+23/-116)
3 files modified
utils/ssh/authorisedkeys.go (+6/-93)
utils/ssh/authorisedkeys_test.go (+16/-22)
utils/ssh/fingerprint_test.go (+1/-1)
To merge this branch: bzr merge lp:~axwalk/juju-core/ssh-authorized-keys-gocrypto
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+203878@code.launchpad.net

Commit message

utils/ssh: use go.crypto/ssh.ParseAuthorizedKey

There's a function in go.crypto/ssh that we
can use for parsing authorized_key lines. We
should use it.

https://codereview.appspot.com/58540043/

Description of the change

utils/ssh: use go.crypto/ssh.ParseAuthorizedKey

There's a function in go.crypto/ssh that we
can use for parsing authorized_key lines. We
should use it.

https://codereview.appspot.com/58540043/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Reviewers: mp+203878_code.launchpad.net,

Message:
Please take a look.

Description:
utils/ssh: use go.crypto/ssh.ParseAuthorizedKey

There's a function in go.crypto/ssh that we
can use for parsing authorized_key lines. We
should use it.

https://code.launchpad.net/~axwalk/juju-core/ssh-authorized-keys-gocrypto/+merge/203878

(do not edit description out of merge proposal)

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

Affected files (+25, -116 lines):
   A [revision details]
   M utils/ssh/authorisedkeys.go
   M utils/ssh/authorisedkeys_test.go
   M utils/ssh/fingerprint_test.go

Revision history for this message
Ian Booth (wallyworld) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'utils/ssh/authorisedkeys.go'
2--- utils/ssh/authorisedkeys.go 2014-01-28 04:58:43 +0000
3+++ utils/ssh/authorisedkeys.go 2014-01-30 06:16:19 +0000
4@@ -4,7 +4,6 @@
5 package ssh
6
7 import (
8- "encoding/base64"
9 "fmt"
10 "io/ioutil"
11 "os"
12@@ -15,6 +14,7 @@
13 "strings"
14 "sync"
15
16+ "code.google.com/p/go.crypto/ssh"
17 "github.com/loggo/loggo"
18
19 "launchpad.net/juju-core/utils"
20@@ -34,108 +34,21 @@
21 authKeysFile = "authorized_keys"
22 )
23
24-// case-insensive public authorized_keys options
25-var validOptions = [...]string{
26- "cert-authority",
27- "command",
28- "environment",
29- "from",
30- "no-agent",
31- "no-port-forwarding",
32- "no-pty",
33- "no-user",
34- "no-X11-forwarding",
35- "permitopen",
36- "principals",
37- "tunnel",
38-}
39-
40-var validKeytypes = [...]string{
41- "ecdsa-sha2-nistp256",
42- "ecdsa-sha2-nistp384",
43- "ecdsa-sha2-nistp521",
44- "ssh-dss",
45- "ssh-rsa",
46-}
47-
48 type AuthorisedKey struct {
49- KeyType string
50 Key []byte
51 Comment string
52 }
53
54-// skipOptions takes a non-comment line from an
55-// authorized_keys file, and returns the remainder
56-// of the line after skipping any options at the
57-// beginning of the line.
58-func skipOptions(line string) string {
59- found := false
60- lower := strings.ToLower(line)
61- for _, o := range validOptions {
62- if strings.HasPrefix(lower, o) {
63- line = line[len(o):]
64- found = true
65- break
66- }
67- }
68- if !found {
69- return line
70- }
71- // Skip to the next unquoted whitespace, returning the remainder.
72- // Double quotes may be escaped with \".
73- var quoted bool
74- for i := 0; i < len(line); i++ {
75- switch line[i] {
76- case ' ', '\t':
77- if !quoted {
78- return strings.TrimLeft(line[i+1:], " \t")
79- }
80- case '\\':
81- if i+1 < len(line) && line[i+1] == '"' {
82- i++
83- }
84- case '"':
85- quoted = !quoted
86- }
87- }
88- return ""
89-}
90-
91 // ParseAuthorisedKey parses a non-comment line from an
92 // authorized_keys file and returns the constituent parts.
93 // Based on description in "man sshd".
94-//
95-// TODO(axw) support version 1 format?
96 func ParseAuthorisedKey(line string) (*AuthorisedKey, error) {
97- withoutOptions := skipOptions(line)
98- var keytype, key, comment string
99- if i := strings.IndexAny(withoutOptions, " \t"); i == -1 {
100- // There must be at least two fields: keytype and key.
101- return nil, fmt.Errorf("malformed line: %q", line)
102- } else {
103- keytype = withoutOptions[:i]
104- key = strings.TrimSpace(withoutOptions[i+1:])
105- }
106- validKeytype := false
107- for _, kt := range validKeytypes {
108- if keytype == kt {
109- validKeytype = true
110- break
111- }
112- }
113- if !validKeytype {
114- return nil, fmt.Errorf("invalid keytype %q in line %q", keytype, line)
115- }
116- // Split key/comment (if any)
117- if i := strings.IndexAny(key, " \t"); i != -1 {
118- key, comment = key[:i], key[i+1:]
119- }
120- keyBytes, err := base64.StdEncoding.DecodeString(key)
121- if err != nil {
122- return nil, err
123- }
124+ key, comment, _, _, ok := ssh.ParseAuthorizedKey([]byte(line))
125+ if !ok {
126+ return nil, fmt.Errorf("invalid authorized_key %q", line)
127+ }
128+ keyBytes := ssh.MarshalPublicKey(key)
129 return &AuthorisedKey{
130- KeyType: keytype,
131 Key: keyBytes,
132 Comment: comment,
133 }, nil
134
135=== modified file 'utils/ssh/authorisedkeys_test.go'
136--- utils/ssh/authorisedkeys_test.go 2014-01-10 02:42:02 +0000
137+++ utils/ssh/authorisedkeys_test.go 2014-01-30 06:16:19 +0000
138@@ -5,6 +5,7 @@
139
140 import (
141 "encoding/base64"
142+ "strings"
143 stdtesting "testing"
144
145 gc "launchpad.net/gocheck"
146@@ -236,41 +237,35 @@
147 }
148 }
149
150-func b64(s string) string {
151- return base64.StdEncoding.EncodeToString([]byte(s))
152+func b64decode(c *gc.C, s string) []byte {
153+ b, err := base64.StdEncoding.DecodeString(s)
154+ c.Assert(err, gc.IsNil)
155+ return b
156 }
157
158 func (s *AuthorisedKeysKeysSuite) TestParseAuthorisedKey(c *gc.C) {
159 for i, test := range []struct {
160 line string
161- keytype string
162- key string
163+ key []byte
164 comment string
165 err string
166 }{{
167- line: "ssh-rsa " + b64("abc def"),
168- keytype: "ssh-rsa",
169- key: "abc def",
170- }, {
171- line: "ssh-dss " + b64("abc def"),
172- keytype: "ssh-dss",
173- key: "abc def",
174- }, {
175- line: "ssh-rsa " + b64("abc def") + " a b c",
176- keytype: "ssh-rsa",
177- key: "abc def",
178+ line: sshtesting.ValidKeyOne.Key,
179+ key: b64decode(c, strings.Fields(sshtesting.ValidKeyOne.Key)[1]),
180+ }, {
181+ line: sshtesting.ValidKeyOne.Key + " a b c",
182+ key: b64decode(c, strings.Fields(sshtesting.ValidKeyOne.Key)[1]),
183 comment: "a b c",
184 }, {
185 line: "ssh-xsa blah",
186- err: "invalid keytype \"ssh-xsa\" in line \"ssh-xsa blah\"",
187+ err: "invalid authorized_key \"ssh-xsa blah\"",
188 }, {
189 // options should be skipped
190- line: `no-pty,principals="\"",command="\!" ssh-rsa ` + b64("blah"),
191- keytype: "ssh-rsa",
192- key: "blah",
193+ line: `no-pty,principals="\"",command="\!" ` + sshtesting.ValidKeyOne.Key,
194+ key: b64decode(c, strings.Fields(sshtesting.ValidKeyOne.Key)[1]),
195 }, {
196 line: "ssh-rsa",
197- err: "malformed line: \"ssh-rsa\"",
198+ err: "invalid authorized_key \"ssh-rsa\"",
199 }} {
200 c.Logf("test %d: %s", i, test.line)
201 ak, err := ssh.ParseAuthorisedKey(test.line)
202@@ -279,8 +274,7 @@
203 } else {
204 c.Assert(err, gc.IsNil)
205 c.Assert(ak, gc.Not(gc.IsNil))
206- c.Assert(ak.KeyType, gc.Equals, test.keytype)
207- c.Assert(string(ak.Key), gc.Equals, test.key)
208+ c.Assert(ak.Key, gc.DeepEquals, test.key)
209 c.Assert(ak.Comment, gc.Equals, test.comment)
210 }
211 }
212
213=== modified file 'utils/ssh/fingerprint_test.go'
214--- utils/ssh/fingerprint_test.go 2014-01-10 02:42:02 +0000
215+++ utils/ssh/fingerprint_test.go 2014-01-30 06:16:19 +0000
216@@ -32,5 +32,5 @@
217
218 func (s *FingerprintSuite) TestKeyFingerprintError(c *gc.C) {
219 _, _, err := ssh.KeyFingerprint("invalid key")
220- c.Assert(err, gc.ErrorMatches, `generating key fingerprint: invalid keytype "invalid" in line "invalid key"`)
221+ c.Assert(err, gc.ErrorMatches, `generating key fingerprint: invalid authorized_key "invalid key"`)
222 }

Subscribers

People subscribed via source and target branches

to status/vote changes: