@@ -2,6 +2,7 @@ package ssh
22
33import (
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