Skip to content

Commit

Permalink
Merge pull request #33 from moul/fix-28
Browse files Browse the repository at this point in the history
Add password-auth-script support
  • Loading branch information
moul committed Sep 30, 2015
2 parents dc79b1e + 2a3ef6d commit d86abfb
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 17 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ GLOBAL OPTIONS:

### master (unreleased)

* Support of 'ssh2docker --password-auth-script' options ([#28](https://github.com/moul/ssh2docker/issues/28))
* Add docker support ([#17](https://github.com/moul/ssh2docker/issues/17))
* Add GOXC support to build binaries for multiple architectures ([#18](https://github.com/moul/ssh2docker/issues/18))
* Support of 'ssh2docker --clean-on-startup' ([#23](https://github.com/moul/ssh2docker/issues/23))
Expand Down
45 changes: 43 additions & 2 deletions auth.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package ssh2docker

import (
"encoding/json"
"fmt"
"os/exec"

"github.com/moul/ssh2docker/vendor/github.com/Sirupsen/logrus"
"github.com/moul/ssh2docker/vendor/golang.org/x/crypto/ssh"
)

Expand All @@ -20,10 +23,48 @@ func (s *Server) ImageIsAllowed(target string) bool {
}

// PasswordCallback is called when the user tries to authenticate using a password
func (s *Server) PasswordCallback(conn ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
image := conn.User()
func (s *Server) PasswordCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
username := conn.User()
clientID := conn.RemoteAddr().String()

logrus.Debugf("PasswordCallback: %q %q", username, password)
var image string

if s.PasswordAuthScript != "" {
// Using a hook script
script, err := expandUser(s.PasswordAuthScript)
if err != nil {
logrus.Warnf("Failed to expandUser: %v", err)
return nil, err
}
cmd := exec.Command(script, username, string(password))
output, err := cmd.CombinedOutput()
if err != nil {
logrus.Warnf("Failed to execute password-auth-script: %v", err)
return nil, err
}

var config ClientConfig
err = json.Unmarshal(output, &config)
if err != nil {
logrus.Warnf("Failed to unmarshal json %q: %v", string(output), err)
return nil, err
}
s.ClientConfigs[clientID] = &config
if config.Allowed == false {
logrus.Warnf("Hook returned allowed:false")
return nil, fmt.Errorf("Access not allowed")
}

return nil, nil
} else {
// Default behavior
image = username
}

if s.ImageIsAllowed(image) {
return nil, nil
}

return nil, fmt.Errorf("TEST")
}
23 changes: 16 additions & 7 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ type Client struct {
Server *Server
Pty, Tty *os.File
Env Environment
RemoteUser string
ImageName string
Config *ClientConfig
}

type ClientConfig struct {
ImageName string `json:"image-name",omitempty`
RemoteUser string `json:"remote-user",omitempty`
Allowed bool `json:"allowed",omitempty`
}

// NewClient initializes a new client
Expand All @@ -39,14 +44,18 @@ func NewClient(conn *ssh.ServerConn, chans <-chan ssh.NewChannel, reqs <-chan *s
Chans: chans,
Reqs: reqs,
Server: server,
ImageName: conn.User(),
RemoteUser: "nobody",
Env: Environment{
"TERM": os.Getenv("TERM"),
"DOCKER_HOST": os.Getenv("DOCKER_HOST"),
"DOCKER_CERT_PATH": os.Getenv("DOCKER_CERT_PATH"),
"DOCKER_TLS_VERIFY": os.Getenv("DOCKER_TLS_VERIFY"),
},

// Default ClientConfig, maybe we should completely remove it
Config: &ClientConfig{
ImageName: conn.User(),
RemoteUser: "anonymous",
},
}

clientCounter++
Expand Down Expand Up @@ -124,7 +133,7 @@ func (c *Client) HandleChannelRequests(channel ssh.Channel, requests <-chan *ssh
// checking if a container already exists for this user
existingContainer := ""
if !c.Server.NoJoin {
cmd := exec.Command("docker", "ps", "--filter=label=ssh2docker", fmt.Sprintf("--filter=label=image=%s", c.ImageName), fmt.Sprintf("--filter=label=user=%s", c.RemoteUser), "--quiet", "--no-trunc")
cmd := exec.Command("docker", "ps", "--filter=label=ssh2docker", fmt.Sprintf("--filter=label=image=%s", c.Config.ImageName), fmt.Sprintf("--filter=label=user=%s", c.Config.RemoteUser), "--quiet", "--no-trunc")
buf, err := cmd.CombinedOutput()
if err != nil {
logrus.Warnf("docker ps ... failed: %v", err)
Expand All @@ -146,8 +155,8 @@ func (c *Client) HandleChannelRequests(channel ssh.Channel, requests <-chan *ssh
// Creating and attaching to a new container
args := []string{"run"}
args = append(args, c.Server.DockerRunArgs...)
args = append(args, "--label=ssh2docker", fmt.Sprintf("--label=user=%s", c.RemoteUser), fmt.Sprintf("--label=image=%s", c.ImageName))
args = append(args, c.ImageName, c.Server.DefaultShell)
args = append(args, "--label=ssh2docker", fmt.Sprintf("--label=user=%s", c.Config.RemoteUser), fmt.Sprintf("--label=image=%s", c.Config.ImageName))
args = append(args, c.Config.ImageName, c.Server.DefaultShell)
logrus.Debugf("Executing 'docker %s'", strings.Join(args, " "))
cmd = exec.Command("docker", args...)
cmd.Env = c.Env.List()
Expand Down
5 changes: 5 additions & 0 deletions cmd/ssh2docker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ func main() {
Name: "clean-on-startup",
Usage: "Cleanup Docker containers created by ssh2docker on start",
},
cli.StringFlag{
Name: "password-auth-script",
Usage: "Password auth hook file",
},
}

app.Action = Action
Expand Down Expand Up @@ -128,6 +132,7 @@ func Action(c *cli.Context) {
server.DockerRunArgs = strings.Split(c.String("docker-run-args"), " ")
server.NoJoin = c.Bool("no-join")
server.CleanOnStartup = c.Bool("clean-on-startup")
server.PasswordAuthScript = c.String("password-auth-script")

// Register the SSH host key
hostKey := c.String("host-key")
Expand Down
2 changes: 1 addition & 1 deletion docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"os/exec"
"strings"

"github.com/Sirupsen/logrus"
"github.com/moul/ssh2docker/vendor/github.com/Sirupsen/logrus"
)

// DockerCleanup cleans all containers created by ssh2docker
Expand Down
17 changes: 10 additions & 7 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import (
// Server is the ssh2docker main structure
type Server struct {
SshConfig *ssh.ServerConfig
// Clients []Client
// Clients map[string]Client
ClientConfigs map[string]*ClientConfig

AllowedImages []string
DefaultShell string
DockerRunArgs []string
NoJoin bool
CleanOnStartup bool
AllowedImages []string
DefaultShell string
DockerRunArgs []string
NoJoin bool
CleanOnStartup bool
PasswordAuthScript string

initialized bool
}
Expand All @@ -27,7 +29,7 @@ func NewServer() (*Server, error) {
server.SshConfig = &ssh.ServerConfig{
PasswordCallback: server.PasswordCallback,
}
server.AllowedImages = nil
server.ClientConfigs = make(map[string]*ClientConfig, 0)
server.DefaultShell = "/bin/sh"
server.DockerRunArgs = []string{"-it", "--rm"}
return &server, nil
Expand Down Expand Up @@ -64,6 +66,7 @@ func (s *Server) Handle(netConn net.Conn) error {
return err
}
client := NewClient(conn, chans, reqs, s)
client.Config = s.ClientConfigs[conn.RemoteAddr().String()]

// Handle requests
if err = client.HandleRequests(); err != nil {
Expand Down
22 changes: 22 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ssh2docker

import (
"errors"
"os"
"strings"
)

func expandUser(path string) (string, error) {
if path[:2] == "~/" {
homeDir := os.Getenv("HOME") // *nix
if homeDir == "" { // Windows
homeDir = os.Getenv("USERPROFILE")
}
if homeDir == "" {
return "", errors.New("user home directory not found")
}

return strings.Replace(path, "~", homeDir, 1), nil
}
return path, nil
}

0 comments on commit d86abfb

Please sign in to comment.