ssh: clarify intended use of Permissions.
The Permissions struct should be used to pass information from
authentication callback to server application.
Fixes golang/go#20094.
Change-Id: I5542b657d053452327260707a24925286546bfdd
Reviewed-on: https://go-review.googlesource.com/45311
Run-TryBot: Han-Wen Nienhuys <hanwen@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/ssh/example_test.go b/ssh/example_test.go
index 618398c..b910c7b 100644
--- a/ssh/example_test.go
+++ b/ssh/example_test.go
@@ -56,7 +56,12 @@
// 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 &ssh.Permissions{
+ // Record the public key used for authentication.
+ Extensions: map[string]string{
+ "pubkey-fp": ssh.FingerprintSHA256(pubKey),
+ },
+ }, nil
}
return nil, fmt.Errorf("unknown public key for %q", c.User())
},
@@ -87,10 +92,12 @@
// Before use, a handshake must be performed on the incoming
// net.Conn.
- _, chans, reqs, err := ssh.NewServerConn(nConn, config)
+ conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
if err != nil {
log.Fatal("failed to handshake: ", err)
}
+ log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
+
// The incoming Request channel must be serviced.
go ssh.DiscardRequests(reqs)
diff --git a/ssh/server.go b/ssh/server.go
index 23b41d9..70d6077 100644
--- a/ssh/server.go
+++ b/ssh/server.go
@@ -14,23 +14,34 @@
)
// The Permissions type holds fine-grained permissions that are
-// specific to a user or a specific authentication method for a
-// user. Permissions, except for "source-address", must be enforced in
-// the server application layer, after successful authentication. The
-// Permissions are passed on in ServerConn so a server implementation
-// can honor them.
+// specific to a user or a specific authentication method for a user.
+// The Permissions value for a successful authentication attempt is
+// available in ServerConn, so it can be used to pass information from
+// the user-authentication phase to the application layer.
type Permissions struct {
- // Critical options restrict default permissions. Common
- // restrictions are "source-address" and "force-command". If
- // the server cannot enforce the restriction, or does not
- // recognize it, the user should not authenticate.
+ // CriticalOptions indicate restrictions to the default
+ // permissions, and are typically used in conjunction with
+ // user certificates. The standard for SSH certificates
+ // defines "force-command" (only allow the given command to
+ // execute) and "source-address" (only allow connections from
+ // the given address). The SSH package currently only enforces
+ // the "source-address" critical option. It is up to server
+ // implementations to enforce other critical options, such as
+ // "force-command", by checking them after the SSH handshake
+ // is successful. In general, SSH servers should reject
+ // connections that specify critical options that are unknown
+ // or not supported.
CriticalOptions map[string]string
// Extensions are extra functionality that the server may
- // offer on authenticated connections. Common extensions are
- // "permit-agent-forwarding", "permit-X11-forwarding". Lack of
- // support for an extension does not preclude authenticating a
- // user.
+ // offer on authenticated connections. Lack of support for an
+ // extension does not preclude authenticating a user. Common
+ // extensions are "permit-agent-forwarding",
+ // "permit-X11-forwarding". The Go SSH library currently does
+ // not act on any extension, and it is up to server
+ // implementations to honor them. Extensions can be used to
+ // pass data from the authentication callbacks to the server
+ // application layer.
Extensions map[string]string
}
@@ -55,9 +66,14 @@
// attempts to authenticate using a password.
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
- // PublicKeyCallback, if non-nil, is called when a client attempts public
- // key authentication. It must return true if the given public key is
- // valid for the given user. For example, see CertChecker.Authenticate.
+ // PublicKeyCallback, if non-nil, is called when a client
+ // offers a public key for authentication. It must return true
+ // if the given public key can be used to authenticate the
+ // given user. For example, see CertChecker.Authenticate. A
+ // call to this function does not guarantee that the key
+ // offered is in fact used to authenticate. To record any data
+ // depending on the public key, store it inside a
+ // Permissions.Extensions entry.
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
// KeyboardInteractiveCallback, if non-nil, is called when