英文:
Answer to password shell prompt in golang
问题
我正在寻找一种在Golang中回答shell密码提示的方法。
例如:
bussiere@kus:~/Workspace/rteest$ ./passwordtest.sh
Password :
我想在启动shell命令/脚本后,使用我的令牌自动输入密码。
我已经编写了一些脚本,在Golang中使用MFA获取一次性令牌(如果一切正常)。因此,我需要将临时令牌输入到Linux密码提示中。
我知道有expect命令,但我想将我的程序编译为嵌入式程序,并尽量减少依赖。
谢谢和问候
编辑感谢@nevermore,我尝试了这个(但它不起作用):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)
}
它给我返回了这个:
2017/05/12 20:42:36 exit status 1
exit status 1
再次编辑:
cmdb := "git"
args := "https://bb@gitlab.com/bb/fzgs.git"
cmd := exec.Command(cmdb, "clone", args)
它要求输入密码:
Password for 'https://bb@gitlab.com':
英文:
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':
答案1
得分: 4
如果用户在其shell中被要求输入密码,您可以使用golang来写入io.Writer,即os.Stdin
。
**os.Stdin
**是通过以下方式创建的os.File
:
NewFile(uintptr(syscall.Stdin), "/dev/stdin")
密码提示将从此文件中读取。
您可以像在问题中那样执行./passwordtest.sh
,然后将密码写入os.Stdin
,bash脚本应该将golang写入的字节作为密码接受。
另外,在exec
包的Cmd
类型中实际上有一种方法可以实现这一点。
- 使用cmd执行您的shell脚本
- 使用stdin或
cmd.StdinPipe()
输入密码 - 使用
cmd.CombinedOutput()
读取shell的输出
> Cmd表示正在准备或运行的外部命令。
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返回一个管道,当命令启动时,该管道将连接到命令的标准输入。在Wait看到命令退出后,管道将自动关闭。调用者只需调用Close来更早地强制关闭管道。例如,如果运行的命令在关闭标准输入之前不会退出,调用者必须关闭管道。
此外,您的cmd
参数不应将clone和url组合在一起,而应尝试使用以下方式:
cmd := exec.Command(cmdb, "clone", url)
英文:
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
os.Stdin
is a os.File
created by
NewFile(uintptr(syscall.Stdin), "/dev/stdin")
And the password prompt will be reading from 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.
<hr>
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)
答案2
得分: 4
问题是你试图在Git要求你输入密码之前发送密码。
而Git要求密码的方式取决于是否设置了凭据助手。如果未设置凭据助手,或者凭据助手未返回密码,系统会要求用户输入密码。
解决方案1:将密码包含在URI中
在大多数情况下(至少在Github和Bitbucket上),Git服务器接受通过HTTPS URI传递的凭据,例如 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()
解决方案2:自定义凭据助手
另一种方法是创建一个凭据助手脚本,例如:
#!/bin/bash -
printf '%s\n' 'YOUR_PASSWORD'
并通过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()
英文:
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 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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论