Skip to content

Commit c9ca86c

Browse files
committed
Pass public key via auth callback permissions
1 parent 8a2025d commit c9ca86c

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

server.go

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ssh
22

33
import (
44
"context"
5+
"encoding/base64"
56
"errors"
67
"fmt"
78
"net"
@@ -29,6 +30,16 @@ var DefaultChannelHandlers = map[string]ChannelHandler{
2930
"session": DefaultSessionHandler,
3031
}
3132

33+
var permissionsPublicKeyExt = "gliderlabs/ssh.PublicKey"
34+
35+
func ensureNoPKInPermissions(ctx Context) error {
36+
if _, ok := ctx.Permissions().Permissions.Extensions[permissionsPublicKeyExt]; ok {
37+
return errors.New("misconfigured server: public key incorrectly set")
38+
}
39+
40+
return nil
41+
}
42+
3243
// Server defines parameters for running an SSH server. The zero value for
3344
// Server is a valid configuration. When both PasswordHandler and
3445
// PublicKeyHandler are nil, no client authentication is performed.
@@ -149,7 +160,12 @@ func (srv *Server) config(ctx Context) *gossh.ServerConfig {
149160
config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
150161
resetPermissions(ctx)
151162
applyConnMetadata(ctx, conn)
152-
if ok := srv.PasswordHandler(ctx, string(password)); !ok {
163+
err := ensureNoPKInPermissions(ctx)
164+
if err != nil {
165+
return ctx.Permissions().Permissions, err
166+
}
167+
ok := srv.PasswordHandler(ctx, string(password))
168+
if !ok {
153169
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
154170
}
155171
return ctx.Permissions().Permissions, nil
@@ -159,18 +175,31 @@ func (srv *Server) config(ctx Context) *gossh.ServerConfig {
159175
config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
160176
resetPermissions(ctx)
161177
applyConnMetadata(ctx, conn)
162-
if ok := srv.PublicKeyHandler(ctx, key); !ok {
178+
err := ensureNoPKInPermissions(ctx)
179+
if err != nil {
180+
return ctx.Permissions().Permissions, err
181+
}
182+
ok := srv.PublicKeyHandler(ctx, key)
183+
if !ok {
163184
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
164185
}
165-
ctx.SetValue(ContextKeyPublicKey, key)
186+
187+
pkStr := base64.StdEncoding.EncodeToString(key.Marshal())
188+
ctx.Permissions().Permissions.Extensions[permissionsPublicKeyExt] = pkStr
189+
166190
return ctx.Permissions().Permissions, nil
167191
}
168192
}
169193
if srv.KeyboardInteractiveHandler != nil {
170194
config.KeyboardInteractiveCallback = func(conn gossh.ConnMetadata, challenger gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
171195
resetPermissions(ctx)
172196
applyConnMetadata(ctx, conn)
173-
if ok := srv.KeyboardInteractiveHandler(ctx, challenger); !ok {
197+
ok := srv.KeyboardInteractiveHandler(ctx, challenger)
198+
err := ensureNoPKInPermissions(ctx)
199+
if err != nil {
200+
return ctx.Permissions().Permissions, err
201+
}
202+
if !ok {
174203
return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
175204
}
176205
return ctx.Permissions().Permissions, nil
@@ -302,6 +331,30 @@ func (srv *Server) HandleConn(newConn net.Conn) {
302331
return
303332
}
304333

334+
if sshConn.Permissions != nil {
335+
// Now that the connection was authed, if the permissionsPublicKeyExt was
336+
// attached, we need to re-parse it as a public key.
337+
if keyData, ok := sshConn.Permissions.Extensions[permissionsPublicKeyExt]; ok {
338+
decodedData, err := base64.StdEncoding.DecodeString(keyData)
339+
if err != nil {
340+
if srv.ConnectionFailedCallback != nil {
341+
srv.ConnectionFailedCallback(conn, err)
342+
}
343+
return
344+
}
345+
346+
key, err := gossh.ParsePublicKey(decodedData)
347+
if err != nil {
348+
if srv.ConnectionFailedCallback != nil {
349+
srv.ConnectionFailedCallback(conn, err)
350+
}
351+
return
352+
}
353+
354+
ctx.SetValue(ContextKeyPublicKey, key)
355+
}
356+
}
357+
305358
// Additionally, now that the connection was authed, we can take the
306359
// permissions off of the gossh.Conn and re-attach them to the Permissions
307360
// object stored in the Context.

0 commit comments

Comments
 (0)