From df1b4d2fcd21fb05d2ac65176e2a4243c201a920 Mon Sep 17 00:00:00 2001 From: Fazlul Shahriar Date: Tue, 27 Mar 2012 14:40:42 -0400 Subject: [PATCH] go.crypto/ssh: fix example in documentation R=golang-dev, dave CC=golang-dev https://golang.org/cl/5905048 --- ssh/client_auth_test.go | 2 +- ssh/doc.go | 113 ------------------------------------- ssh/example_test.go | 121 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 114 deletions(-) create mode 100644 ssh/example_test.go diff --git a/ssh/client_auth_test.go b/ssh/client_auth_test.go index 0df51c3..c1c57ba 100644 --- a/ssh/client_auth_test.go +++ b/ssh/client_auth_test.go @@ -58,7 +58,7 @@ y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== -----END RSA PRIVATE KEY-----` -// keychain implements the ClientPublickey interface +// keychain implements the ClientKeyring interface type keychain struct { keys []interface{} } diff --git a/ssh/doc.go b/ssh/doc.go index e7deb5e..8880656 100644 --- a/ssh/doc.go +++ b/ssh/doc.go @@ -10,118 +10,5 @@ family of application protocols. The most typical application level protocol is a remote shell and this is specifically implemented. However, the multiplexed nature of SSH is exposed to users that wish to support others. - -An SSH server is represented by a ServerConfig, which holds certificate -details and handles authentication of ServerConns. - - config := new(ssh.ServerConfig) - config.PubKeyCallback = pubKeyAuth - config.PasswordCallback = passwordAuth - - pemBytes, err := ioutil.ReadFile("id_rsa") - if err != nil { - panic("Failed to load private key") - } - err = config.SetRSAPrivateKey(pemBytes) - if err != nil { - panic("Failed to parse private key") - } - -Once a ServerConfig has been configured, connections can be accepted. - - listener := Listen("tcp", "0.0.0.0:2022", config) - sConn, err := listener.Accept() - if err != nil { - panic("failed to accept incoming connection") - } - if err := sConn.Handshake(conn); err != nil { - panic("failed to handshake") - } - -An SSH connection multiplexes several channels, which must be accepted themselves: - - for { - channel, err := sConn.Accept() - if err != nil { - panic("error from Accept") - } - - ... - } - -Accept reads from the connection, demultiplexes packets to their corresponding -channels and returns when a new channel request is seen. Some goroutine must -always be calling Accept; otherwise no messages will be forwarded to the -channels. - -Channels have a type, depending on the application level protocol intended. In -the case of a shell, the type is "session" and ServerShell may be used to -present a simple terminal interface. - - if channel.ChannelType() != "session" { - channel.Reject(UnknownChannelType, "unknown channel type") - return - } - channel.Accept() - - term := terminal.NewTerminal(channel, "> ") - serverTerm := &ssh.ServerTerminal{ - Term: term, - Channel: channel, - } - go func() { - defer channel.Close() - for { - line, err := serverTerm.ReadLine() - if err != nil { - break - } - println(line) - } - return - }() - -To authenticate with the remote server you must pass at least one implementation of -ClientAuth via the Auth field in ClientConfig. - - // password implements the ClientPassword interface - type password string - - func (p password) Password(user string) (string, error) { - return string(p), nil - } - - config := &ssh.ClientConfig { - User: "username", - Auth: []ClientAuth { - // ClientAuthPassword wraps a ClientPassword implementation - // in a type that implements ClientAuth. - ClientAuthPassword(password("yourpassword")), - } - } - -An SSH client is represented with a ClientConn. Currently only the "password" -authentication method is supported. - - config := &ClientConfig{ - User: "username", - Auth: []ClientAuth{ ... }, - } - client, err := Dial("yourserver.com:22", config) - -Each ClientConn can support multiple interactive sessions, represented by a Session. - - session, err := client.NewSession() - -Once a Session is created, you can execute a single command on the remote side -using the Exec method. - - b := bytes.NewBuffer() - session.Stdin = b - if err := session.Run("/usr/bin/whoami"); err != nil { - panic("Failed to exec: " + err.String()) - } - fmt.Println(bytes.String()) - session.Close() */ package ssh diff --git a/ssh/example_test.go b/ssh/example_test.go new file mode 100644 index 0000000..2ee9fd8 --- /dev/null +++ b/ssh/example_test.go @@ -0,0 +1,121 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "exp/terminal" + "fmt" + "io/ioutil" +) + +func ExampleListen() { + // An SSH server is represented by a ServerConfig, which holds + // certificate details and handles authentication of ServerConns. + config := &ServerConfig{ + PasswordCallback: func(conn *ServerConn, user, pass string) bool { + return user == "testuser" && pass == "tiger" + }, + } + + pemBytes, err := ioutil.ReadFile("id_rsa") + if err != nil { + panic("Failed to load private key") + } + if err = config.SetRSAPrivateKey(pemBytes); err != nil { + panic("Failed to parse private key") + } + + // Once a ServerConfig has been configured, connections can be + // accepted. + listener, err := Listen("tcp", "0.0.0.0:2022", config) + if err != nil { + panic("failed to listen for connection") + } + sConn, err := listener.Accept() + if err != nil { + panic("failed to accept incoming connection") + } + if err := sConn.Handshake(); err != nil { + panic("failed to handshake") + } + + // A ServerConn multiplexes several channels, which must + // themselves be Accepted. + for { + // Accept reads from the connection, demultiplexes packets + // to their corresponding channels and returns when a new + // channel request is seen. Some goroutine must always be + // calling Accept; otherwise no messages will be forwarded + // to the channels. + channel, err := sConn.Accept() + if err != nil { + panic("error from Accept") + } + + // Channels have a type, depending on the application level + // protocol intended. In the case of a shell, the type is + // "session" and ServerShell may be used to present a simple + // terminal interface. + if channel.ChannelType() != "session" { + channel.Reject(UnknownChannelType, "unknown channel type") + continue + } + channel.Accept() + + term := terminal.NewTerminal(channel, "> ") + serverTerm := &ServerTerminal{ + Term: term, + Channel: channel, + } + go func() { + defer channel.Close() + for { + line, err := serverTerm.ReadLine() + if err != nil { + break + } + fmt.Println(line) + } + }() + } +} + +func ExampleDial() { + // An SSH client is represented with a ClientConn. Currently only + // the "password" authentication method is supported. + // + // To authenticate with the remote server you must pass at least one + // implementation of ClientAuth via the Auth field in ClientConfig. + config := &ClientConfig{ + User: "username", + Auth: []ClientAuth{ + // ClientAuthPassword wraps a ClientPassword implementation + // in a type that implements ClientAuth. + ClientAuthPassword(password("yourpassword")), + }, + } + client, err := Dial("tcp", "yourserver.com:22", config) + if err != nil { + panic("Failed to dial: " + err.Error()) + } + + // Each ClientConn can support multiple interactive sessions, + // represented by a Session. + session, err := client.NewSession() + if err != nil { + panic("Failed to create session: " + err.Error()) + } + defer session.Close() + + // Once a Session is created, you can execute a single command on + // the remote side using the Run method. + var b bytes.Buffer + session.Stdout = &b + if err := session.Run("/usr/bin/whoami"); err != nil { + panic("Failed to run: " + err.Error()) + } + fmt.Println(b.String()) +}