I am searching for a way to answer to a shell password prompt in golang.
like :
bussiere@kus:~/Workspace/rteest$ ./passwordtest.sh Password :
I would like to enter the password automatically with my token in golang after launching a shell command / script ...
I've made some script that get a one time token with mfa if everything is ok (in golang). So i need to enter the tempory token to a linux password prompt.
I know that there is the expect command but i would like to compile my program to embed it and have minimal depency.
Thanks and regards
edit thks to @nevermore i've tried this (but it doesn't work) : https://play.golang.org/p/Ffm3q5h636
package main import ( "os/exec" "fmt" "log" "io" ) func main() { cmdb := "git" args := "clone https://bb@gitlab.com/bb/fzgs.git" cmd := exec.Command(cmdb, args) stdin, err := cmd.StdinPipe() if err != nil { log.Fatal(err) } go func() { defer stdin.Close() io.WriteString(stdin, "QSRDFGHJfZERTYU") }() out, err := cmd.CombinedOutput() if err != nil { log.Fatal(err) } fmt.Printf("%s\n", out) }
it gives me this :
2017/05/12 20:42:36 exit status 1 exit status 1
edit bis :
cmdb := "git" args := "https://bb@gitlab.com/bb/fzgs.git" cmd := exec.Command(cmdb, "clone", args)
it asks for the password :
Password for 'https://bb@gitlab.com':
2 Answers
Answers 1
The problem is that you are trying to send the password before Git asks you to do so.
And the way Git asks for password depends on whether credential helper is set. If the credential helper is not set, or doesn't return a password, the user is asked to for input.
Solution #1: Include Password into URI
In most cases (at least with Github and Bitbucket) the Git server accepts credentials passed via HTTPS URI, e.g. https://user:password@domain.com/repo.git
.
cmd := exec.Command("git", "clone", "https://bb:PASSWORD@gitlab.com/bb/fzgs.git") env := os.Environ() env = append(env, "GIT_ASKPASS=") cmd.Env = env var out bytes.Buffer cmd.Stdout = &out err := cmd.Run()
Solution #2: Custom Credential Helper
Another way is to make a credential helper script, e.g.:
#!/bin/bash - printf '%s\n' 'YOUR_PASSWORD'
and pass it via GIT_ASKPASS
:
cmd := exec.Command("git", "clone", "https://bb@gitlab.com/bb/fzgs.git") env := os.Environ() env = append(env, "GIT_ASKPASS=/path/to/fzgs-askpass.sh") cmd.Env = env var out bytes.Buffer cmd.Stdout = &out err := cmd.Run()
Answers 2
If a user is asked for a password in their shell, you can use golang to write to the io.Writer that is os.Stdin
Properly passing data on stdin to a command and receiving data from stdout of that command in golang
os.Stdin
is a os.File
created by
NewFile(uintptr(syscall.Stdin), "/dev/stdin"
And the password prompt will be reading form this file
You can execute ./passwordtest.sh
as in your question, and then write the password to os.Stdin
, and the bash script should accept the bytes written by golang as the password.
Alternatively is actually a method for this in the exec
package for the Cmd
type.
- Use cmd to execute your shell script
- Input the password using stdin, or
cmd.StdinPip()
- Read the shells output using
cmd.CombinedOutput()
Cmd represents an external command being prepared or run.
https://golang.org/pkg/os/exec/#Cmd.StdinPipe
cmd := exec.Command("cat") stdin, err := cmd.StdinPipe() if err != nil { log.Fatal(err) } go func() { defer stdin.Close() io.WriteString(stdin, "values written to stdin are passed to cmd's standard input") }() out, err := cmd.CombinedOutput() if err != nil { log.Fatal(err) } fmt.Printf("%s\n", out)
StdinPipe returns a pipe that will be connected to the command's standard input when the command starts. The pipe will be closed automatically after Wait sees the command exit. A caller need only call Close to force the pipe to close sooner. For example, if the command being run will not exit until standard input is closed, the caller must close the pipe.
Also, your cmd
arguments shouldn't combine clone and the url, try instead
cmd := exec.Command(cmdb, "clone", url)
0 comments:
Post a Comment