Skip to content

Commit

Permalink
Fixes ContainerSSH/ContainerSSH#331: Add SSH certificate information …
Browse files Browse the repository at this point in the history
…to webhook.
  • Loading branch information
Janos Bonic committed Dec 26, 2021
1 parent c925d96 commit 0e1f107
Show file tree
Hide file tree
Showing 26 changed files with 89 additions and 83 deletions.
28 changes: 28 additions & 0 deletions auth/protocol.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package auth

import "time"

// PasswordAuthRequest is an authentication request for password authentication.
//
// swagger:model PasswordAuthRequest
Expand Down Expand Up @@ -58,6 +60,13 @@ type PublicKeyAuthRequest struct {
//
// required: true
PublicKey string `json:"publicKey"`

// CACertificate contains information about the SSH certificate presented by a connecting client. This certificate
// is not an SSL/TLS/x509 certificate and has a much simpler structure. However, this can be used to verify if the
// connecting client belongs to an organization.
//
// required: false
CACertificate CACertificate `json:"caCertificate,omitempty"`
}

// ResponseBody is a response to authentication requests.
Expand Down Expand Up @@ -85,3 +94,22 @@ type Response struct {
// in: body
ResponseBody
}

// CACertificate contains information about the SSH certificate presented by a connecting client. This certificate
// is not an SSL/TLS/x509 certificate and has a much simpler structure. However, this can be used to verify if the
// connecting client belongs to an organization.
//
// swagger:model CACertificate
type CACertificate struct {
// PublicKey contains the public key of the CA signing the public key presented in the OpenSSH authorized key
// format.
PublicKey string `json:"key"`
// KeyID contains an identifier for the key.
KeyID string `json:"keyID"`
// ValidPrincipals contains a list of principals for which this CA certificate is valid.
ValidPrincipals []string `json:"validPrincipals"`
// ValidAfter contains the time after which this certificate is valid. This may be empty.
ValidAfter *time.Time `json:"validAfter,omitempty"`
// ValidBefore contains the time when this certificate expires. This may be empty.
ValidBefore *time.Time `json:"validBefore,omitempty"`
}
14 changes: 13 additions & 1 deletion auth/webhook/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,22 @@ type Client interface {

// PubKey authenticates with a public key from the client. It returns a bool if the authentication as successful
// or not. If an error happened while contacting the authentication server it will return an error.
//
// The parameters are as follows:
//
// - username is the username provided by the connecting client.
// - pubKey is the public key offered by the connecting client. The client may offer multiple keys which will be
// presented by calling this function multiple times.
// - connectionID is an opaque random string representing this SSH connection across multiple webhooks and logs.
// - remoteAddr is the IP address of the connecting client.
// - caPubKey is the verified public key of the SSH CA certificate offered by the client. If no CA certificate
// was offered this string is empty.
PubKey(
username string,
pubKey string,
connectionID string,
remoteAddr net.IP,
caPubKey string,
) AuthenticationContext
}

Expand Down Expand Up @@ -79,6 +90,7 @@ func (a authClientWrapper) PubKey(
pubKey string,
connectionID string,
remoteAddr net.IP,
caPubKey string,
) AuthenticationContext {
return a.c.PubKey(username, pubKey, connectionID, remoteAddr)
return a.c.PubKey(username, pubKey, connectionID, remoteAddr, caPubKey)
}
2 changes: 1 addition & 1 deletion internal/auditlog/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type Connection interface {
OnAuthPasswordBackendError(username string, password []byte, reason string)

// OnAuthPubKey creates an audit log message for an authentication attempt with public key.
OnAuthPubKey(username string, pubKey string)
OnAuthPubKey(username string, pubKey string, caKey string)
// OnAuthPubKeySuccess creates an audit log message for a successful public key authentication.
OnAuthPubKeySuccess(username string, pubKey string)
// OnAuthPubKeyFailed creates an audit log message for a failed public key authentication.
Expand Down
2 changes: 1 addition & 1 deletion internal/auditlog/logger_empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (e *empty) OnAuthPasswordFailed(_ string, _ []byte) {}

func (e *empty) OnAuthPasswordBackendError(_ string, _ []byte, _ string) {}

func (e *empty) OnAuthPubKey(_ string, _ string) {}
func (e *empty) OnAuthPubKey(username string, pubKey string, caKey string) {}

func (e *empty) OnAuthPubKeySuccess(_ string, _ string) {}

Expand Down
2 changes: 1 addition & 1 deletion internal/auditlog/logger_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (l *loggerConnection) OnAuthPasswordBackendError(username string, password
})
}

