1package ssh 2 3import ( 4 "bufio" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "strings" 9 10 "golang.org/x/crypto/ssh" 11 "golang.org/x/crypto/ssh/testdata" 12 13 . "gopkg.in/check.v1" 14) 15 16type ( 17 SuiteCommon struct{} 18 19 mockKnownHosts struct{} 20) 21 22func (mockKnownHosts) host() string { return "github.com" } 23func (mockKnownHosts) knownHosts() []byte { 24 return []byte(`github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==`) 25} 26func (mockKnownHosts) Network() string { return "tcp" } 27func (mockKnownHosts) String() string { return "github.com:22" } 28 29var _ = Suite(&SuiteCommon{}) 30 31func (s *SuiteCommon) TestKeyboardInteractiveName(c *C) { 32 a := &KeyboardInteractive{ 33 User: "test", 34 Challenge: nil, 35 } 36 c.Assert(a.Name(), Equals, KeyboardInteractiveName) 37} 38 39func (s *SuiteCommon) TestKeyboardInteractiveString(c *C) { 40 a := &KeyboardInteractive{ 41 User: "test", 42 Challenge: nil, 43 } 44 c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", KeyboardInteractiveName)) 45} 46 47func (s *SuiteCommon) TestPasswordName(c *C) { 48 a := &Password{ 49 User: "test", 50 Password: "", 51 } 52 c.Assert(a.Name(), Equals, PasswordName) 53} 54 55func (s *SuiteCommon) TestPasswordString(c *C) { 56 a := &Password{ 57 User: "test", 58 Password: "", 59 } 60 c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PasswordName)) 61} 62 63func (s *SuiteCommon) TestPasswordCallbackName(c *C) { 64 a := &PasswordCallback{ 65 User: "test", 66 Callback: nil, 67 } 68 c.Assert(a.Name(), Equals, PasswordCallbackName) 69} 70 71func (s *SuiteCommon) TestPasswordCallbackString(c *C) { 72 a := &PasswordCallback{ 73 User: "test", 74 Callback: nil, 75 } 76 c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PasswordCallbackName)) 77} 78 79func (s *SuiteCommon) TestPublicKeysName(c *C) { 80 a := &PublicKeys{ 81 User: "test", 82 Signer: nil, 83 } 84 c.Assert(a.Name(), Equals, PublicKeysName) 85} 86 87func (s *SuiteCommon) TestPublicKeysString(c *C) { 88 a := &PublicKeys{ 89 User: "test", 90 Signer: nil, 91 } 92 c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PublicKeysName)) 93} 94 95func (s *SuiteCommon) TestPublicKeysCallbackName(c *C) { 96 a := &PublicKeysCallback{ 97 User: "test", 98 Callback: nil, 99 } 100 c.Assert(a.Name(), Equals, PublicKeysCallbackName) 101} 102 103func (s *SuiteCommon) TestPublicKeysCallbackString(c *C) { 104 a := &PublicKeysCallback{ 105 User: "test", 106 Callback: nil, 107 } 108 c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PublicKeysCallbackName)) 109} 110func (s *SuiteCommon) TestNewSSHAgentAuth(c *C) { 111 if os.Getenv("SSH_AUTH_SOCK") == "" { 112 c.Skip("SSH_AUTH_SOCK or SSH_TEST_PRIVATE_KEY are required") 113 } 114 115 auth, err := NewSSHAgentAuth("foo") 116 c.Assert(err, IsNil) 117 c.Assert(auth, NotNil) 118} 119 120func (s *SuiteCommon) TestNewSSHAgentAuthNoAgent(c *C) { 121 addr := os.Getenv("SSH_AUTH_SOCK") 122 err := os.Unsetenv("SSH_AUTH_SOCK") 123 c.Assert(err, IsNil) 124 125 defer func() { 126 err := os.Setenv("SSH_AUTH_SOCK", addr) 127 c.Assert(err, IsNil) 128 }() 129 130 k, err := NewSSHAgentAuth("foo") 131 c.Assert(k, IsNil) 132 c.Assert(err, ErrorMatches, ".*SSH_AUTH_SOCK.*|.*SSH agent .* not running.*") 133} 134 135func (*SuiteCommon) TestNewPublicKeys(c *C) { 136 auth, err := NewPublicKeys("foo", testdata.PEMBytes["rsa"], "") 137 c.Assert(err, IsNil) 138 c.Assert(auth, NotNil) 139} 140 141func (*SuiteCommon) TestNewPublicKeysWithEncryptedPEM(c *C) { 142 f := testdata.PEMEncryptedKeys[0] 143 auth, err := NewPublicKeys("foo", f.PEMBytes, f.EncryptionKey) 144 c.Assert(err, IsNil) 145 c.Assert(auth, NotNil) 146} 147 148func (*SuiteCommon) TestNewPublicKeysFromFile(c *C) { 149 f, err := ioutil.TempFile("", "ssh-test") 150 c.Assert(err, IsNil) 151 _, err = f.Write(testdata.PEMBytes["rsa"]) 152 c.Assert(err, IsNil) 153 c.Assert(f.Close(), IsNil) 154 defer os.RemoveAll(f.Name()) 155 156 auth, err := NewPublicKeysFromFile("foo", f.Name(), "") 157 c.Assert(err, IsNil) 158 c.Assert(auth, NotNil) 159} 160 161func (*SuiteCommon) TestNewPublicKeysWithInvalidPEM(c *C) { 162 auth, err := NewPublicKeys("foo", []byte("bar"), "") 163 c.Assert(err, NotNil) 164 c.Assert(auth, IsNil) 165} 166 167func (*SuiteCommon) TestNewKnownHostsCallback(c *C) { 168 var mock = mockKnownHosts{} 169 170 f, err := ioutil.TempFile("", "known-hosts") 171 c.Assert(err, IsNil) 172 173 _, err = f.Write(mock.knownHosts()) 174 c.Assert(err, IsNil) 175 176 err = f.Close() 177 c.Assert(err, IsNil) 178 179 defer os.RemoveAll(f.Name()) 180 181 f, err = os.Open(f.Name()) 182 c.Assert(err, IsNil) 183 184 defer f.Close() 185 186 var hostKey ssh.PublicKey 187 scanner := bufio.NewScanner(f) 188 for scanner.Scan() { 189 fields := strings.Split(scanner.Text(), " ") 190 if len(fields) != 3 { 191 continue 192 } 193 if strings.Contains(fields[0], mock.host()) { 194 var err error 195 hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes()) 196 if err != nil { 197 c.Fatalf("error parsing %q: %v", fields[2], err) 198 } 199 break 200 } 201 } 202 if hostKey == nil { 203 c.Fatalf("no hostkey for %s", mock.host()) 204 } 205 206 clb, err := NewKnownHostsCallback(f.Name()) 207 c.Assert(err, IsNil) 208 209 err = clb(mock.String(), mock, hostKey) 210 c.Assert(err, IsNil) 211} 212