practice / blog

For personal blogging
1 stars 0 forks source link

scp using java sshd and golang client #53

Open practice opened 6 years ago

practice commented 6 years ago

Java Server using apache sshd

(defonce sshdserver (atom nil))
(defn start-sshd [^Integer port]
  (let [server (SshServer/setUpDefaultServer)]
    (doto server
      (.setPort port)
      (.setKeyPairProvider (SimpleGeneratorHostKeyProvider. (File. "cedsd-hostkey.ser")))
      (.setCommandFactory (ScpCommandFactory.))
      (.setPasswordAuthenticator (reify PasswordAuthenticator
                                   (authenticate [_ username password _server-session]
                                     (log/info "sshd auth:" username "," password)
                                     (let [user (userquery/get-user username)]
                                       (let [ret (and (:enabled @user) (userquery/match-password? @user password))]
                                         (if ret (log/info "ssh login success:" username)
                                                 (log/info "ssh login fail:" username))
                                         ret)))))
      (.setFileSystemFactory (VirtualFileSystemFactory. ^Path (Paths/get (URI. (str "file://" (conf/repo-root))))))
      (.start))
    (reset! sshdserver server)))

(defn stop-sshd []
  (when @sshdserver
    (doto @sshdserver .stop)))

command line client

$ scp -P 8097 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev.edn root@localhost:/scp-3.dev.edn

Golang client

package main

import (
        "fmt"
        "os"
        "io"
        "path"

        "golang.org/x/crypto/ssh"
)

func main() {
        clientConfig := &ssh.ClientConfig{
                User: "root",
                Auth: []ssh.AuthMethod{
                        ssh.Password("root"),
                },
        }
        clientConfig.HostKeyCallback = ssh.InsecureIgnoreHostKey()

        client, err := ssh.Dial("tcp", "127.0.0.1:8097", clientConfig)
        if err != nil {
                panic("Failed to dial: " + err.Error())
        }
        session, err := client.NewSession()
        if err != nil {
                panic("Failed to create session: " + err.Error())
        }
        defer session.Close()
        /*
        go func() {
                w, _ := session.StdinPipe()
                defer w.Close()
                content := "123456789\n"
                fmt.Fprintln(w, "D0755", 0, "testdir") // mkdir
                fmt.Fprintln(w, "C0644", len(content), "testfile1")
                fmt.Fprint(w, content)
                fmt.Fprint(w, "\x00") // transfer end with \x00
                fmt.Fprintln(w, "C0644", len(content), "testfile2")
                fmt.Fprint(w, content)
                fmt.Fprint(w, "\x00")
        }()
        if err := session.Run("/usr/bin/scp -tr ./"); err != nil {
                panic("Failed to run: " + err.Error())
        }
        */
        f, _ := os.Open("myscp.go")
        CopyFromFile(session, f, "/hello/dev.sample.edn", "0644")
}

func CopyFromFile(session *ssh.Session, file *os.File, remotePath string, permissions string) {
        stat, _ := file.Stat()
        Copy(session, file, remotePath, permissions, stat.Size())
}

// Copies the contents of an io.Reader to a remote location
func Copy(session *ssh.Session, r io.Reader, remotePath string, permissions string, size int64) {
        filename := path.Base(remotePath)
        directory := path.Dir(remotePath)

        go func() {
                w, _ := session.StdinPipe()
                defer w.Close()
                fmt.Fprintln(w, "C"+permissions, size, filename)
                io.Copy(w, r)
                fmt.Fprintln(w, "\x00")
        }()

        session.Run("scp -t " + directory)
}
practice commented 6 years ago

참고

https://github.com/bramvdbogaerde/go-scp

http://blog.ralch.com/tutorial/golang-ssh-connection/