|
|
@@ -17,9 +17,29 @@ import (
|
|
|
)
|
|
|
|
|
|
func ExampleNewServerConn() {
|
|
|
+ // Public key authentication is done by comparing
|
|
|
+ // the public key of a received connection
|
|
|
+ // with the entries in the authorized_keys file.
|
|
|
+ authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("Failed to load authorized_keys, err: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ authorizedKeysMap := map[string]bool{}
|
|
|
+ for len(authorizedKeysBytes) > 0 {
|
|
|
+ pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ authorizedKeysMap[string(pubKey.Marshal())] = true
|
|
|
+ authorizedKeysBytes = rest
|
|
|
+ }
|
|
|
+
|
|
|
// An SSH server is represented by a ServerConfig, which holds
|
|
|
// certificate details and handles authentication of ServerConns.
|
|
|
config := &ssh.ServerConfig{
|
|
|
+ // Remove to disable password auth.
|
|
|
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
|
|
// Should use constant-time compare (or better, salt+hash) in
|
|
|
// a production setting.
|
|
|
@@ -28,6 +48,14 @@ func ExampleNewServerConn() {
|
|
|
}
|
|
|
return nil, fmt.Errorf("password rejected for %q", c.User())
|
|
|
},
|
|
|
+
|
|
|
+ // Remove to disable public key auth.
|
|
|
+ PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
|
|
+ if authorizedKeysMap[string(pubKey.Marshal())] {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ return nil, fmt.Errorf("unknown public key for %q", c.User())
|
|
|
+ },
|
|
|
}
|
|
|
|
|
|
privateBytes, err := ioutil.ReadFile("id_rsa")
|
|
|
@@ -62,6 +90,8 @@ func ExampleNewServerConn() {
|
|
|
// The incoming Request channel must be serviced.
|
|
|
go ssh.DiscardRequests(reqs)
|
|
|
|
|
|
+ // Service the incoming Channel channel.
|
|
|
+
|
|
|
// Service the incoming Channel channel.
|
|
|
for newChannel := range chans {
|
|
|
// Channels have a type, depending on the application level
|
|
|
@@ -74,7 +104,7 @@ func ExampleNewServerConn() {
|
|
|
}
|
|
|
channel, requests, err := newChannel.Accept()
|
|
|
if err != nil {
|
|
|
- log.Fatal("could not accept channel: ", err)
|
|
|
+ log.Fatalf("Could not accept channel: %v", err)
|
|
|
}
|
|
|
|
|
|
// Sessions have out-of-band requests such as "shell",
|
|
|
@@ -82,18 +112,7 @@ func ExampleNewServerConn() {
|
|
|
// "shell" request.
|
|
|
go func(in <-chan *ssh.Request) {
|
|
|
for req := range in {
|
|
|
- ok := false
|
|
|
- switch req.Type {
|
|
|
- case "shell":
|
|
|
- ok = true
|
|
|
- if len(req.Payload) > 0 {
|
|
|
- // We don't accept any
|
|
|
- // commands, only the
|
|
|
- // default shell.
|
|
|
- ok = false
|
|
|
- }
|
|
|
- }
|
|
|
- req.Reply(ok, nil)
|
|
|
+ req.Reply(req.Type == "shell", nil)
|
|
|
}
|
|
|
}(requests)
|
|
|
|