mirror of
https://github.com/netbirdio/netbird.git
synced 2025-06-19 17:31:39 +02:00
switch PATs to map and add deletion
This commit is contained in:
parent
e1ef091d45
commit
e30def175b
@ -66,6 +66,8 @@ type AccountManager interface {
|
|||||||
GetNetworkMap(peerID string) (*NetworkMap, error)
|
GetNetworkMap(peerID string) (*NetworkMap, error)
|
||||||
GetPeerNetwork(peerID string) (*Network, error)
|
GetPeerNetwork(peerID string) (*Network, error)
|
||||||
AddPeer(setupKey, userID string, peer *Peer) (*Peer, *NetworkMap, error)
|
AddPeer(setupKey, userID string, peer *Peer) (*Peer, *NetworkMap, error)
|
||||||
|
AddPATToUser(accountID string, userID string, pat *PersonalAccessToken) error
|
||||||
|
DeletePAT(accountID string, userID string, tokenID string) error
|
||||||
UpdatePeerSSHKey(peerID string, sshKey string) error
|
UpdatePeerSSHKey(peerID string, sshKey string) error
|
||||||
GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error)
|
GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error)
|
||||||
GetGroup(accountId, groupID string) (*Group, error)
|
GetGroup(accountId, groupID string) (*Group, error)
|
||||||
|
@ -473,7 +473,12 @@ func TestAccountManager_GetAccountFromPAT(t *testing.T) {
|
|||||||
|
|
||||||
token := "nbp_9999EUDNdkeusjentDLSJEn1902u84390W6W"
|
token := "nbp_9999EUDNdkeusjentDLSJEn1902u84390W6W"
|
||||||
hashedToken := sha256.Sum256([]byte(token))
|
hashedToken := sha256.Sum256([]byte(token))
|
||||||
pat := PersonalAccessToken{
|
account.Users["someUser"] = &User{
|
||||||
|
Id: "someUser",
|
||||||
|
Role: "",
|
||||||
|
AutoGroups: nil,
|
||||||
|
PATs: map[string]*PersonalAccessToken{
|
||||||
|
"pat1": {
|
||||||
ID: "tokenId",
|
ID: "tokenId",
|
||||||
Description: "some Description",
|
Description: "some Description",
|
||||||
HashedToken: string(hashedToken[:]),
|
HashedToken: string(hashedToken[:]),
|
||||||
@ -481,12 +486,8 @@ func TestAccountManager_GetAccountFromPAT(t *testing.T) {
|
|||||||
CreatedBy: "testuser",
|
CreatedBy: "testuser",
|
||||||
CreatedAt: time.Time{},
|
CreatedAt: time.Time{},
|
||||||
LastUsed: time.Time{},
|
LastUsed: time.Time{},
|
||||||
}
|
},
|
||||||
account.Users["someUser"] = &User{
|
},
|
||||||
Id: "someUser",
|
|
||||||
Role: "",
|
|
||||||
AutoGroups: nil,
|
|
||||||
PATs: []PersonalAccessToken{pat},
|
|
||||||
}
|
}
|
||||||
err := store.SaveAccount(account)
|
err := store.SaveAccount(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1267,8 +1268,8 @@ func TestAccount_Copy(t *testing.T) {
|
|||||||
Id: "user1",
|
Id: "user1",
|
||||||
Role: UserRoleAdmin,
|
Role: UserRoleAdmin,
|
||||||
AutoGroups: []string{"group1"},
|
AutoGroups: []string{"group1"},
|
||||||
PATs: []PersonalAccessToken{
|
PATs: map[string]*PersonalAccessToken{
|
||||||
{
|
"pat1": {
|
||||||
ID: "pat1",
|
ID: "pat1",
|
||||||
Description: "First PAT",
|
Description: "First PAT",
|
||||||
HashedToken: "SoMeHaShEdToKeN",
|
HashedToken: "SoMeHaShEdToKeN",
|
||||||
|
@ -288,6 +288,24 @@ func (s *FileStore) SaveAccount(account *Account) error {
|
|||||||
return s.persist(s.storeFile)
|
return s.persist(s.storeFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FileStore) DeleteHashedPAT2TokenIDIndex(hashedToken string) error {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
delete(s.HashedPAT2TokenID, hashedToken)
|
||||||
|
|
||||||
|
return s.persist(s.storeFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FileStore) DeleteTokenID2UserIDIndex(tokenID string) error {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
delete(s.TokenID2UserID, tokenID)
|
||||||
|
|
||||||
|
return s.persist(s.storeFile)
|
||||||
|
}
|
||||||
|
|
||||||
// GetAccountByPrivateDomain returns account by private domain
|
// GetAccountByPrivateDomain returns account by private domain
|
||||||
func (s *FileStore) GetAccountByPrivateDomain(domain string) (*Account, error) {
|
func (s *FileStore) GetAccountByPrivateDomain(domain string) (*Account, error) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
|
@ -249,7 +249,7 @@ func TestRestore(t *testing.T) {
|
|||||||
|
|
||||||
require.NotNil(t, account.SetupKeys["A2C8E62B-38F5-4553-B31E-DD66C696CEBB"], "failed to restore a FileStore file - missing Account SetupKey A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
require.NotNil(t, account.SetupKeys["A2C8E62B-38F5-4553-B31E-DD66C696CEBB"], "failed to restore a FileStore file - missing Account SetupKey A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
||||||
|
|
||||||
require.Len(t, account.Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs, 1, "failed to restore a FileStore wrong PATs length")
|
require.NotNil(t, account.Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"], "failed to restore a FileStore wrong PATs length")
|
||||||
|
|
||||||
require.Len(t, store.UserID2AccountID, 2, "failed to restore a FileStore wrong UserID2AccountID mapping length")
|
require.Len(t, store.UserID2AccountID, 2, "failed to restore a FileStore wrong UserID2AccountID mapping length")
|
||||||
|
|
||||||
@ -383,16 +383,34 @@ func TestFileStore_GetTokenIDByHashedToken(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedToken := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs[0].HashedToken
|
hashedToken := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"].HashedToken
|
||||||
tokenID, err := store.GetTokenIDByHashedToken(hashedToken)
|
tokenID, err := store.GetTokenIDByHashedToken(hashedToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedTokenID := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs[0].ID
|
expectedTokenID := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"].ID
|
||||||
assert.Equal(t, expectedTokenID, tokenID)
|
assert.Equal(t, expectedTokenID, tokenID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileStore_DeleteHashedPAT2TokenIDIndex(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
store.HashedPAT2TokenID["someHashedToken"] = "someTokenId"
|
||||||
|
|
||||||
|
store.DeleteHashedPAT2TokenIDIndex("someHashedToken")
|
||||||
|
|
||||||
|
assert.Empty(t, store.HashedPAT2TokenID["someHashedToken"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileStore_DeleteTokenID2UserIDIndex(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
store.TokenID2UserID["someTokenId"] = "someUserId"
|
||||||
|
|
||||||
|
store.DeleteTokenID2UserIDIndex("someTokenId")
|
||||||
|
|
||||||
|
assert.Empty(t, store.TokenID2UserID["someTokenId"])
|
||||||
|
}
|
||||||
|
|
||||||
func TestFileStore_GetTokenIDByHashedToken_Failure(t *testing.T) {
|
func TestFileStore_GetTokenIDByHashedToken_Failure(t *testing.T) {
|
||||||
storeDir := t.TempDir()
|
storeDir := t.TempDir()
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
storeFile := filepath.Join(storeDir, "store.json")
|
||||||
@ -437,7 +455,7 @@ func TestFileStore_GetUserByTokenID(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenID := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs[0].ID
|
tokenID := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"].ID
|
||||||
user, err := store.GetUserByTokenID(tokenID)
|
user, err := store.GetUserByTokenID(tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -11,6 +11,8 @@ type Store interface {
|
|||||||
GetTokenIDByHashedToken(secret string) (string, error)
|
GetTokenIDByHashedToken(secret string) (string, error)
|
||||||
GetUserByTokenID(tokenID string) (*User, error)
|
GetUserByTokenID(tokenID string) (*User, error)
|
||||||
SaveAccount(account *Account) error
|
SaveAccount(account *Account) error
|
||||||
|
DeleteHashedPAT2TokenIDIndex(hashedToken string) error
|
||||||
|
DeleteTokenID2UserIDIndex(tokenID string) error
|
||||||
GetInstallationID() string
|
GetInstallationID() string
|
||||||
SaveInstallationID(ID string) error
|
SaveInstallationID(ID string) error
|
||||||
// AcquireAccountLock should attempt to acquire account lock and return a function that releases the lock
|
// AcquireAccountLock should attempt to acquire account lock and return a function that releases the lock
|
||||||
|
9
management/server/testdata/store.json
vendored
9
management/server/testdata/store.json
vendored
@ -29,13 +29,14 @@
|
|||||||
"Users": {
|
"Users": {
|
||||||
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
||||||
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
||||||
"Role": "admin"
|
"Role": "admin",
|
||||||
|
"PATs": {}
|
||||||
},
|
},
|
||||||
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
||||||
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
||||||
"Role": "user",
|
"Role": "user",
|
||||||
"PATs":[
|
"PATs": {
|
||||||
{
|
"9dj38s35-63fb-11ec-90d6-0242ac120003": {
|
||||||
"ID":"9dj38s35-63fb-11ec-90d6-0242ac120003",
|
"ID":"9dj38s35-63fb-11ec-90d6-0242ac120003",
|
||||||
"Description":"some Description",
|
"Description":"some Description",
|
||||||
"HashedToken":"SoMeHaShEdToKeN",
|
"HashedToken":"SoMeHaShEdToKeN",
|
||||||
@ -44,7 +45,7 @@
|
|||||||
"CreatedAt":"2023-01-01T00:00:00Z",
|
"CreatedAt":"2023-01-01T00:00:00Z",
|
||||||
"LastUsed":"2023-02-01T00:00:00Z"
|
"LastUsed":"2023-02-01T00:00:00Z"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ type User struct {
|
|||||||
Role UserRole
|
Role UserRole
|
||||||
// AutoGroups is a list of Group IDs to auto-assign to peers registered by this user
|
// AutoGroups is a list of Group IDs to auto-assign to peers registered by this user
|
||||||
AutoGroups []string
|
AutoGroups []string
|
||||||
PATs []PersonalAccessToken
|
PATs map[string]*PersonalAccessToken
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAdmin returns true if user is an admin, false otherwise
|
// IsAdmin returns true if user is an admin, false otherwise
|
||||||
@ -94,8 +94,12 @@ func (u *User) toUserInfo(userData *idp.UserData) (*UserInfo, error) {
|
|||||||
func (u *User) Copy() *User {
|
func (u *User) Copy() *User {
|
||||||
autoGroups := make([]string, len(u.AutoGroups))
|
autoGroups := make([]string, len(u.AutoGroups))
|
||||||
copy(autoGroups, u.AutoGroups)
|
copy(autoGroups, u.AutoGroups)
|
||||||
pats := make([]PersonalAccessToken, len(u.PATs))
|
pats := make(map[string]*PersonalAccessToken, len(u.PATs))
|
||||||
copy(pats, u.PATs)
|
for k, v := range u.PATs {
|
||||||
|
patCopy := new(PersonalAccessToken)
|
||||||
|
*patCopy = *v
|
||||||
|
pats[k] = patCopy
|
||||||
|
}
|
||||||
return &User{
|
return &User{
|
||||||
Id: u.Id,
|
Id: u.Id,
|
||||||
Role: u.Role,
|
Role: u.Role,
|
||||||
@ -190,7 +194,7 @@ func (am *DefaultAccountManager) CreateUser(accountID, userID string, invite *Us
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddPATToUser takes the userID and the accountID the user belongs to and assigns a provided PersonalAccessToken to that user
|
// AddPATToUser takes the userID and the accountID the user belongs to and assigns a provided PersonalAccessToken to that user
|
||||||
func (am *DefaultAccountManager) AddPATToUser(accountID string, userID string, pat PersonalAccessToken) error {
|
func (am *DefaultAccountManager) AddPATToUser(accountID string, userID string, pat *PersonalAccessToken) error {
|
||||||
unlock := am.Store.AcquireAccountLock(accountID)
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
@ -204,7 +208,40 @@ func (am *DefaultAccountManager) AddPATToUser(accountID string, userID string, p
|
|||||||
return status.Errorf(status.NotFound, "user not found")
|
return status.Errorf(status.NotFound, "user not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
user.PATs = append(user.PATs, pat)
|
user.PATs[pat.ID] = pat
|
||||||
|
|
||||||
|
err = am.Store.SaveAccount(account)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *DefaultAccountManager) DeletePAT(accountID string, userID string, tokenID string) error {
|
||||||
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user := account.Users[userID]
|
||||||
|
if user == nil {
|
||||||
|
return status.Errorf(status.NotFound, "user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
pat := user.PATs["tokenID"]
|
||||||
|
if pat == nil {
|
||||||
|
return status.Errorf(status.NotFound, "PAT not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.Store.DeleteTokenID2UserIDIndex(pat.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = am.Store.DeleteHashedPAT2TokenIDIndex(pat.HashedToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delete(user.PATs, tokenID)
|
||||||
|
|
||||||
err = am.Store.SaveAccount(account)
|
err = am.Store.SaveAccount(account)
|
||||||
return err
|
return err
|
||||||
|
@ -51,7 +51,7 @@ func TestUser_AddPATToUser(t *testing.T) {
|
|||||||
LastUsed: time.Time{},
|
LastUsed: time.Time{},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = am.AddPATToUser("account_id", "testuser", pat)
|
err = am.AddPATToUser("account_id", "testuser", &pat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error when adding PAT to user: %s", err)
|
t.Fatalf("Error when adding PAT to user: %s", err)
|
||||||
}
|
}
|
||||||
@ -71,3 +71,60 @@ func TestUser_AddPATToUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.Equal(t, "testuser", userID)
|
assert.Equal(t, "testuser", userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUser_DeletePAT(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
account := newAccountWithId("account_id", "testuser", "")
|
||||||
|
account.Peers["testpeer"] = &Peer{
|
||||||
|
Key: "peerkey",
|
||||||
|
SetupKey: "peerkeysetupkey",
|
||||||
|
IP: net.IP{127, 0, 0, 1},
|
||||||
|
Meta: PeerSystemMeta{},
|
||||||
|
Name: "peer name",
|
||||||
|
Status: &PeerStatus{Connected: true, LastSeen: time.Now()},
|
||||||
|
}
|
||||||
|
account.Users["user1"] = &User{
|
||||||
|
Id: "user1",
|
||||||
|
Role: "admin",
|
||||||
|
AutoGroups: nil,
|
||||||
|
PATs: map[string]*PersonalAccessToken{
|
||||||
|
"tokenID": {
|
||||||
|
ID: "tokenID",
|
||||||
|
Description: "some Description",
|
||||||
|
HashedToken: "SoMeHaShEdToKeN",
|
||||||
|
ExpirationDate: time.Now().AddDate(0, 0, 7),
|
||||||
|
CreatedBy: "user1",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
LastUsed: time.Now(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error when saving account: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
am := DefaultAccountManager{
|
||||||
|
Store: store,
|
||||||
|
cacheMux: sync.Mutex{},
|
||||||
|
cacheLoading: nil,
|
||||||
|
peersUpdateManager: nil,
|
||||||
|
idpManager: nil,
|
||||||
|
cacheManager: nil,
|
||||||
|
ctx: nil,
|
||||||
|
eventStore: nil,
|
||||||
|
singleAccountMode: false,
|
||||||
|
singleAccountModeDomain: "",
|
||||||
|
dnsDomain: "",
|
||||||
|
peerLoginExpiry: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.DeletePAT("account_id", "user1", "tokenID")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error when adding PAT to user: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, store.Accounts["account_id"].Users["user1"].PATs["tokenID"])
|
||||||
|
assert.Empty(t, store.HashedPAT2TokenID["SoMeHaShEdToKeN"])
|
||||||
|
assert.Empty(t, store.TokenID2UserID["tokenID"])
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user