Answer to password shell prompt in golang

huangapple go评论104阅读模式
英文:

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

https://stackoverflow.com/questions/14803425/properly-passing-data-on-stdin-to-a-command-and-receiving-data-from-stdout-of-th

**os.Stdin**是通过以下方式创建的os.File

NewFile(uintptr(syscall.Stdin), "/dev/stdin")

密码提示将从此文件中读取。

您可以像在问题中那样执行./passwordtest.sh,然后将密码写入os.Stdin,bash脚本应该将golang写入的字节作为密码接受。


另外,在exec包的Cmd类型中实际上有一种方法可以实现这一点。

  1. 使用cmd执行您的shell脚本
  2. 使用stdincmd.StdinPipe()输入密码
  3. 使用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

https://stackoverflow.com/questions/14803425/properly-passing-data-on-stdin-to-a-command-and-receiving-data-from-stdout-of-th

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.

  1. Use cmd to execute your shell script
  2. Input the password using stdin, or cmd.StdinPip()
  3. 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(&quot;cat&quot;)
stdin, err := cmd.StdinPipe()
if err != nil {
	log.Fatal(err)
}

go func() {
	defer stdin.Close()
	io.WriteString(stdin, &quot;values written to stdin are passed to cmd&#39;s standard input&quot;)
}()

out, err := cmd.CombinedOutput()
if err != nil {
	log.Fatal(err)
}

fmt.Printf(&quot;%s\n&quot;, 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, &quot;clone&quot;, 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(&quot;git&quot;, &quot;clone&quot;, &quot;https://bb:PASSWORD@gitlab.com/bb/fzgs.git&quot;)

env := os.Environ()
env = append(env, &quot;GIT_ASKPASS=&quot;)
cmd.Env = env

var out bytes.Buffer
cmd.Stdout = &amp;out

err := cmd.Run()

Solution #2: Custom Credential Helper

Another way is to make a credential helper script, e.g.:

#!/bin/bash -
printf &#39;%s\n&#39; &#39;YOUR_PASSWORD&#39;

and pass it via GIT_ASKPASS:

cmd := exec.Command(&quot;git&quot;, &quot;clone&quot;, &quot;https://bb@gitlab.com/bb/fzgs.git&quot;)

env := os.Environ()
env = append(env, &quot;GIT_ASKPASS=/path/to/fzgs-askpass.sh&quot;)
cmd.Env = env

var out bytes.Buffer
cmd.Stdout = &amp;out

err := cmd.Run()

huangapple
  • 本文由 发表于 2017年5月13日 01:49:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/43943742.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定