diff --git a/dataprovider/bolt.go b/dataprovider/bolt.go index a9b84036..ced30801 100644 --- a/dataprovider/bolt.go +++ b/dataprovider/bolt.go @@ -118,7 +118,7 @@ func (p *BoltProvider) validateAdminAndPass(username, password, ip string) (Admi return admin, err } -func (p *BoltProvider) validateUserAndPubKey(username string, pubKey []byte) (User, string, error) { +func (p *BoltProvider) validateUserAndPubKey(username string, pubKey []byte, isSSHCert bool) (User, string, error) { var user User if len(pubKey) == 0 { return user, "", errors.New("credentials cannot be null or empty") @@ -128,7 +128,7 @@ func (p *BoltProvider) validateUserAndPubKey(username string, pubKey []byte) (Us providerLog(logger.LevelWarn, "error authenticating user %#v: %v", username, err) return user, "", err } - return checkUserAndPubKey(&user, pubKey) + return checkUserAndPubKey(&user, pubKey, isSSHCert) } func (p *BoltProvider) updateAPIKeyLastUse(keyID string) error { diff --git a/dataprovider/dataprovider.go b/dataprovider/dataprovider.go index 97c3a673..57e03130 100644 --- a/dataprovider/dataprovider.go +++ b/dataprovider/dataprovider.go @@ -615,7 +615,7 @@ func HasUsersBaseDir() bool { // Provider defines the interface that data providers must implement. type Provider interface { validateUserAndPass(username, password, ip, protocol string) (User, error) - validateUserAndPubKey(username string, pubKey []byte) (User, string, error) + validateUserAndPubKey(username string, pubKey []byte, isSSHCert bool) (User, string, error) validateUserAndTLSCert(username, protocol string, tlsCert *x509.Certificate) (User, error) updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error updateTransferQuota(username string, uploadSize, downloadSize int64, reset bool) error @@ -1054,30 +1054,30 @@ func CheckUserAndPass(username, password, ip, protocol string) (User, error) { } // CheckUserAndPubKey retrieves the SFTP user with the given username and public key if a match is found or an error -func CheckUserAndPubKey(username string, pubKey []byte, ip, protocol string) (User, string, error) { +func CheckUserAndPubKey(username string, pubKey []byte, ip, protocol string, isSSHCert bool) (User, string, error) { username = config.convertName(username) if plugin.Handler.HasAuthScope(plugin.AuthScopePublicKey) { user, err := doPluginAuth(username, "", pubKey, ip, protocol, nil, plugin.AuthScopePublicKey) if err != nil { return user, "", err } - return checkUserAndPubKey(&user, pubKey) + return checkUserAndPubKey(&user, pubKey, isSSHCert) } if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&2 != 0) { user, err := doExternalAuth(username, "", pubKey, "", ip, protocol, nil) if err != nil { return user, "", err } - return checkUserAndPubKey(&user, pubKey) + return checkUserAndPubKey(&user, pubKey, isSSHCert) } if config.PreLoginHook != "" { user, err := executePreLoginHook(username, SSHLoginMethodPublicKey, ip, protocol) if err != nil { return user, "", err } - return checkUserAndPubKey(&user, pubKey) + return checkUserAndPubKey(&user, pubKey, isSSHCert) } - return provider.validateUserAndPubKey(username, pubKey) + return provider.validateUserAndPubKey(username, pubKey, isSSHCert) } // CheckKeyboardInteractiveAuth checks the keyboard interactive authentication and returns @@ -2178,9 +2178,10 @@ func validateBaseParams(user *User) error { if user.HomeDir == "" { return util.NewValidationError("home_dir is mandatory") } - if user.Password == "" && len(user.PublicKeys) == 0 { + // we can have users with no passwords and public keys, they can authenticate via SSH user certs or OIDC + /*if user.Password == "" && len(user.PublicKeys) == 0 { return util.NewValidationError("please set a password or at least a public_key") - } + }*/ if !filepath.IsAbs(user.HomeDir) { return util.NewValidationError(fmt.Sprintf("home_dir must be an absolute path, actual value: %v", user.HomeDir)) } @@ -2429,28 +2430,25 @@ func checkUserPasscode(user *User, password, protocol string) (string, error) { return password, nil } -func checkUserAndPubKey(user *User, pubKey []byte) (User, string, error) { +func checkUserAndPubKey(user *User, pubKey []byte, isSSHCert bool) (User, string, error) { err := user.CheckLoginConditions() if err != nil { return *user, "", err } + if isSSHCert { + return *user, "", nil + } if len(user.PublicKeys) == 0 { return *user, "", ErrInvalidCredentials } for i, k := range user.PublicKeys { storedPubKey, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(k)) if err != nil { - providerLog(logger.LevelError, "error parsing stored public key %d for user %v: %v", i, user.Username, err) + providerLog(logger.LevelError, "error parsing stored public key %d for user %s: %v", i, user.Username, err) return *user, "", err } if bytes.Equal(storedPubKey.Marshal(), pubKey) { - certInfo := "" - cert, ok := storedPubKey.(*ssh.Certificate) - if ok { - certInfo = fmt.Sprintf(" %v ID: %v Serial: %v CA: %v", cert.Type(), cert.KeyId, cert.Serial, - ssh.FingerprintSHA256(cert.SignatureKey)) - } - return *user, fmt.Sprintf("%s:%s%s", ssh.FingerprintSHA256(storedPubKey), comment, certInfo), nil + return *user, fmt.Sprintf("%s:%s", ssh.FingerprintSHA256(storedPubKey), comment), nil } } return *user, "", ErrInvalidCredentials diff --git a/dataprovider/memory.go b/dataprovider/memory.go index 9bdad0bb..355c02ad 100644 --- a/dataprovider/memory.go +++ b/dataprovider/memory.go @@ -126,7 +126,7 @@ func (p *MemoryProvider) validateUserAndPass(username, password, ip, protocol st return checkUserAndPass(&user, password, ip, protocol) } -func (p *MemoryProvider) validateUserAndPubKey(username string, pubKey []byte) (User, string, error) { +func (p *MemoryProvider) validateUserAndPubKey(username string, pubKey []byte, isSSHCert bool) (User, string, error) { var user User if len(pubKey) == 0 { return user, "", errors.New("credentials cannot be null or empty") @@ -136,7 +136,7 @@ func (p *MemoryProvider) validateUserAndPubKey(username string, pubKey []byte) ( providerLog(logger.LevelWarn, "error authenticating user %#v: %v", username, err) return user, "", err } - return checkUserAndPubKey(&user, pubKey) + return checkUserAndPubKey(&user, pubKey, isSSHCert) } func (p *MemoryProvider) validateAdminAndPass(username, password, ip string) (Admin, error) { diff --git a/dataprovider/mysql.go b/dataprovider/mysql.go index 9b9da95a..3ab8c6a9 100644 --- a/dataprovider/mysql.go +++ b/dataprovider/mysql.go @@ -203,8 +203,8 @@ func (p *MySQLProvider) validateUserAndTLSCert(username, protocol string, tlsCer return sqlCommonValidateUserAndTLSCertificate(username, protocol, tlsCert, p.dbHandle) } -func (p *MySQLProvider) validateUserAndPubKey(username string, publicKey []byte) (User, string, error) { - return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle) +func (p *MySQLProvider) validateUserAndPubKey(username string, publicKey []byte, isSSHCert bool) (User, string, error) { + return sqlCommonValidateUserAndPubKey(username, publicKey, isSSHCert, p.dbHandle) } func (p *MySQLProvider) updateTransferQuota(username string, uploadSize, downloadSize int64, reset bool) error { diff --git a/dataprovider/pgsql.go b/dataprovider/pgsql.go index 02493ce1..91d35d7e 100644 --- a/dataprovider/pgsql.go +++ b/dataprovider/pgsql.go @@ -179,8 +179,8 @@ func (p *PGSQLProvider) validateUserAndTLSCert(username, protocol string, tlsCer return sqlCommonValidateUserAndTLSCertificate(username, protocol, tlsCert, p.dbHandle) } -func (p *PGSQLProvider) validateUserAndPubKey(username string, publicKey []byte) (User, string, error) { - return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle) +func (p *PGSQLProvider) validateUserAndPubKey(username string, publicKey []byte, isSSHCert bool) (User, string, error) { + return sqlCommonValidateUserAndPubKey(username, publicKey, isSSHCert, p.dbHandle) } func (p *PGSQLProvider) updateTransferQuota(username string, uploadSize, downloadSize int64, reset bool) error { diff --git a/dataprovider/sqlcommon.go b/dataprovider/sqlcommon.go index 107e4f42..bd40bc9b 100644 --- a/dataprovider/sqlcommon.go +++ b/dataprovider/sqlcommon.go @@ -620,7 +620,7 @@ func sqlCommonValidateUserAndTLSCertificate(username, protocol string, tlsCert * return checkUserAndTLSCertificate(&user, protocol, tlsCert) } -func sqlCommonValidateUserAndPubKey(username string, pubKey []byte, dbHandle *sql.DB) (User, string, error) { +func sqlCommonValidateUserAndPubKey(username string, pubKey []byte, isSSHCert bool, dbHandle *sql.DB) (User, string, error) { var user User if len(pubKey) == 0 { return user, "", errors.New("credentials cannot be null or empty") @@ -630,7 +630,7 @@ func sqlCommonValidateUserAndPubKey(username string, pubKey []byte, dbHandle *sq providerLog(logger.LevelWarn, "error authenticating user %#v: %v", username, err) return user, "", err } - return checkUserAndPubKey(&user, pubKey) + return checkUserAndPubKey(&user, pubKey, isSSHCert) } func sqlCommonCheckAvailability(dbHandle *sql.DB) error { diff --git a/dataprovider/sqlite.go b/dataprovider/sqlite.go index d18861a1..5ba82c1c 100644 --- a/dataprovider/sqlite.go +++ b/dataprovider/sqlite.go @@ -153,8 +153,8 @@ func (p *SQLiteProvider) validateUserAndTLSCert(username, protocol string, tlsCe return sqlCommonValidateUserAndTLSCertificate(username, protocol, tlsCert, p.dbHandle) } -func (p *SQLiteProvider) validateUserAndPubKey(username string, publicKey []byte) (User, string, error) { - return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle) +func (p *SQLiteProvider) validateUserAndPubKey(username string, publicKey []byte, isSSHCert bool) (User, string, error) { + return sqlCommonValidateUserAndPubKey(username, publicKey, isSSHCert, p.dbHandle) } func (p *SQLiteProvider) updateTransferQuota(username string, uploadSize, downloadSize int64, reset bool) error { diff --git a/httpd/httpd_test.go b/httpd/httpd_test.go index cf758d8d..391a53b0 100644 --- a/httpd/httpd_test.go +++ b/httpd/httpd_test.go @@ -1583,7 +1583,13 @@ func TestAddUserNoCredentials(t *testing.T) { u := getTestUser() u.Password = "" u.PublicKeys = []string{} - _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) + user, _, err := httpdtest.AddUser(u, http.StatusCreated) + assert.NoError(t, err) + // this user cannot login with an empty password but it still can use an SSH cert + _, err = getJWTAPITokenFromTestServer(defaultTokenAuthUser, "") + assert.Error(t, err) + + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) } diff --git a/sftpd/server.go b/sftpd/server.go index e5fb509e..3417af4b 100644 --- a/sftpd/server.go +++ b/sftpd/server.go @@ -885,6 +885,13 @@ func (c *Configuration) validatePublicKeyCredentials(conn ssh.ConnMetadata, pubK updateLoginMetrics(&user, ipAddr, method, err) return nil, err } + if len(cert.ValidPrincipals) == 0 { + err = fmt.Errorf("ssh: certificate %s has no valid principals, user: \"%s\"", + ssh.FingerprintSHA256(pubKey), conn.User()) + user.Username = conn.User() + updateLoginMetrics(&user, ipAddr, method, err) + return nil, err + } if err := c.certChecker.CheckCert(conn.User(), cert); err != nil { user.Username = conn.User() updateLoginMetrics(&user, ipAddr, method, err) @@ -892,7 +899,11 @@ func (c *Configuration) validatePublicKeyCredentials(conn ssh.ConnMetadata, pubK } certPerm = &cert.Permissions } - if user, keyID, err = dataprovider.CheckUserAndPubKey(conn.User(), pubKey.Marshal(), ipAddr, common.ProtocolSSH); err == nil { + if user, keyID, err = dataprovider.CheckUserAndPubKey(conn.User(), pubKey.Marshal(), ipAddr, common.ProtocolSSH, ok); err == nil { + if ok { + keyID = fmt.Sprintf("%s: ID: %s, serial: %v, CA %s %s", ssh.FingerprintSHA256(pubKey), + cert.KeyId, cert.Serial, cert.Type(), ssh.FingerprintSHA256(cert.SignatureKey)) + } if user.IsPartialAuth(method) { logger.Debug(logSender, connectionID, "user %#v authenticated with partial success", conn.User()) return certPerm, ssh.ErrPartialSuccess diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index c00d9146..0e875cb3 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -116,10 +116,13 @@ iixITGvaNZh/tjAAAACW5pY29sYUBwMQE= // this is testPubKey signed using testCAUserKey but expired. // % ssh-keygen -s ca_user_key -I test_user_sftp -n test_user_sftp -V 20100101123000:20110101123000 -z 4 /tmp/test.pub testCertExpired = "ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgU3TLP5285k20fBSsdZioI78oJUpaRXFlgx5IPg6gWg8AAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0AAAAAAAAABAAAAAEAAAAOdGVzdF91c2VyX3NmdHAAAAASAAAADnRlc3RfdXNlcl9zZnRwAAAAAEs93LgAAAAATR8QOAAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQDF5fcwZHiyixmnE6IlOZJpZhWXoh62gN+yadAA0GJ509SAEaZVLPDP8S5RsE8mUikR3wxynVshxHeqMhrkS+RlNbhSlOXDdNg94yTrq/xF8Z/PgKRInvef74k5i7bAIytza7jERzFJ/ujTEy3537T5k5EYQJ15ZQGuvzynSdv+6o99SjI4jFplyQOZ2QcYbEAmhHm5GgQlIiEFG/RlDtLksOulKZxOY3qPzP0AyQxtZJXn/5vG40aW9LTbwxCJqWlgrkFXMqAAVCbuU5YspwhiXmKt1PsldiXw23oloa4caCKN1jzbFiGuZNXEU2Ebx7JIvjQCPaUYwLjEbkRDxDqN/vmwZqBuKYiuG9Eafx+nFSQkr7QYb5b+mT+/1IFHnmeRGn38731kBqtH7tpzC/t+soRX9p2HtJM+9MYhblO2OqTSPGTlxihWUkyiRBekpAhaiHld16TsG+A3bOJHrojGcX+5g6oGarKGLAMcykL1X+rZqT993Mo6d2Z7q43MOXEAAAGUAAAADHJzYS1zaGEyLTUxMgAAAYAlH3hhj8J6xLyVpeLZjblzwDKrxp/MWiH30hQ965ExPrPRcoAZFEKVqOYdj6bp4Q19Q4Yzqdobg3aN5ym2iH0b2TlOY0mM901CAoHbNJyiLs+0KiFRoJ+30EDj/hcKusg6v8ln2yixPagAyQu3zyiWo4t1ZuO3I86xchGlptStxSdHAHPFCfpbhcnzWFZctiMqUutl82C4ROWyjOZcRzdVdWHeN5h8wnooXuvba2VkT8QPmjYYyRGuQ3Hg+ySdh8Tel4wiix1Dg5MX7Wjh4hKEx80No9UPy+0iyZMNc07lsWAtrY6NRxGM5CzB6mklscB8TzFrVSnIl9u3bquLfaCrFt/Mft5dR7Yy4jmF+zUhjia6h6giCZ91J+FZ4hV+WkBtPCvTfrGWoA1BgEB/iI2xOq/NPqJ7UXRoMXk/l0NPgRPT2JS1adegqnt4ddr6IlmPyZxaSEvXhanjKdfMlEFYO1wz7ouqpYUozQVy4KXBlzFlNwyD1hI+k4+/A6AIYeI= nicola@p1" - configDir = ".." - osWindows = "windows" - testFileName = "test_file_sftp.dat" - testDLFileName = "test_download_sftp.dat" + // this is testPubKey signed without a principal + // ssh-keygen -s ca_user_key -I test_user_sftp -V always:forever -O source-address=127.0.0.1 -z 1 /tmp/test.pub + testCertNoPrincipals = "ssh-rsa-cert-v01@openssh.com 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 nicola@p1" + configDir = ".." + osWindows = "windows" + testFileName = "test_file_sftp.dat" + testDLFileName = "test_download_sftp.dat" ) var ( @@ -1788,7 +1791,6 @@ func TestLogin(t *testing.T) { func TestLoginUserCert(t *testing.T) { u := getTestUser(true) - u.PublicKeys = []string{testCertValid, testCertUntrustedCA, testHostCert, testCertOtherSourceAddress, testCertExpired} user, _, err := httpdtest.AddUser(u, http.StatusCreated) assert.NoError(t, err) // try login using a cert signed from a trusted CA @@ -1832,11 +1834,28 @@ func TestLoginUserCert(t *testing.T) { client.Close() conn.Close() } + // try login using a certificate with no principals + signer, err = getSignerForUserCert([]byte(testCertNoPrincipals)) + assert.NoError(t, err) + conn, client, err = getCustomAuthSftpClient(user, []ssh.AuthMethod{ssh.PublicKeys(signer)}, "") + if !assert.Error(t, err) { + client.Close() + conn.Close() + } _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + // the user does not exist + signer, err = getSignerForUserCert([]byte(testCertValid)) + assert.NoError(t, err) + conn, client, err = getCustomAuthSftpClient(user, []ssh.AuthMethod{ssh.PublicKeys(signer)}, "") + if !assert.Error(t, err) { + client.Close() + conn.Close() + } + // now login with a username not in the set of valid principals for the given certificate u.Username += "1" user, _, err = httpdtest.AddUser(u, http.StatusCreated) @@ -1989,7 +2008,6 @@ func TestMultiStepLoginKeyAndKeyInt(t *testing.T) { func TestMultiStepLoginCertAndPwd(t *testing.T) { u := getTestUser(true) u.Password = defaultPassword - u.PublicKeys = []string{testCertValid, testCertOtherSourceAddress} u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, []string{ dataprovider.SSHLoginMethodKeyAndKeyboardInt, dataprovider.SSHLoginMethodPublicKey,