Show info about public key during login

This will show the key fingerprint and the associated comment, or
"password" when password was used, during login.

Eg.:

```
message":"User id: 1, logged in with: \"public_key:SHA256:FV3+wlAKGzYy7+J02786fh8N8c06+jga/mdiSOSPT7g:jo@desktop\",
```

or

```
message":"User id: 1, logged in with: \"password\",
...`

Signed-off-by: Jo Vandeginste <Jo.Vandeginste@kuleuven.be>
This commit is contained in:
Jo Vandeginste 2019-09-05 21:35:53 +02:00 committed by drakkan
parent bb589c6fc8
commit 25260297aa
8 changed files with 29 additions and 24 deletions

View file

@ -71,15 +71,15 @@ func (p BoltProvider) validateUserAndPass(username string, password string) (Use
return checkUserAndPass(user, password)
}
func (p BoltProvider) validateUserAndPubKey(username string, pubKey string) (User, error) {
func (p BoltProvider) validateUserAndPubKey(username string, pubKey string) (User, string, error) {
var user User
if len(pubKey) == 0 {
return user, errors.New("Credentials cannot be null or empty")
return user, "", errors.New("Credentials cannot be null or empty")
}
user, err := p.userExists(username)
if err != nil {
logger.Warn(logSender, "", "error authenticating user: %v, error: %v", username, err)
return user, err
return user, "", err
}
return checkUserAndPubKey(user, pubKey)
}

View file

@ -132,7 +132,7 @@ func GetProvider() Provider {
// Provider interface that data providers must implement.
type Provider interface {
validateUserAndPass(username string, password string) (User, error)
validateUserAndPubKey(username string, pubKey string) (User, error)
validateUserAndPubKey(username string, pubKey string) (User, string, error)
updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error
getUsedQuota(username string) (int, int64, error)
userExists(username string) (User, error)
@ -166,7 +166,7 @@ func CheckUserAndPass(p Provider, username string, password 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(p Provider, username string, pubKey string) (User, error) {
func CheckUserAndPubKey(p Provider, username string, pubKey string) (User, string, error) {
return p.validateUserAndPubKey(username, pubKey)
}
@ -297,21 +297,22 @@ func checkUserAndPass(user User, password string) (User, error) {
return user, err
}
func checkUserAndPubKey(user User, pubKey string) (User, error) {
func checkUserAndPubKey(user User, pubKey string) (User, string, error) {
if len(user.PublicKeys) == 0 {
return user, errors.New("Invalid credentials")
return user, "", errors.New("Invalid credentials")
}
for i, k := range user.PublicKeys {
storedPubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(k))
storedPubKey, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(k))
if err != nil {
logger.Warn(logSender, "", "error parsing stored public key %d for user %v: %v", i, user.Username, err)
return user, err
return user, "", err
}
if string(storedPubKey.Marshal()) == pubKey {
return user, nil
fp := ssh.FingerprintSHA256(storedPubKey)
return user, fp + ":" + comment, nil
}
}
return user, errors.New("Invalid credentials")
return user, "", errors.New("Invalid credentials")
}
func comparePbkdf2PasswordAndHash(password, hashedPassword string) (bool, error) {

View file

@ -41,7 +41,7 @@ func (p MySQLProvider) validateUserAndPass(username string, password string) (Us
return sqlCommonValidateUserAndPass(username, password, p.dbHandle)
}
func (p MySQLProvider) validateUserAndPubKey(username string, publicKey string) (User, error) {
func (p MySQLProvider) validateUserAndPubKey(username string, publicKey string) (User, string, error) {
return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle)
}

View file

@ -39,7 +39,7 @@ func (p PGSQLProvider) validateUserAndPass(username string, password string) (Us
return sqlCommonValidateUserAndPass(username, password, p.dbHandle)
}
func (p PGSQLProvider) validateUserAndPubKey(username string, publicKey string) (User, error) {
func (p PGSQLProvider) validateUserAndPubKey(username string, publicKey string) (User, string, error) {
return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle)
}

View file

@ -37,15 +37,15 @@ func sqlCommonValidateUserAndPass(username string, password string, dbHandle *sq
return checkUserAndPass(user, password)
}
func sqlCommonValidateUserAndPubKey(username string, pubKey string, dbHandle *sql.DB) (User, error) {
func sqlCommonValidateUserAndPubKey(username string, pubKey string, dbHandle *sql.DB) (User, string, error) {
var user User
if len(pubKey) == 0 {
return user, errors.New("Credentials cannot be null or empty")
return user, "", errors.New("Credentials cannot be null or empty")
}
user, err := getUserByUsername(username, dbHandle)
if err != nil {
logger.Warn(logSender, "", "error authenticating user: %v, error: %v", username, err)
return user, err
return user, "", err
}
return checkUserAndPubKey(user, pubKey)
}

View file

@ -52,7 +52,7 @@ func (p SQLiteProvider) validateUserAndPass(username string, password string) (U
return sqlCommonValidateUserAndPass(username, password, p.dbHandle)
}
func (p SQLiteProvider) validateUserAndPubKey(username string, publicKey string) (User, error) {
func (p SQLiteProvider) validateUserAndPubKey(username string, publicKey string) (User, string, error) {
return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle)
}

View file

@ -144,7 +144,7 @@ func TestUploadFiles(t *testing.T) {
func TestWithInvalidHome(t *testing.T) {
u := dataprovider.User{}
u.HomeDir = "home_rel_path"
_, err := loginUser(u)
_, err := loginUser(u, "password")
if err == nil {
t.Errorf("login a user with an invalid home_dir must fail")
}

View file

@ -210,6 +210,7 @@ func (c Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Server
logger.Debug(logSender, "", "accepted inbound connection, ip: %v", conn.RemoteAddr().String())
var user dataprovider.User
var loginType string
err = json.Unmarshal([]byte(sconn.Permissions.Extensions["user"]), &user)
@ -217,6 +218,7 @@ func (c Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Server
logger.Warn(logSender, "", "Unable to deserialize user info, cannot serve connection: %v", err)
return
}
loginType = sconn.Permissions.Extensions["login_type"]
connectionID := hex.EncodeToString(sconn.SessionID())
@ -230,8 +232,8 @@ func (c Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Server
lock: new(sync.Mutex),
sshConn: sconn,
}
logger.Info(logSender, connectionID, "User id: %d, name: %#v, home_dir: %#v",
user.ID, user.Username, user.HomeDir)
logger.Info(logSender, connectionID, "User id: %d, logged in with: %#v, name: %#v, home_dir: %#v",
user.ID, loginType, user.Username, user.HomeDir)
go ssh.DiscardRequests(reqs)
@ -317,7 +319,7 @@ func (c Configuration) createHandler(connection Connection) sftp.Handlers {
}
}
func loginUser(user dataprovider.User) (*ssh.Permissions, error) {
func loginUser(user dataprovider.User, loginType string) (*ssh.Permissions, error) {
if !filepath.IsAbs(user.HomeDir) {
logger.Warn(logSender, "", "user %v has invalid home dir: %v. Home dir must be an absolute path, login not allowed",
user.Username, user.HomeDir)
@ -348,6 +350,7 @@ func loginUser(user dataprovider.User) (*ssh.Permissions, error) {
p := &ssh.Permissions{}
p.Extensions = make(map[string]string)
p.Extensions["user"] = string(json)
p.Extensions["login_type"] = loginType
return p, nil
}
@ -370,9 +373,10 @@ func (c *Configuration) checkHostKeys(configDir string) error {
func (c Configuration) validatePublicKeyCredentials(conn ssh.ConnMetadata, pubKey string) (*ssh.Permissions, error) {
var err error
var user dataprovider.User
var keyID string
if user, err = dataprovider.CheckUserAndPubKey(dataProvider, conn.User(), pubKey); err == nil {
return loginUser(user)
if user, keyID, err = dataprovider.CheckUserAndPubKey(dataProvider, conn.User(), pubKey); err == nil {
return loginUser(user, "public_key:"+keyID)
}
return nil, err
}
@ -382,7 +386,7 @@ func (c Configuration) validatePasswordCredentials(conn ssh.ConnMetadata, pass [
var user dataprovider.User
if user, err = dataprovider.CheckUserAndPass(dataProvider, conn.User(), string(pass)); err == nil {
return loginUser(user)
return loginUser(user, "password")
}
return nil, err
}