Skip to content

Commit

Permalink
Fixed a nasty bug with stored hashes of passwords
Browse files Browse the repository at this point in the history
Hash is generated with random salt by default and if we don't know
salt (our case) - we can't pull from DB and remove the access quickly.
So instead I store just hash there with empty salt. This works, because
the access is temporary and one-shot, so technically no issues, but
if we will change that at some point - this mechanism is needed to be
reworked.
  • Loading branch information
sparshev committed Dec 11, 2024
1 parent daba843 commit 27dcfa2
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 26 deletions.
8 changes: 3 additions & 5 deletions lib/openapi/api/api_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,9 @@ func (e *Processor) ResourceAccessPut(c echo.Context, uid types.ResourceUID) err
}

pwd := crypt.RandString(64)
pwdHash, err := crypt.NewHash(pwd, nil).Serialize()
if err != nil {
c.JSON(http.StatusBadRequest, H{"message": "Unable to prepare password hash"})
return fmt.Errorf("Unable to prepare password hash: %w", err)
}
// The proxy password is temporary (for the lifetime of the Resource) and one-time
// so lack of salt will not be a big deal - the params will contribute to salt majorily.
pwdHash := crypt.NewHash(pwd, []byte{}).Hash
key, err := crypt.GenerateSSHKey()
if err != nil {
c.JSON(http.StatusBadRequest, H{"message": "Unable to generate SSH key"})
Expand Down
21 changes: 10 additions & 11 deletions lib/proxyssh/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,24 +307,23 @@ func (p *proxySSH) passwordCallback(incomingConn ssh.ConnMetadata, pass []byte)

fishUser, err := p.fish.UserGet(user)
if err != nil {
log.Errorf("PROXYSSH: Unrecognized user %q", user)
log.Errorf("PROXYSSH: %s: Unrecognized user %q", incomingConn.RemoteAddr(), user)
return nil, fmt.Errorf("Invalid access")
}

pwdHash, err := crypt.NewHash(string(pass), nil).Serialize()
if err != nil {
return nil, fmt.Errorf("PROXYSSH: Unable to prepare password hash: %w", err)
}
pwdHashStr := string(pwdHash)
// The proxy password is temporary (for the lifetime of the Resource) and one-time
// so lack of salt will not be a big deal - the params will contribute to salt majorily.
passHash := crypt.NewHash(string(pass), []byte{}).Hash
passHashStr := string(passHash)

ra, err := p.fish.ResourceAccessSingleUsePasswordHash(fishUser.Name, pwdHashStr)
ra, err := p.fish.ResourceAccessSingleUsePasswordHash(fishUser.Name, passHashStr)
if err != nil {
log.Errorf("PROXYSSH: Invalid access for user %q: %v", user, err)
log.Errorf("PROXYSSH: %s: Invalid access for user %q: %v", incomingConn.RemoteAddr(), fishUser.Name, err)
return nil, fmt.Errorf("Invalid access")
}

// Only return non-error if the username and password match (double check just in case)
if ra.Username == user && ra.Password == pwdHashStr {
if ra.Username == user && ra.Password == passHashStr {
srcAddr := incomingConn.RemoteAddr()
// If the session is not already stored in our map, create it so that
// we have access to it when processing the incoming connections.
Expand All @@ -342,15 +341,15 @@ func (p *proxySSH) publicKeyCallback(incomingConn ssh.ConnMetadata, key ssh.Publ

fishUser, err := p.fish.UserGet(user)
if err != nil {
log.Errorf("PROXYSSH: Unrecognized user %q", user)
log.Errorf("PROXYSSH: %s: Unrecognized user %q", incomingConn.RemoteAddr(), user)
return nil, fmt.Errorf("Invalid access")
}

stringKey := string(ssh.MarshalAuthorizedKey(key))

ra, err := p.fish.ResourceAccessSingleUseKey(fishUser.Name, stringKey)
if err != nil {
log.Errorf("PROXYSSH: Invalid access for user %q: %v", user, err)
log.Errorf("PROXYSSH: %s: Invalid access for user %q: %v", incomingConn.RemoteAddr(), user, err)
return nil, fmt.Errorf("Invalid access")
}

Expand Down
12 changes: 6 additions & 6 deletions tests/proxyssh_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ drivers:
}

// Running SSH Pty server with shell
sshPort := h.TestSSHPtyServer(t, "testuser", "testpass", "")
sshdPort := h.TestSSHPtyServer(t, "testuser", "testpass", "")

var label types.Label
t.Run("Create Label", func(t *testing.T) {
Expand All @@ -80,7 +80,7 @@ drivers:
JSON(`{"name":"test-label", "version":1, "definitions": [{
"driver":"test",
"resources":{"cpu":1,"ram":2},
"authentication":{"username":"testuser","password":"testpass","port":`+sshPort+`}
"authentication":{"username":"testuser","password":"testpass","port":`+sshdPort+`}
}]}`).
BasicAuth("admin", afi.AdminToken()).
Expect(t).
Expand Down Expand Up @@ -276,7 +276,7 @@ drivers:
}

// Running SSH Pty server with shell
sshPort := h.TestSSHPtyServer(t, "testuser", "", string(serverpubkey))
sshdPort := h.TestSSHPtyServer(t, "testuser", "", string(serverpubkey))

var label types.Label
t.Run("Create Label", func(t *testing.T) {
Expand All @@ -286,7 +286,7 @@ drivers:
JSON(`{"name":"test-label", "version":1, "definitions": [{
"driver":"test",
"resources":{"cpu":1,"ram":2},
"authentication":{"username":"testuser","key":`+string(serverkeyjson)+`,"port":`+sshPort+`}
"authentication":{"username":"testuser","key":`+string(serverkeyjson)+`,"port":`+sshdPort+`}
}]}`).
BasicAuth("admin", afi.AdminToken()).
Expect(t).
Expand Down Expand Up @@ -468,7 +468,7 @@ drivers:
}

// Running SSH Sftp server with shell
sshPort := h.TestSSHSftpServer(t, "testuser", "testpass", "")
sshdPort := h.TestSSHSftpServer(t, "testuser", "testpass", "")

var label types.Label
t.Run("Create Label", func(t *testing.T) {
Expand All @@ -478,7 +478,7 @@ drivers:
JSON(`{"name":"test-label", "version":1, "definitions": [{
"driver":"test",
"resources":{"cpu":1,"ram":2},
"authentication":{"username":"testuser","password":"testpass","port":`+sshPort+`}
"authentication":{"username":"testuser","password":"testpass","port":`+sshdPort+`}
}]}`).
BasicAuth("admin", afi.AdminToken()).
Expect(t).
Expand Down
8 changes: 4 additions & 4 deletions tests/proxyssh_password_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ drivers:
}

// Running SSH Pty server with shell
sshPort := h.TestSSHPtyServer(t, "testuser", "testpass", "")
sshdPort := h.TestSSHPtyServer(t, "testuser", "testpass", "")

var label types.Label
t.Run("Create Label", func(t *testing.T) {
Expand All @@ -72,7 +72,7 @@ drivers:
JSON(`{"name":"test-label", "version":1, "definitions": [{
"driver":"test",
"resources":{"cpu":1,"ram":2},
"authentication":{"username":"testuser","password":"testpass","port":`+sshPort+`}
"authentication":{"username":"testuser","password":"testpass","port":`+sshdPort+`}
}]}`).
BasicAuth("admin", afi.AdminToken()).
Expect(t).
Expand Down Expand Up @@ -232,7 +232,7 @@ drivers:
}

// Running SSH Sftp server with shell
sshPort := h.TestSSHSftpServer(t, "testuser", "testpass", "")
sshdPort := h.TestSSHSftpServer(t, "testuser", "testpass", "")

var label types.Label
t.Run("Create Label", func(t *testing.T) {
Expand All @@ -242,7 +242,7 @@ drivers:
JSON(`{"name":"test-label", "version":1, "definitions": [{
"driver":"test",
"resources":{"cpu":1,"ram":2},
"authentication":{"username":"testuser","password":"testpass","port":`+sshPort+`}
"authentication":{"username":"testuser","password":"testpass","port":`+sshdPort+`}
}]}`).
BasicAuth("admin", afi.AdminToken()).
Expect(t).
Expand Down

0 comments on commit 27dcfa2

Please sign in to comment.