store hashed token base64 encoded

This commit is contained in:
Pascal Fischer 2023-03-29 15:21:53 +02:00
parent 726ffb5740
commit c5942e6b33
6 changed files with 43 additions and 22 deletions

View File

@ -3,6 +3,7 @@ package server
import (
"context"
"crypto/sha256"
b64 "encoding/base64"
"fmt"
"hash/crc32"
"math/rand"
@ -54,7 +55,7 @@ type AccountManager interface {
GetSetupKey(accountID, userID, keyID string) (*SetupKey, error)
GetAccountByUserOrAccountID(userID, accountID, domain string) (*Account, error)
GetAccountFromToken(claims jwtclaims.AuthorizationClaims) (*Account, *User, error)
GetAccountFromPAT(pat string) (*Account, *User, error)
GetAccountFromPAT(pat string) (*Account, *User, *PersonalAccessToken, error)
IsUserAdmin(claims jwtclaims.AuthorizationClaims) (bool, error)
AccountExists(accountId string) (*bool, error)
GetPeerByKey(peerKey string) (*Peer, error)
@ -1120,44 +1121,55 @@ func (am *DefaultAccountManager) redeemInvite(account *Account, userID string) e
}
// GetAccountFromPAT returns Account and User associated with a personal access token
func (am *DefaultAccountManager) GetAccountFromPAT(token string) (*Account, *User, error) {
func (am *DefaultAccountManager) GetAccountFromPAT(token string) (*Account, *User, *PersonalAccessToken, error) {
if len(token) != PATLength {
return nil, nil, fmt.Errorf("token has wrong length")
return nil, nil, nil, fmt.Errorf("token has wrong length")
}
log.Debugf("Token: %s", token)
prefix := token[:len(PATPrefix)]
if prefix != PATPrefix {
return nil, nil, fmt.Errorf("token has wrong prefix")
return nil, nil, nil, fmt.Errorf("token has wrong prefix")
}
secret := token[len(PATPrefix) : len(PATPrefix)+PATSecretLength]
encodedChecksum := token[len(PATPrefix)+PATSecretLength : len(PATPrefix)+PATSecretLength+PATChecksumLength]
verificationChecksum, err := base62.Decode(encodedChecksum)
if err != nil {
return nil, nil, fmt.Errorf("token checksum decoding failed: %w", err)
return nil, nil, nil, fmt.Errorf("token checksum decoding failed: %w", err)
}
secretChecksum := crc32.ChecksumIEEE([]byte(secret))
if secretChecksum != verificationChecksum {
return nil, nil, fmt.Errorf("token checksum does not match")
return nil, nil, nil, fmt.Errorf("token checksum does not match")
}
hashedToken := sha256.Sum256([]byte(token))
tokenID, err := am.Store.GetTokenIDByHashedToken(string(hashedToken[:]))
encodedHashedToken := b64.StdEncoding.EncodeToString(hashedToken[:])
tokenID, err := am.Store.GetTokenIDByHashedToken(encodedHashedToken)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
log.Debugf("TokenID: %s", tokenID)
user, err := am.Store.GetUserByTokenID(tokenID)
log.Debugf("User: %v", user)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
account, err := am.Store.GetAccountByUser(user.Id)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
return account, user, nil
pat := user.PATs[tokenID]
if pat == nil {
return nil, nil, nil, fmt.Errorf("personal access token not found")
}
return account, user, pat, nil
}
// GetAccountFromToken returns an account associated with this token

View File

@ -2,6 +2,7 @@ package server
import (
"crypto/sha256"
b64 "encoding/base64"
"fmt"
"net"
"reflect"
@ -465,12 +466,13 @@ func TestAccountManager_GetAccountFromPAT(t *testing.T) {
token := "nbp_9999EUDNdkeusjentDLSJEn1902u84390W6W"
hashedToken := sha256.Sum256([]byte(token))
encodedHashedToken := b64.StdEncoding.EncodeToString(hashedToken[:])
account.Users["someUser"] = &User{
Id: "someUser",
PATs: map[string]*PersonalAccessToken{
"pat1": {
"tokenId": {
ID: "tokenId",
HashedToken: string(hashedToken[:]),
HashedToken: encodedHashedToken,
},
},
}
@ -483,13 +485,14 @@ func TestAccountManager_GetAccountFromPAT(t *testing.T) {
Store: store,
}
account, user, err := am.GetAccountFromPAT(token)
account, user, pat, err := am.GetAccountFromPAT(token)
if err != nil {
t.Fatalf("Error when getting Account from PAT: %s", err)
}
assert.Equal(t, "account_id", account.Id)
assert.Equal(t, "someUser", user.Id)
assert.Equal(t, account.Users["someUser"].PATs["tokenId"], pat)
}
func TestAccountManager_PrivateAccount(t *testing.T) {

View File

@ -112,7 +112,7 @@ func restore(file string) (*FileStore, error) {
store.UserID2AccountID[user.Id] = accountID
for _, pat := range user.PATs {
store.TokenID2UserID[pat.ID] = user.Id
store.HashedPAT2TokenID[pat.HashedToken[:]] = pat.ID
store.HashedPAT2TokenID[pat.HashedToken] = pat.ID
}
}
@ -268,7 +268,7 @@ func (s *FileStore) SaveAccount(account *Account) error {
s.UserID2AccountID[user.Id] = accountCopy.Id
for _, pat := range user.PATs {
s.TokenID2UserID[pat.ID] = user.Id
s.HashedPAT2TokenID[pat.HashedToken[:]] = pat.ID
s.HashedPAT2TokenID[pat.HashedToken] = pat.ID
}
}
@ -349,11 +349,13 @@ func (s *FileStore) GetTokenIDByHashedToken(token string) (string, error) {
s.mux.Lock()
defer s.mux.Unlock()
log.Debugf("TOken still there: %v", token)
log.Debugf("TokenID2UserId %v", s.HashedPAT2TokenID)
tokenID, ok := s.HashedPAT2TokenID[token]
if !ok {
return "", status.Errorf(status.NotFound, "tokenID not found: provided token doesn't exists")
}
log.Debugf("TokenID for token %s is %s", token, tokenID)
return tokenID, nil
}
@ -366,12 +368,12 @@ func (s *FileStore) GetUserByTokenID(tokenID string) (*User, error) {
if !ok {
return nil, status.Errorf(status.NotFound, "user not found: provided tokenID doesn't exists")
}
log.Debugf("UserID for tokenID %s is %s", tokenID, userID)
accountID, ok := s.UserID2AccountID[userID]
if !ok {
return nil, status.Errorf(status.NotFound, "accountID not found: provided userID doesn't exists")
}
log.Debugf("AccountID for userID %s is %s", userID, accountID)
account, err := s.getAccount(accountID)
if err != nil {
return nil, err

View File

@ -2,6 +2,7 @@ package server
import (
"crypto/sha256"
b64 "encoding/base64"
"fmt"
"hash/crc32"
"time"
@ -74,5 +75,6 @@ func generateNewToken() (string, string, error) {
paddedChecksum := fmt.Sprintf("%06s", encodedChecksum)
plainToken := PATPrefix + secret + paddedChecksum
hashedToken := sha256.Sum256([]byte(plainToken))
return string(hashedToken[:]), plainToken, nil
encodedHashedToken := b64.StdEncoding.EncodeToString(hashedToken[:])
return encodedHashedToken, plainToken, nil
}

View File

@ -2,6 +2,7 @@ package server
import (
"crypto/sha256"
b64 "encoding/base64"
"hash/crc32"
"strings"
"testing"
@ -13,7 +14,8 @@ import (
func TestPAT_GenerateToken_Hashing(t *testing.T) {
hashedToken, plainToken, _ := generateNewToken()
expectedToken := sha256.Sum256([]byte(plainToken))
assert.Equal(t, hashedToken, string(expectedToken[:]))
encodedExpectedToken := b64.StdEncoding.EncodeToString(expectedToken[:])
assert.Equal(t, hashedToken, encodedExpectedToken)
}
func TestPAT_GenerateToken_Prefix(t *testing.T) {

View File

@ -37,7 +37,7 @@ func TestUser_AddPATToUser(t *testing.T) {
}
fileStore := am.Store.(*FileStore)
tokenID := fileStore.HashedPAT2TokenID[mockToken[:]]
tokenID := fileStore.HashedPAT2TokenID[mockToken]
if tokenID == "" {
t.Fatal("GetTokenIDByHashedToken failed after adding PAT")