func (l *loggerConnection) OnAuthPubKey(username string, pubKey string) {
func (l *loggerConnection) OnAuthPubKey(username string, pubKey string, caKey string) {
l.log(message.Message{
ConnectionID: l.connectionID,
Timestamp: time.Now().UnixNano(),
Expand Down
6 changes: 3 additions & 3 deletions internal/auditlog/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,11 @@ func TestAuth(t *testing.T) {
connection.OnAuthPasswordFailed("foo", []byte("bar"))
connection.OnAuthPassword("foo", []byte("baz"))
connection.OnAuthPasswordSuccess("foo", []byte("baz"))
connection.OnAuthPubKey("foo", "ssh-rsa ASDF")
connection.OnAuthPubKey("foo", "ssh-rsa ASDF", "")
connection.OnAuthPubKeyBackendError("foo", "ssh-rsa ASDF", "no particular reason")
connection.OnAuthPubKey("foo", "ssh-rsa ASDF")
connection.OnAuthPubKey("foo", "ssh-rsa ASDF", "")
connection.OnAuthPubKeyFailed("foo", "ssh-rsa ASDF")
connection.OnAuthPubKey("foo", "ssh-rsa ABCDEF")
connection.OnAuthPubKey("foo", "ssh-rsa ABCDEF", "")
connection.OnAuthPubKeySuccess("foo", "ssh-rsa ABCDEF")
connection.OnHandshakeSuccessful("foo")
connection.OnDisconnect()
Expand Down
14 changes: 3 additions & 11 deletions internal/auditlogintegration/handler_networkconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,9 @@ func (n *networkConnectionHandler) OnAuthPassword(
return response, metadata, reason
}

func (n *networkConnectionHandler) OnAuthPubKey(
username string,
pubKey string,
clientVersion string,
) (
response sshserver.AuthResponse,
metadata map[string]string,
reason error,
) {
n.audit.OnAuthPubKey(username, pubKey)
response, metadata, reason = n.backend.OnAuthPubKey(username, pubKey, clientVersion)
func (n *networkConnectionHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
n.audit.OnAuthPubKey(username, pubKey, caKey)
response, metadata, reason = n.backend.OnAuthPubKey(username, pubKey, clientVersion, caKey)
switch response {
case sshserver.AuthResponseSuccess:
n.audit.OnAuthPubKeySuccess(username, pubKey)
Expand Down
6 changes: 1 addition & 5 deletions internal/auditlogintegration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,7 @@ func (b *backendHandler) OnAuthPassword(username string, _ []byte, _ string) (
return sshserver.AuthResponseFailure, nil, nil
}

func (b *backendHandler) OnAuthPubKey(_ string, _ string, _ string) (
response sshserver.AuthResponse,
metadata map[string]string,
reason error,
) {
func (b *backendHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
return sshserver.AuthResponseFailure, nil, nil
}

Expand Down
11 changes: 4 additions & 7 deletions internal/auth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package auth

import (
"net"

"github.com/containerssh/libcontainerssh/ssh"
)

// AuthenticationContext holds the results of an authentication.
Expand Down Expand Up @@ -33,12 +35,7 @@ type Client interface {

// PubKey authenticates with a public key from the client. It returns a bool if the authentication as successful
// or not. If an error happened while contacting the authentication server it will return an error.
PubKey(
username string,
pubKey string,
connectionID string,
remoteAddr net.IP,
) AuthenticationContext
PubKey(username string, pubKey string, connectionID string, remoteAddr net.IP, caPubKey ssh.CACertificate) AuthenticationContext

// KeyboardInteractive is a method to post a series of questions to the user and receive answers.
KeyboardInteractive(
Expand Down Expand Up @@ -69,4 +66,4 @@ type KeyboardInteractiveQuestion struct {
type KeyboardInteractiveAnswers struct {
// KeyboardInteractiveQuestion is the original question that was answered.
Answers map[string]string
}
}
8 changes: 2 additions & 6 deletions internal/auth/client_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,7 @@ func (client *httpAuthClient) Password(
return client.processAuthWithRetry(username, method, authType, connectionID, url, authRequest, remoteAddr)
}

func (client *httpAuthClient) PubKey(
username string,
pubKey string,
connectionID string,
remoteAddr net.IP,
) AuthenticationContext {
func (client *httpAuthClient) PubKey(username string, pubKey string, connectionID string, remoteAddr net.IP, caPubKey interface{}) AuthenticationContext {
if !client.enablePubKey {
err := message.UserMessage(
message.EAuthDisabled,
Expand All @@ -117,6 +112,7 @@ func (client *httpAuthClient) PubKey(
ConnectionID: connectionID,
SessionID: connectionID,
PublicKey: pubKey,
CAPublicKey: caPubKey,
}
method := "Public key"
authType := "pubkey"
Expand Down
3 changes: 2 additions & 1 deletion internal/auth/client_oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/containerssh/libcontainerssh/log"
"github.com/containerssh/libcontainerssh/message"
"github.com/containerssh/libcontainerssh/ssh"
)

type oauth2Client struct {
Expand Down Expand Up @@ -48,7 +49,7 @@ func (o *oauth2Client) Password(_ string, _ []byte, _ string, _ net.IP) Authenti
), nil}
}

func (o *oauth2Client) PubKey(_ string, _ string, _ string, _ net.IP) AuthenticationContext {
func (o *oauth2Client) PubKey(username string, pubKey string, connectionID string, remoteAddr net.IP, caPubKey ssh.CACertificate) AuthenticationContext {
return &oauth2Context{false, nil, message.UserMessage(
message.EAuthUnsupported,
"Public key authentication is not available.",
Expand Down
7 changes: 1 addition & 6 deletions internal/auth/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,7 @@ func TestPubKeyDisabled(t *testing.T) {
if err != nil {
t.Fatal(err)
}
authContext := c.PubKey(
"foo",
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDP39LqSomHi4kicGADA3XVQoYxzNkvrBLOqN5AEEP01p0TZ39LXa6FdB4Pmvg8h51c+BNLoxpYrTk4UibMD87OPKYYXrNmLvq0GwjMPYpzoICevAJm+/2sDVlK9sXT93Fkin+tei+Evgf/hQK0xN+HXqP8dz8SWSXeWjBv588eHHCdrV+0FlZLXH+9D18tD4BNPHe9iJLpeeH6gsvQBvArXcIEQVvHIo1cCcsy28ymUFndG55LdOaTCA+pcfHLmRtL8HO2mI2Qc/0HBSc2d1gb3lHAnmdMT82K58OjRp9Tegc5hVuKVE+hkmNjfo3f1mVHsNu6JYLxRngnbJ20QdzuKcPb3pRMty+ggRgEQExvgl1pC3OVcgyc8YX1eXiyhYy0kXT/Jg++AcaIC1Xk/hDfB0T7WxCO0Wwd4KSjKr79tIxM/m4jP2K1Hk4yAnT7mZQ0GjdphLLuDk3yt8R809SPuzkPCXBM0sL6FrqT2GVDNihN2pBh1MyuUt7S8ZXpuW0=",
"asdf",
net.ParseIP("127.0.0.1"),
)
authContext := c.PubKey("foo", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDP39LqSomHi4kicGADA3XVQoYxzNkvrBLOqN5AEEP01p0TZ39LXa6FdB4Pmvg8h51c+BNLoxpYrTk4UibMD87OPKYYXrNmLvq0GwjMPYpzoICevAJm+/2sDVlK9sXT93Fkin+tei+Evgf/hQK0xN+HXqP8dz8SWSXeWjBv588eHHCdrV+0FlZLXH+9D18tD4BNPHe9iJLpeeH6gsvQBvArXcIEQVvHIo1cCcsy28ymUFndG55LdOaTCA+pcfHLmRtL8HO2mI2Qc/0HBSc2d1gb3lHAnmdMT82K58OjRp9Tegc5hVuKVE+hkmNjfo3f1mVHsNu6JYLxRngnbJ20QdzuKcPb3pRMty+ggRgEQExvgl1pC3OVcgyc8YX1eXiyhYy0kXT/Jg++AcaIC1Xk/hDfB0T7WxCO0Wwd4KSjKr79tIxM/m4jP2K1Hk4yAnT7mZQ0GjdphLLuDk3yt8R809SPuzkPCXBM0sL6FrqT2GVDNihN2pBh1MyuUt7S8ZXpuW0=", "asdf", net.ParseIP("127.0.0.1"), "")
if authContext.Success() {
t.Fatal("Public key authentication method resulted in successful authentication.")
}
Expand Down
6 changes: 3 additions & 3 deletions internal/auth/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ func TestAuth(t *testing.T) {
assert.Equal(t, false, authenticationContext.Success())
assert.Equal(t, float64(1), metricsCollector.GetMetric(auth.MetricNameAuthBackendFailure)[0].Value)

authenticationContext = client.PubKey("foo", "ssh-rsa asdf", "0123456789ABCDEF", net.ParseIP("127.0.0.1"))
authenticationContext = client.PubKey("foo", "ssh-rsa asdf", "0123456789ABCDEF", net.ParseIP("127.0.0.1"), "")
assert.Equal(t, nil, authenticationContext.Error())
assert.Equal(t, true, authenticationContext.Success())

authenticationContext = client.PubKey("foo", "ssh-rsa asdx", "0123456789ABCDEF", net.ParseIP("127.0.0.1"))
authenticationContext = client.PubKey("foo", "ssh-rsa asdx", "0123456789ABCDEF", net.ParseIP("127.0.0.1"), "")
assert.Equal(t, nil, authenticationContext.Error())
assert.Equal(t, false, authenticationContext.Success())

authenticationContext = client.PubKey("crash", "ssh-rsa asdx", "0123456789ABCDEF", net.ParseIP("127.0.0.1"))
authenticationContext = client.PubKey("crash", "ssh-rsa asdx", "0123456789ABCDEF", net.ParseIP("127.0.0.1"), "")
assert.NotEqual(t, nil, authenticationContext.Error())
assert.Equal(t, false, authenticationContext.Success())
})
Expand Down
10 changes: 5 additions & 5 deletions internal/authintegration/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,26 +113,26 @@ func (h *networkConnectionHandler) OnAuthPassword(username string, password []by
}
}

func (h *networkConnectionHandler) OnAuthPubKey(username string, pubKey string, clientVersion string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
func (h *networkConnectionHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
if h.authContext != nil {
h.authContext.OnDisconnect()
}
authContext := h.authClient.PubKey(username, pubKey, h.connectionID, h.ip)
authContext := h.authClient.PubKey(username, pubKey, h.connectionID, h.ip, caKey)
h.authContext = authContext
if !authContext.Success() {
if authContext.Error() != nil {
if h.behavior == BehaviorPassthroughOnUnavailable {
return h.backend.OnAuthPubKey(username, pubKey, clientVersion)
return h.backend.OnAuthPubKey(username, pubKey, clientVersion, caKey)
}
return sshserver.AuthResponseUnavailable, authContext.Metadata(), authContext.Error()
}
if h.behavior == BehaviorPassthroughOnFailure {
return h.backend.OnAuthPubKey(username, pubKey, clientVersion)
return h.backend.OnAuthPubKey(username, pubKey, clientVersion, caKey)
}
return sshserver.AuthResponseFailure, authContext.Metadata(), authContext.Error()
}
if h.behavior == BehaviorPassthroughOnSuccess {
return h.backend.OnAuthPubKey(username, pubKey, clientVersion)
return h.backend.OnAuthPubKey(username, pubKey, clientVersion, caKey)
}
return sshserver.AuthResponseSuccess, authContext.Metadata(), authContext.Error()
}
Expand Down
2 changes: 1 addition & 1 deletion internal/backend/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (n *networkHandler) authResponse() (sshserver.AuthResponse, map[string]stri
}
}

func (n *networkHandler) OnAuthPubKey(_ string, _ string, _ string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
func (n *networkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
return n.authResponse()
}

Expand Down
2 changes: 1 addition & 1 deletion internal/docker/handler_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (n *networkHandler) OnAuthPassword(_ string, _ []byte, _ string) (sshserver
return sshserver.AuthResponseUnavailable, nil, fmt.Errorf("docker does not support authentication")
}

func (n *networkHandler) OnAuthPubKey(_ string, _ string, _ string) (sshserver.AuthResponse, map[string]string, error) {
func (n *networkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (sshserver.AuthResponse, map[string]string, error) {
return sshserver.AuthResponseUnavailable, nil, fmt.Errorf("docker does not support authentication")
}

Expand Down
2 changes: 1 addition & 1 deletion internal/kubernetes/networkHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (n *networkHandler) OnAuthPassword(_ string, _ []byte, _ string) (response
return sshserver.AuthResponseUnavailable, nil, fmt.Errorf("the backend handler does not support authentication")
}

func (n *networkHandler) OnAuthPubKey(_ string, _ string, _ string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
func (n *networkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
return sshserver.AuthResponseUnavailable, nil, fmt.Errorf("the backend handler does not support authentication")
}

Expand Down
8 changes: 2 additions & 6 deletions internal/metricsintegration/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,8 @@ func (m *metricsNetworkHandler) OnAuthPassword(username string, password []byte,
return m.backend.OnAuthPassword(username, password, clientVersion)
}

func (m *metricsNetworkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string) (
response sshserver.AuthResponse,
metadata map[string]string,
reason error,
) {
return m.backend.OnAuthPubKey(username, pubKey, clientVersion)
func (m *metricsNetworkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
return m.backend.OnAuthPubKey(username, pubKey, clientVersion, "")
}

func (m *metricsNetworkHandler) OnAuthKeyboardInteractive(
Expand Down
6 changes: 1 addition & 5 deletions internal/metricsintegration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,7 @@ func (d *dummyBackendHandler) OnAuthPassword(_ string, _ []byte, _ string) (
return d.authResponse, nil, nil
}

func (d *dummyBackendHandler) OnAuthPubKey(_ string, _ string, _ string) (
response sshserver.AuthResponse,
metadata map[string]string,
reason error,
) {
func (d *dummyBackendHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
return d.authResponse, nil, nil
}

Expand Down
8 changes: 2 additions & 6 deletions internal/security/handler_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,8 @@ func (n *networkHandler) OnAuthPassword(username string, password []byte, client
return n.backend.OnAuthPassword(username, password, clientVersion)
}

func (n *networkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string) (
response sshserver.AuthResponse,
metadata map[string]string,
reason error,
) {
return n.backend.OnAuthPubKey(username, pubKey, clientVersion)
func (n *networkHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
return n.backend.OnAuthPubKey(username, pubKey, clientVersion, "")
}

func (n *networkHandler) OnHandshakeFailed(reason error) {
Expand Down
6 changes: 1 addition & 5 deletions internal/sshproxy/networkConnectionHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@ func (s *networkConnectionHandler) OnAuthPassword(_ string, _ []byte, _ string)
)
}

func (s *networkConnectionHandler) OnAuthPubKey(_ string, _ string, _ string) (
sshserver.AuthResponse,
map[string]string,
error,
) {
func (s *networkConnectionHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (sshserver.AuthResponse, map[string]string, error) {
return sshserver.AuthResponseUnavailable, nil, fmt.Errorf(
"ssh proxy does not support authentication",
)
Expand Down
2 changes: 1 addition & 1 deletion internal/sshserver/AbstractNetworkConnectionHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (a *AbstractNetworkConnectionHandler) OnAuthPassword(_ string, _ []byte, _
// OnAuthPassword is called when a user attempts a pubkey authentication. The implementation must always supply
// AuthResponse and may supply error as a reason description. The pubKey parameter is an SSH key in
// the form of "ssh-rsa KEY HERE".
func (a *AbstractNetworkConnectionHandler) OnAuthPubKey(_ string, _ string, _ string) (response AuthResponse, metadata map[string]string, reason error) {
func (a *AbstractNetworkConnectionHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response AuthResponse, metadata map[string]string, reason error) {
return AuthResponseUnavailable, nil, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/sshserver/Server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ func (f *fullNetworkConnectionHandler) OnAuthPassword(
return sshserver.AuthResponseFailure, nil, fmt.Errorf("authentication failed")
}

func (f *fullNetworkConnectionHandler) OnAuthPubKey(username string, pubKey string, _ string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
func (f *fullNetworkConnectionHandler) OnAuthPubKey(username string, pubKey string, clientVersion string, caKey string) (response sshserver.AuthResponse, metadata map[string]string, reason error) {
if storedPubKey, ok := f.handler.pubKeys[username]; ok && storedPubKey == pubKey {
return sshserver.AuthResponseSuccess, nil, nil
}
Expand Down
Loading

0 comments on commit 0e1f107

Please sign in to comment.