mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-05 20:31:59 +00:00
ssh/tailssh: try out new AuthBanner API
Uses https://go-review.googlesource.com/c/crypto/+/613856 DO NOT MERGE Change-Id: I0083fe34015e2ba39374ee58deae68c112b24750 Signed-off-by: Percy Wegmann <percy@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
49de23cf1b
commit
487470ea47
@@ -7,7 +7,7 @@ import (
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// contextKey is a value for use with context.WithValue. It's used as
|
||||
@@ -121,7 +121,6 @@ func applyConnMetadata(ctx Context, conn gossh.ConnMetadata) {
|
||||
ctx.SetValue(ContextKeyUser, conn.User())
|
||||
ctx.SetValue(ContextKeyLocalAddr, conn.LocalAddr())
|
||||
ctx.SetValue(ContextKeyRemoteAddr, conn.RemoteAddr())
|
||||
ctx.SetValue(ContextKeySendAuthBanner, conn.SendAuthBanner)
|
||||
}
|
||||
|
||||
func (ctx *sshContext) SetValue(key, value interface{}) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package ssh
|
||||
import (
|
||||
"os"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// PasswordAuth returns a functional option that sets PasswordHandler on the server.
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func newTestSessionWithOptions(t *testing.T, srv *Server, cfg *gossh.ClientConfig, options ...Option) (*gossh.Session, *gossh.Client, func()) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// ErrServerClosed is returned by the Server's Serve, ListenAndServe,
|
||||
@@ -134,45 +134,97 @@ func (srv *Server) config(ctx Context) *gossh.ServerConfig {
|
||||
config.ServerVersion = "SSH-2.0-" + srv.Version
|
||||
}
|
||||
if srv.PasswordHandler != nil {
|
||||
config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if ok := srv.PasswordHandler(ctx, string(password)); !ok {
|
||||
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
|
||||
}
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
config.PasswordCallback = passwordCallback(ctx, srv.PasswordHandler)
|
||||
}
|
||||
if srv.PublicKeyHandler != nil {
|
||||
config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if err := srv.PublicKeyHandler(ctx, key); err != nil {
|
||||
return ctx.Permissions().Permissions, err
|
||||
}
|
||||
ctx.SetValue(ContextKeyPublicKey, key)
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
config.PublicKeyCallback = publicKeyCallback(ctx, srv.PublicKeyHandler)
|
||||
}
|
||||
if srv.KeyboardInteractiveHandler != nil {
|
||||
config.KeyboardInteractiveCallback = func(conn gossh.ConnMetadata, challenger gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if ok := srv.KeyboardInteractiveHandler(ctx, challenger); !ok {
|
||||
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
|
||||
}
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
config.KeyboardInteractiveCallback = keyboardInteractiveCallback(ctx, srv.KeyboardInteractiveHandler)
|
||||
}
|
||||
if srv.NoClientAuthHandler != nil {
|
||||
config.NoClientAuthCallback = func(conn gossh.ConnMetadata) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if err := srv.NoClientAuthHandler(ctx); err != nil {
|
||||
return ctx.Permissions().Permissions, err
|
||||
}
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
config.NoClientAuthCallback = noClientAuthCallback(ctx, srv.NoClientAuthHandler)
|
||||
}
|
||||
config.PreAuthConnCallback = func(pac gossh.ServerPreAuthConn) {
|
||||
ctx.SetValue(ContextKeySendAuthBanner, pac.SendAuthBanner)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func passwordCallback(ctx Context, h PasswordHandler) func(gossh.ConnMetadata, []byte) (*gossh.Permissions, error) {
|
||||
return func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if ok := h(ctx, string(password)); !ok {
|
||||
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
|
||||
}
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
}
|
||||
|
||||
func publicKeyCallback(ctx Context, h PublicKeyHandler) func(gossh.ConnMetadata, gossh.PublicKey) (*gossh.Permissions, error) {
|
||||
return func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if err := h(ctx, key); err != nil {
|
||||
return ctx.Permissions().Permissions, adaptPartialSuccessError(err)
|
||||
}
|
||||
ctx.SetValue(ContextKeyPublicKey, key)
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
}
|
||||
|
||||
func keyboardInteractiveCallback(ctx Context, h KeyboardInteractiveHandler) func(conn gossh.ConnMetadata, client gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
|
||||
return func(conn gossh.ConnMetadata, challenger gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if ok := h(ctx, challenger); !ok {
|
||||
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
|
||||
}
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
}
|
||||
|
||||
func noClientAuthCallback(ctx Context, h NoClientAuthHandler) func(gossh.ConnMetadata) (*gossh.Permissions, error) {
|
||||
return func(conn gossh.ConnMetadata) (*gossh.Permissions, error) {
|
||||
applyConnMetadata(ctx, conn)
|
||||
if err := h(ctx); err != nil {
|
||||
return ctx.Permissions().Permissions, adaptPartialSuccessError(err)
|
||||
}
|
||||
return ctx.Permissions().Permissions, nil
|
||||
}
|
||||
}
|
||||
|
||||
func adaptPartialSuccessError(err error) error {
|
||||
fmt.Printf("Adapt? error %q of type %T\n", err, err)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
pse := &PartialSuccessError{}
|
||||
if errors.As(err, &pse) {
|
||||
adapted := &gossh.PartialSuccessError{}
|
||||
if pse.PasswordHandler != nil {
|
||||
adapted.Next.PasswordCallback = passwordCallback(pse.Context, pse.PasswordHandler)
|
||||
}
|
||||
if pse.PublicKeyHandler != nil {
|
||||
adapted.Next.PublicKeyCallback = publicKeyCallback(pse.Context, pse.PublicKeyHandler)
|
||||
}
|
||||
if pse.KeyboardInteractiveHandler != nil {
|
||||
adapted.Next.KeyboardInteractiveCallback = keyboardInteractiveCallback(pse.Context, pse.KeyboardInteractiveHandler)
|
||||
}
|
||||
return adapted
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type PartialSuccessError struct {
|
||||
Context Context
|
||||
PasswordHandler PasswordHandler
|
||||
PublicKeyHandler PublicKeyHandler
|
||||
KeyboardInteractiveHandler KeyboardInteractiveHandler
|
||||
}
|
||||
|
||||
func (p *PartialSuccessError) Error() string {
|
||||
return "ssh: authenticated with partial success"
|
||||
}
|
||||
|
||||
// Handle sets the Handler for the server.
|
||||
func (srv *Server) Handle(fn Handler) {
|
||||
srv.mu.Lock()
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/anmitsu/go-shlex"
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// Session provides access to information about an SSH session and methods
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func (srv *Server) serveOnce(l net.Listener) error {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"crypto/subtle"
|
||||
"net"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type Signal string
|
||||
@@ -105,7 +105,7 @@ type Pty struct {
|
||||
// requested by the client as part of the pty-req. These are outlined as
|
||||
// part of https://datatracker.ietf.org/doc/html/rfc4254#section-8.
|
||||
//
|
||||
// The opcodes are defined as constants in github.com/tailscale/golang-x-crypto/ssh (VINTR,VQUIT,etc.).
|
||||
// The opcodes are defined as constants in golang.org/x/crypto/ssh (VINTR,VQUIT,etc.).
|
||||
// Boolean opcodes have values 0 or 1.
|
||||
Modes gossh.TerminalModes
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
var sampleServerResponse = []byte("Hello world")
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"crypto/rsa"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/tailscale/golang-x-crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func generateSigner() (ssh.Signer, error) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package ssh
|
||||
|
||||
import gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
import gossh "golang.org/x/crypto/ssh"
|
||||
|
||||
// PublicKey is an abstraction of different types of public keys.
|
||||
type PublicKey interface {
|
||||
|
||||
Reference in New Issue
Block a user