SSH Interactive authentication

426 views
Skip to first unread message

Carl Menezes

unread,
Nov 20, 2013, 8:40:29 PM11/20/13
to golan...@googlegroups.com
I've been trying to get a simple little scp implementation going that tries to download a specific file. 
As I understand it, I can provide an interactive authenticator that will be used to prompt the user for login information, if required.
However, when I use this, my Challenge implementation is simply not called. I'm on Windows, if that makes a difference.
Here's the code. Please forgive the quality - this was something I threw together in about 15 minutes.

I would appreciate any pointers in the right direction.

Cheers,
Carl

package main

import (
"io"
)

type interactive_authenticator string

func (f interactive_authenticator) Challenge(user, instruction string, questions []string, echos []bool) ([]string, error) {
        //Yes, I know about the RFC, but I just want to see what happens here.
println("trying to get password from user")
answers := []string{}
print(instruction)
print(user)
print(echos)
for _, q := range questions {
println(q)
}
answers = append(answers, string(gopass.GetPasswd()))
return answers, nil
}

func get_interactive_authenticator() (i interactive_authenticator) {
return i
}

func doscp_custom_port(host, port, username, passwd, remote_file, local_file string) error {
// Dial code is taken from the ssh package example
config := &ssh.ClientConfig{
User: username,
Auth: []ssh.ClientAuth{
ssh.ClientAuthKeyboardInteractive(get_interactive_authenticator()),
},
}
client, err := ssh.Dial("tcp", host+":"+port, config)
if err != nil {
println("Unable to connect" + err.Error())
return err
}

session, err := client.NewSession()
if err != nil {
println("Failed to create session: " + err.Error())
return err
}
defer session.Close()

go func() {
r, _ := session.StdoutPipe()
if w, err := open_file(local_file); err == nil {
defer w.Close()
io.Copy(w, r)
}
}()
if err := session.Run("`which cat` " + remote_file); err != nil {
println("Could not retrieve file. Reason:" + err.Error())
return err
}
return nil
}

func main() {
if err := doscp_custom_port("localhost", "22", "", "~/test.txt", "test.txt"); err == nil{
       println("File copied successfully")
    } else {
      println("Could not retrieve the file")
   }
}

Carl Menezes

unread,
Nov 20, 2013, 8:41:44 PM11/20/13
to golan...@googlegroups.com
This should have been part of the import too:

package main

import (

Carl Menezes

unread,
Nov 20, 2013, 8:46:03 PM11/20/13
to golan...@googlegroups.com
Sorry..missed out an import. 

Here is the code again:

package main

import (

On Thursday, November 21, 2013 2:40:29 PM UTC+13, Carl Menezes wrote:

Carl Menezes

unread,
Nov 20, 2013, 10:39:52 PM11/20/13
to golan...@googlegroups.com
This is the error message I got: 
Unable to connect: handshake failed: ssh: unable to authenticate, attempted methods [none], no supported methods remain     

Alex Zorin

unread,
Nov 21, 2013, 12:34:04 AM11/21/13
to golan...@googlegroups.com
The code you posted does not compile (open_file missing, among other things).

However, based on the error I believe the problem is that the server you are connecting to does not have challenge authentication enabled. Check your sshd_config for 'ChallengeResponseAuthentication yes'.

Carl Menezes

unread,
Nov 21, 2013, 1:59:40 AM11/21/13
to Alex Zorin, golang-nuts
My apologies. 

Thanks for the heads up about the ssh config. I will look into it. 
I did try using ClientAuthPassword and that works, given the right username and password.

Here is the complete code:

package main

import (
"io"
    "os"
)

type interactive_authenticator string

func (f interactive_authenticator) Challenge(user, instruction string, questions []string, echos []bool) ([]string, error) {
        //Yes, I know about the RFC, but I just want to see what happens here.
println("trying to get password from user")
answers := []string{}
print(instruction)
print(user)
print(echos)
for _, q := range questions {
println(q)
}
answers = append(answers, string(gopass.GetPasswd()))
return answers, nil
}

func get_interactive_authenticator() (i interactive_authenticator) {
return i
}

func open_file(filename string) (w io.WriteCloser, err error){
    return os.Create(filename)
if err := doscp_custom_port("localhost", "22", "test", "", "~/test.txt", "test.txt"); err == nil{

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/_uxqYD2cnuk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Carl Menezes

unread,
Nov 21, 2013, 2:53:25 PM11/21/13
to golan...@googlegroups.com
Just a follow up in case someone else has this issue. 

The issue was indeed the sshd_config (/etc/ssh/sshd_config on Ubuntu), as Alex had suggested.
Changing ChallengeResponseAuthentication to yes and restarting the service resulted in the Challenge function being called.

To unsubscribe from this group and all its topics, send an email to golang-nuts+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages