ssh: add username to sftp auth errors
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
92911bda2b
commit
be2ed1089c
4 changed files with 25 additions and 16 deletions
2
go.mod
2
go.mod
|
@ -187,5 +187,5 @@ replace (
|
||||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20240210102745-f1ffc43f78d2
|
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20240210102745-f1ffc43f78d2
|
||||||
github.com/pkg/sftp => github.com/drakkan/sftp v0.0.0-20240214104840-fbb0b8bdb30c
|
github.com/pkg/sftp => github.com/drakkan/sftp v0.0.0-20240214104840-fbb0b8bdb30c
|
||||||
github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0
|
github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0
|
||||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20240224191538-9f4629f0732c
|
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20240225143451-17f1441a9706
|
||||||
)
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -109,8 +109,8 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0 h1:EW9gIJRmt9lzk66Fhh4S8VEtURA6QHZqGeSRE9Nb2/U=
|
github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0 h1:EW9gIJRmt9lzk66Fhh4S8VEtURA6QHZqGeSRE9Nb2/U=
|
||||||
github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/drakkan/crypto v0.0.0-20240224191538-9f4629f0732c h1:Jwxc0vhD7t484x2GDv8B5WbvrSwxML9V+A8esl7vkh8=
|
github.com/drakkan/crypto v0.0.0-20240225143451-17f1441a9706 h1:udyaktWAkqPhMN9iVkpZ4kxdW7clkq7Ia4etPilRMRk=
|
||||||
github.com/drakkan/crypto v0.0.0-20240224191538-9f4629f0732c/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
github.com/drakkan/crypto v0.0.0-20240225143451-17f1441a9706/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
github.com/drakkan/ftp v0.0.0-20240210102745-f1ffc43f78d2 h1:ufiGMPFBjndWSQOst9FNP11IuMqPblI2NXbpRMUWNhk=
|
github.com/drakkan/ftp v0.0.0-20240210102745-f1ffc43f78d2 h1:ufiGMPFBjndWSQOst9FNP11IuMqPblI2NXbpRMUWNhk=
|
||||||
github.com/drakkan/ftp v0.0.0-20240210102745-f1ffc43f78d2/go.mod h1:4p8lUl4vQ80L598CygL+3IFtm+3nggvvW/palOlViwE=
|
github.com/drakkan/ftp v0.0.0-20240210102745-f1ffc43f78d2/go.mod h1:4p8lUl4vQ80L598CygL+3IFtm+3nggvvW/palOlViwE=
|
||||||
github.com/drakkan/ftpserverlib v0.0.0-20240212100826-a241365cb085 h1:LAKYR9z9USKeyEQK91sRWldmMOjEHLOt2NuLDx+x1UQ=
|
github.com/drakkan/ftpserverlib v0.0.0-20240212100826-a241365cb085 h1:LAKYR9z9USKeyEQK91sRWldmMOjEHLOt2NuLDx+x1UQ=
|
||||||
|
|
|
@ -2227,23 +2227,26 @@ func TestCanReadSymlink(t *testing.T) {
|
||||||
|
|
||||||
func TestAuthenticationErrors(t *testing.T) {
|
func TestAuthenticationErrors(t *testing.T) {
|
||||||
loginMethod := dataprovider.SSHLoginMethodPassword
|
loginMethod := dataprovider.SSHLoginMethodPassword
|
||||||
err := newAuthenticationError(fmt.Errorf("cannot validate credentials: %w", util.NewRecordNotFoundError("not found")), loginMethod)
|
username := "test user"
|
||||||
|
err := newAuthenticationError(fmt.Errorf("cannot validate credentials: %w", util.NewRecordNotFoundError("not found")),
|
||||||
|
loginMethod, username)
|
||||||
assert.ErrorIs(t, err, sftpAuthError)
|
assert.ErrorIs(t, err, sftpAuthError)
|
||||||
assert.ErrorIs(t, err, util.ErrNotFound)
|
assert.ErrorIs(t, err, util.ErrNotFound)
|
||||||
var sftpAuthErr *authenticationError
|
var sftpAuthErr *authenticationError
|
||||||
if assert.ErrorAs(t, err, &sftpAuthErr) {
|
if assert.ErrorAs(t, err, &sftpAuthErr) {
|
||||||
assert.Equal(t, loginMethod, sftpAuthErr.getLoginMethod())
|
assert.Equal(t, loginMethod, sftpAuthErr.getLoginMethod())
|
||||||
|
assert.Equal(t, username, sftpAuthErr.getUsername())
|
||||||
}
|
}
|
||||||
err = newAuthenticationError(fmt.Errorf("cannot validate credentials: %w", fs.ErrPermission), loginMethod)
|
err = newAuthenticationError(fmt.Errorf("cannot validate credentials: %w", fs.ErrPermission), loginMethod, username)
|
||||||
assert.ErrorIs(t, err, sftpAuthError)
|
assert.ErrorIs(t, err, sftpAuthError)
|
||||||
assert.NotErrorIs(t, err, util.ErrNotFound)
|
assert.NotErrorIs(t, err, util.ErrNotFound)
|
||||||
err = newAuthenticationError(fmt.Errorf("cert has wrong type %d", ssh.HostCert), loginMethod)
|
err = newAuthenticationError(fmt.Errorf("cert has wrong type %d", ssh.HostCert), loginMethod, username)
|
||||||
assert.ErrorIs(t, err, sftpAuthError)
|
assert.ErrorIs(t, err, sftpAuthError)
|
||||||
assert.NotErrorIs(t, err, util.ErrNotFound)
|
assert.NotErrorIs(t, err, util.ErrNotFound)
|
||||||
err = newAuthenticationError(errors.New("ssh: certificate signed by unrecognized authority"), loginMethod)
|
err = newAuthenticationError(errors.New("ssh: certificate signed by unrecognized authority"), loginMethod, username)
|
||||||
assert.ErrorIs(t, err, sftpAuthError)
|
assert.ErrorIs(t, err, sftpAuthError)
|
||||||
assert.NotErrorIs(t, err, util.ErrNotFound)
|
assert.NotErrorIs(t, err, util.ErrNotFound)
|
||||||
err = newAuthenticationError(nil, loginMethod)
|
err = newAuthenticationError(nil, loginMethod, username)
|
||||||
assert.ErrorIs(t, err, sftpAuthError)
|
assert.ErrorIs(t, err, sftpAuthError)
|
||||||
assert.NotErrorIs(t, err, util.ErrNotFound)
|
assert.NotErrorIs(t, err, util.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ var (
|
||||||
certs: map[string]bool{},
|
certs: map[string]bool{},
|
||||||
}
|
}
|
||||||
|
|
||||||
sftpAuthError = newAuthenticationError(nil, "")
|
sftpAuthError = newAuthenticationError(nil, "", "")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Binding defines the configuration for a network listener
|
// Binding defines the configuration for a network listener
|
||||||
|
@ -192,6 +192,7 @@ type Configuration struct {
|
||||||
type authenticationError struct {
|
type authenticationError struct {
|
||||||
err error
|
err error
|
||||||
loginMethod string
|
loginMethod string
|
||||||
|
username string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *authenticationError) Error() string {
|
func (e *authenticationError) Error() string {
|
||||||
|
@ -213,8 +214,12 @@ func (e *authenticationError) getLoginMethod() string {
|
||||||
return e.loginMethod
|
return e.loginMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAuthenticationError(err error, loginMethod string) *authenticationError {
|
func (e *authenticationError) getUsername() string {
|
||||||
return &authenticationError{err: err, loginMethod: loginMethod}
|
return e.username
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAuthenticationError(err error, loginMethod, username string) *authenticationError {
|
||||||
|
return &authenticationError{err: err, loginMethod: loginMethod, username: username}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldBind returns true if there is at least a valid binding
|
// ShouldBind returns true if there is at least a valid binding
|
||||||
|
@ -240,7 +245,7 @@ func (c *Configuration) getServerConfig() *ssh.ServerConfig {
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newAuthenticationError(fmt.Errorf("could not validate public key credentials: %w", err),
|
return nil, newAuthenticationError(fmt.Errorf("could not validate public key credentials: %w", err),
|
||||||
dataprovider.SSHLoginMethodPublicKey)
|
dataprovider.SSHLoginMethodPublicKey, conn.User())
|
||||||
}
|
}
|
||||||
|
|
||||||
return sp, nil
|
return sp, nil
|
||||||
|
@ -751,7 +756,8 @@ func discardAllChannels(in <-chan ssh.NewChannel, message, connectionID string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAuthError(ip string, err error) {
|
func checkAuthError(ip string, err error) {
|
||||||
if authErrors, ok := err.(*ssh.ServerAuthError); ok {
|
var authErrors *ssh.ServerAuthError
|
||||||
|
if errors.As(err, &authErrors) {
|
||||||
// check public key auth errors here
|
// check public key auth errors here
|
||||||
for _, err := range authErrors.Errors {
|
for _, err := range authErrors.Errors {
|
||||||
var sftpAuthErr *authenticationError
|
var sftpAuthErr *authenticationError
|
||||||
|
@ -764,7 +770,7 @@ func checkAuthError(ip string, err error) {
|
||||||
logEv = notifier.LogEventTypeLoginNoUser
|
logEv = notifier.LogEventTypeLoginNoUser
|
||||||
}
|
}
|
||||||
common.AddDefenderEvent(ip, common.ProtocolSSH, event)
|
common.AddDefenderEvent(ip, common.ProtocolSSH, event)
|
||||||
plugin.Handler.NotifyLogEvent(logEv, common.ProtocolSSH, "", ip, "", err)
|
plugin.Handler.NotifyLogEvent(logEv, common.ProtocolSSH, sftpAuthErr.getUsername(), ip, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1215,7 +1221,7 @@ func (c *Configuration) validatePasswordCredentials(conn ssh.ConnMetadata, pass
|
||||||
user.Username = conn.User()
|
user.Username = conn.User()
|
||||||
updateLoginMetrics(&user, ipAddr, method, err)
|
updateLoginMetrics(&user, ipAddr, method, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newAuthenticationError(fmt.Errorf("could not validate password credentials: %w", err), method)
|
return nil, newAuthenticationError(fmt.Errorf("could not validate password credentials: %w", err), method, conn.User())
|
||||||
}
|
}
|
||||||
return sshPerm, nil
|
return sshPerm, nil
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1241,7 @@ func (c *Configuration) validateKeyboardInteractiveCredentials(conn ssh.ConnMeta
|
||||||
user.Username = conn.User()
|
user.Username = conn.User()
|
||||||
updateLoginMetrics(&user, ipAddr, method, err)
|
updateLoginMetrics(&user, ipAddr, method, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newAuthenticationError(fmt.Errorf("could not validate keyboard interactive credentials: %w", err), method)
|
return nil, newAuthenticationError(fmt.Errorf("could not validate keyboard interactive credentials: %w", err), method, conn.User())
|
||||||
}
|
}
|
||||||
return sshPerm, nil
|
return sshPerm, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue