Stop accessing user data in downstreamConn.authenticate

This becomes racy once user.Password is updated on-the-fly.
This commit is contained in:
Simon Ser 2020-03-27 22:38:38 +01:00
parent 551d41335e
commit 2fff645129
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48
2 changed files with 27 additions and 8 deletions

15
db.go
View File

@ -106,6 +106,21 @@ func (db *DB) ListUsers() ([]User, error) {
return users, nil return users, nil
} }
func (db *DB) GetUser(username string) (*User, error) {
db.lock.RLock()
defer db.lock.RUnlock()
user := &User{Username: username}
var password *string
row := db.db.QueryRow("SELECT password FROM User WHERE username = ?", username)
if err := row.Scan(&password); err != nil {
return nil, err
}
user.Password = fromStringPtr(password)
return user, nil
}
func (db *DB) CreateUser(user *User) error { func (db *DB) CreateUser(user *User) error {
db.lock.Lock() db.lock.Lock()
defer db.lock.Unlock() defer db.lock.Unlock()

View File

@ -586,19 +586,23 @@ func unmarshalUsername(rawUsername string) (username, network string) {
func (dc *downstreamConn) authenticate(username, password string) error { func (dc *downstreamConn) authenticate(username, password string) error {
username, networkName := unmarshalUsername(username) username, networkName := unmarshalUsername(username)
u := dc.srv.getUser(username) u, err := dc.srv.db.GetUser(username)
if u == nil {
dc.logger.Printf("failed authentication for %q: unknown username", username)
return errAuthFailed
}
err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
if err != nil { if err != nil {
dc.logger.Printf("failed authentication for %q: %v", username, err) dc.logger.Printf("failed authentication for %q: %v", username, err)
return errAuthFailed return errAuthFailed
} }
dc.user = u err = bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
if err != nil {
dc.logger.Printf("failed authentication for %q: %v", username, err)
return errAuthFailed
}
dc.user = dc.srv.getUser(username)
if dc.user == nil {
dc.logger.Printf("failed authentication for %q: user not active", username)
return errAuthFailed
}
dc.networkName = networkName dc.networkName = networkName
return nil return nil
} }