diff --git a/management/server/account.go b/management/server/account.go index e2cdf40b2..0a1fbc4ed 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -68,8 +68,10 @@ type AccountManager interface { GetNetworkMap(peerID string) (*NetworkMap, error) GetPeerNetwork(peerID string) (*Network, 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 + CreatePAT(accountID string, executingUserID string, targetUserId string, tokenName string, expiresIn int) (*PersonalAccessTokenGenerated, error) + DeletePAT(accountID string, executingUserID string, targetUserId string, tokenID string) error + GetPAT(accountID string, executingUserID string, targetUserId string, tokenID string) (*PersonalAccessToken, error) + GetAllPATs(accountID string, executingUserID string, targetUserId string) ([]*PersonalAccessToken, error) UpdatePeerSSHKey(peerID string, sshKey string) error GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error) GetGroup(accountId, groupID string) (*Group, error) diff --git a/management/server/http/pat_handler.go b/management/server/http/pat_handler.go index d3e8b9ac5..d2398a7e1 100644 --- a/management/server/http/pat_handler.go +++ b/management/server/http/pat_handler.go @@ -46,17 +46,19 @@ func (h *PATHandler) GetAllTokens(w http.ResponseWriter, r *http.Request) { util.WriteError(status.Errorf(status.InvalidArgument, "invalid user ID"), w) return } - if userID != user.Id { - util.WriteErrorResponse("User not authorized to get tokens", http.StatusUnauthorized, w) + + pats, err := h.accountManager.GetAllPATs(account.Id, user.Id, userID) + if err != nil { + util.WriteError(err, w) return } - var pats []*api.PersonalAccessToken - for _, pat := range account.Users[userID].PATs { - pats = append(pats, toPATResponse(pat)) + var patResponse []*api.PersonalAccessToken + for _, pat := range pats { + patResponse = append(patResponse, toPATResponse(pat)) } - util.WriteJSONObject(w, pats) + util.WriteJSONObject(w, patResponse) } // GetToken is HTTP GET handler that returns a personal access token for the given user @@ -69,15 +71,11 @@ func (h *PATHandler) GetToken(w http.ResponseWriter, r *http.Request) { } vars := mux.Vars(r) - userID := vars["userId"] - if len(userID) == 0 { + targetUserID := vars["userId"] + if len(targetUserID) == 0 { util.WriteError(status.Errorf(status.InvalidArgument, "invalid user ID"), w) return } - if userID != user.Id { - util.WriteErrorResponse("User not authorized to get token", http.StatusUnauthorized, w) - return - } tokenID := vars["tokenId"] if len(tokenID) == 0 { @@ -85,15 +83,9 @@ func (h *PATHandler) GetToken(w http.ResponseWriter, r *http.Request) { return } - user = account.Users[userID] - if user == nil { - util.WriteError(status.Errorf(status.NotFound, "user not found"), w) - return - } - - pat := user.PATs[tokenID] - if pat == nil { - util.WriteError(status.Errorf(status.NotFound, "PAT not found"), w) + pat, err := h.accountManager.GetPAT(account.Id, user.Id, targetUserID, tokenID) + if err != nil { + util.WriteError(err, w) return } @@ -110,15 +102,11 @@ func (h *PATHandler) CreateToken(w http.ResponseWriter, r *http.Request) { } vars := mux.Vars(r) - userID := vars["userId"] - if len(userID) == 0 { + targetUserID := vars["userId"] + if len(targetUserID) == 0 { util.WriteError(status.Errorf(status.InvalidArgument, "invalid user ID"), w) return } - if userID != user.Id { - util.WriteErrorResponse("User not authorized to create token", http.StatusUnauthorized, w) - return - } var req api.PostApiUsersUserIdTokensJSONRequestBody err = json.NewDecoder(r.Body).Decode(&req) @@ -127,23 +115,7 @@ func (h *PATHandler) CreateToken(w http.ResponseWriter, r *http.Request) { return } - if req.Name == "" { - util.WriteErrorResponse("name can't be empty", http.StatusBadRequest, w) - return - } - - if req.ExpiresIn < 1 || req.ExpiresIn > 365 { - util.WriteErrorResponse("expiration has to be between 1 and 365", http.StatusBadRequest, w) - return - } - - pat, err := server.CreateNewPAT(req.Name, req.ExpiresIn, user.Id) - if err != nil { - util.WriteError(err, w) - return - } - - err = h.accountManager.AddPATToUser(account.Id, userID, &pat.PersonalAccessToken) + pat, err := h.accountManager.CreatePAT(account.Id, user.Id, targetUserID, req.Name, req.ExpiresIn) if err != nil { util.WriteError(err, w) return @@ -162,15 +134,11 @@ func (h *PATHandler) DeleteToken(w http.ResponseWriter, r *http.Request) { } vars := mux.Vars(r) - userID := vars["userId"] - if len(userID) == 0 { + targetUserID := vars["userId"] + if len(targetUserID) == 0 { util.WriteError(status.Errorf(status.InvalidArgument, "invalid user ID"), w) return } - if userID != user.Id { - util.WriteErrorResponse("User not authorized to delete token", http.StatusUnauthorized, w) - return - } tokenID := vars["tokenId"] if len(tokenID) == 0 { @@ -178,7 +146,7 @@ func (h *PATHandler) DeleteToken(w http.ResponseWriter, r *http.Request) { return } - err = h.accountManager.DeletePAT(account.Id, userID, tokenID) + err = h.accountManager.DeletePAT(account.Id, user.Id, targetUserID, tokenID) if err != nil { util.WriteError(err, w) return diff --git a/management/server/http/pat_handler_test.go b/management/server/http/pat_handler_test.go index 7b83c5db8..de79f1006 100644 --- a/management/server/http/pat_handler_test.go +++ b/management/server/http/pat_handler_test.go @@ -63,31 +63,55 @@ var testAccount = &server.Account{ func initPATTestData() *PATHandler { return &PATHandler{ accountManager: &mock_server.MockAccountManager{ - AddPATToUserFunc: func(accountID string, userID string, pat *server.PersonalAccessToken) error { + CreatePATFunc: func(accountID string, executingUserID string, targetUserID string, tokenName string, expiresIn int) (*server.PersonalAccessTokenGenerated, error) { if accountID != existingAccountID { - return status.Errorf(status.NotFound, "account with ID %s not found", accountID) + return nil, status.Errorf(status.NotFound, "account with ID %s not found", accountID) } - if userID != existingUserID { - return status.Errorf(status.NotFound, "user with ID %s not found", userID) + if targetUserID != existingUserID { + return nil, status.Errorf(status.NotFound, "user with ID %s not found", targetUserID) } - return nil + return &server.PersonalAccessTokenGenerated{ + PlainToken: "nbp_z1pvsg2wP3EzmEou4S679KyTNhov632eyrXe", + PersonalAccessToken: server.PersonalAccessToken{}, + }, nil }, GetAccountFromTokenFunc: func(_ jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error) { return testAccount, testAccount.Users[existingUserID], nil }, - DeletePATFunc: func(accountID string, userID string, tokenID string) error { + DeletePATFunc: func(accountID string, executingUserID string, targetUserID string, tokenID string) error { if accountID != existingAccountID { return status.Errorf(status.NotFound, "account with ID %s not found", accountID) } - if userID != existingUserID { - return status.Errorf(status.NotFound, "user with ID %s not found", userID) + if targetUserID != existingUserID { + return status.Errorf(status.NotFound, "user with ID %s not found", targetUserID) } if tokenID != existingTokenID { return status.Errorf(status.NotFound, "token with ID %s not found", tokenID) } return nil }, + GetPATFunc: func(accountID string, executingUserID string, targetUserID string, tokenID string) (*server.PersonalAccessToken, error) { + if accountID != existingAccountID { + return nil, status.Errorf(status.NotFound, "account with ID %s not found", accountID) + } + if targetUserID != existingUserID { + return nil, status.Errorf(status.NotFound, "user with ID %s not found", targetUserID) + } + if tokenID != existingTokenID { + return nil, status.Errorf(status.NotFound, "token with ID %s not found", tokenID) + } + return testAccount.Users[existingUserID].PATs[existingTokenID], nil + }, + GetAllPATsFunc: func(accountID string, executingUserID string, targetUserID string) ([]*server.PersonalAccessToken, error) { + if accountID != existingAccountID { + return nil, status.Errorf(status.NotFound, "account with ID %s not found", accountID) + } + if targetUserID != existingUserID { + return nil, status.Errorf(status.NotFound, "user with ID %s not found", targetUserID) + } + return []*server.PersonalAccessToken{testAccount.Users[existingUserID].PATs[existingTokenID], testAccount.Users[existingUserID].PATs["token2"]}, nil + }, }, claimsExtractor: jwtclaims.NewClaimsExtractor( jwtclaims.WithFromRequestContext(func(r *http.Request) jwtclaims.AuthorizationClaims { diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index c91201344..eb473d03c 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -61,8 +61,10 @@ type MockAccountManager struct { SaveSetupKeyFunc func(accountID string, key *server.SetupKey, userID string) (*server.SetupKey, error) ListSetupKeysFunc func(accountID, userID string) ([]*server.SetupKey, error) SaveUserFunc func(accountID, userID string, user *server.User) (*server.UserInfo, error) - AddPATToUserFunc func(accountID string, userID string, pat *server.PersonalAccessToken) error - DeletePATFunc func(accountID string, userID string, tokenID string) error + CreatePATFunc func(accountID string, executingUserID string, targetUserId string, tokenName string, expiresIn int) (*server.PersonalAccessTokenGenerated, error) + DeletePATFunc func(accountID string, executingUserID string, targetUserId string, tokenID string) error + GetPATFunc func(accountID string, executingUserID string, targetUserId string, tokenID string) (*server.PersonalAccessToken, error) + GetAllPATsFunc func(accountID string, executingUserID string, targetUserId string) ([]*server.PersonalAccessToken, error) GetNameServerGroupFunc func(accountID, nsGroupID string) (*nbdns.NameServerGroup, error) CreateNameServerGroupFunc func(accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string) (*nbdns.NameServerGroup, error) SaveNameServerGroupFunc func(accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error @@ -195,22 +197,38 @@ func (am *MockAccountManager) MarkPATUsed(pat string) error { return status.Errorf(codes.Unimplemented, "method MarkPATUsed is not implemented") } -// AddPATToUser mock implementation of AddPATToUser from server.AccountManager interface -func (am *MockAccountManager) AddPATToUser(accountID string, userID string, pat *server.PersonalAccessToken) error { - if am.AddPATToUserFunc != nil { - return am.AddPATToUserFunc(accountID, userID, pat) +// CreatePAT mock implementation of GetPAT from server.AccountManager interface +func (am *MockAccountManager) CreatePAT(accountID string, executingUserID string, targetUserID string, name string, expiresIn int) (*server.PersonalAccessTokenGenerated, error) { + if am.CreatePATFunc != nil { + return am.CreatePATFunc(accountID, executingUserID, targetUserID, name, expiresIn) } - return status.Errorf(codes.Unimplemented, "method AddPATToUser is not implemented") + return nil, status.Errorf(codes.Unimplemented, "method CreatePAT is not implemented") } // DeletePAT mock implementation of DeletePAT from server.AccountManager interface -func (am *MockAccountManager) DeletePAT(accountID string, userID string, tokenID string) error { +func (am *MockAccountManager) DeletePAT(accountID string, executingUserID string, targetUserID string, tokenID string) error { if am.DeletePATFunc != nil { - return am.DeletePATFunc(accountID, userID, tokenID) + return am.DeletePATFunc(accountID, executingUserID, targetUserID, tokenID) } return status.Errorf(codes.Unimplemented, "method DeletePAT is not implemented") } +// GetPAT mock implementation of GetPAT from server.AccountManager interface +func (am *MockAccountManager) GetPAT(accountID string, executingUserID string, targetUserID string, tokenID string) (*server.PersonalAccessToken, error) { + if am.GetPATFunc != nil { + return am.GetPATFunc(accountID, executingUserID, targetUserID, tokenID) + } + return nil, status.Errorf(codes.Unimplemented, "method GetPAT is not implemented") +} + +// GetAllPATs mock implementation of GetAllPATs from server.AccountManager interface +func (am *MockAccountManager) GetAllPATs(accountID string, executingUserID string, targetUserID string) ([]*server.PersonalAccessToken, error) { + if am.GetAllPATsFunc != nil { + return am.GetAllPATsFunc(accountID, executingUserID, targetUserID) + } + return nil, status.Errorf(codes.Unimplemented, "method GetAllPATs is not implemented") +} + // GetNetworkMap mock implementation of GetNetworkMap from server.AccountManager interface func (am *MockAccountManager) GetNetworkMap(peerKey string) (*server.NetworkMap, error) { if am.GetNetworkMapFunc != nil { diff --git a/management/server/user.go b/management/server/user.go index 572843fff..97e9cd0c7 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -193,37 +193,63 @@ 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 -func (am *DefaultAccountManager) AddPATToUser(accountID string, userID string, pat *PersonalAccessToken) error { +// CreatePAT creates a new PAT for the given user +func (am *DefaultAccountManager) CreatePAT(accountID string, executingUserID string, targetUserId string, tokenName string, expiresIn int) (*PersonalAccessTokenGenerated, error) { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() + if tokenName == "" { + return nil, status.Errorf(status.InvalidArgument, "token name can't be empty") + } + + if expiresIn < 1 || expiresIn > 365 { + return nil, status.Errorf(status.InvalidArgument, "expiration has to be between 1 and 365") + } + + if executingUserID != targetUserId { + return nil, status.Errorf(status.PermissionDenied, "no permission to create PAT for this user") + } + account, err := am.Store.GetAccount(accountID) if err != nil { - return err + return nil, err } - user := account.Users[userID] - if user == nil { - return status.Errorf(status.NotFound, "user not found") + targetUser := account.Users[targetUserId] + if targetUser == nil { + return nil, status.Errorf(status.NotFound, "targetUser not found") } - user.PATs[pat.ID] = pat + pat, err := CreateNewPAT(tokenName, expiresIn, targetUser.Id) + if err != nil { + return nil, status.Errorf(status.Internal, "failed to create PAT: %v", err) + } - return am.Store.SaveAccount(account) + targetUser.PATs[pat.ID] = &pat.PersonalAccessToken + + err = am.Store.SaveAccount(account) + if err != nil { + return nil, status.Errorf(status.Internal, "failed to save account: %v", err) + } + + return pat, nil } // DeletePAT deletes a specific PAT from a user -func (am *DefaultAccountManager) DeletePAT(accountID string, userID string, tokenID string) error { +func (am *DefaultAccountManager) DeletePAT(accountID string, executingUserID string, targetUserID string, tokenID string) error { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() - account, err := am.Store.GetAccount(accountID) - if err != nil { - return err + if executingUserID != targetUserID { + return status.Errorf(status.PermissionDenied, "no permission to delete PAT for this user") } - user := account.Users[userID] + account, err := am.Store.GetAccount(accountID) + if err != nil { + return status.Errorf(status.NotFound, "account not found: %s", err) + } + + user := account.Users[targetUserID] if user == nil { return status.Errorf(status.NotFound, "user not found") } @@ -235,15 +261,73 @@ func (am *DefaultAccountManager) DeletePAT(accountID string, userID string, toke err = am.Store.DeleteTokenID2UserIDIndex(pat.ID) if err != nil { - return err + return status.Errorf(status.Internal, "Failed to delete token id index: %s", err) } err = am.Store.DeleteHashedPAT2TokenIDIndex(pat.HashedToken) if err != nil { - return err + return status.Errorf(status.Internal, "Failed to delete hashed token index: %s", err) } delete(user.PATs, tokenID) - return am.Store.SaveAccount(account) + err = am.Store.SaveAccount(account) + if err != nil { + return status.Errorf(status.Internal, "Failed to save account: %s", err) + } + return nil +} + +// GetPAT returns a specific PAT from a user +func (am *DefaultAccountManager) GetPAT(accountID string, executingUserID string, targetUserID string, tokenID string) (*PersonalAccessToken, error) { + unlock := am.Store.AcquireAccountLock(accountID) + defer unlock() + + if executingUserID != targetUserID { + return nil, status.Errorf(status.PermissionDenied, "no permission to get PAT for this user") + } + + account, err := am.Store.GetAccount(accountID) + if err != nil { + return nil, status.Errorf(status.NotFound, "account not found: %s", err) + } + + user := account.Users[targetUserID] + if user == nil { + return nil, status.Errorf(status.NotFound, "user not found") + } + + pat := user.PATs[tokenID] + if pat == nil { + return nil, status.Errorf(status.NotFound, "PAT not found") + } + + return pat, nil +} + +// GetAllPATs returns all PATs for a user +func (am *DefaultAccountManager) GetAllPATs(accountID string, executingUserID string, targetUserID string) ([]*PersonalAccessToken, error) { + unlock := am.Store.AcquireAccountLock(accountID) + defer unlock() + + if executingUserID != targetUserID { + return nil, status.Errorf(status.PermissionDenied, "no permission to get PAT for this user") + } + + account, err := am.Store.GetAccount(accountID) + if err != nil { + return nil, status.Errorf(status.NotFound, "account not found: %s", err) + } + + user := account.Users[targetUserID] + if user == nil { + return nil, status.Errorf(status.NotFound, "user not found") + } + + var pats []*PersonalAccessToken + for _, pat := range user.PATs { + pats = append(pats, pat) + } + + return pats, nil } // SaveUser saves updates a given user. If the user doesn't exit it will throw status.NotFound error. diff --git a/management/server/user_test.go b/management/server/user_test.go index ffbb71282..1dd12e57b 100644 --- a/management/server/user_test.go +++ b/management/server/user_test.go @@ -7,13 +7,20 @@ import ( ) const ( - mockAccountID = "accountID" - mockUserID = "userID" - mockTokenID = "tokenID" - mockToken = "SoMeHaShEdToKeN" + mockAccountID = "accountID" + mockUserID = "userID" + mockTargetUserId = "targetUserID" + mockTokenID1 = "tokenID1" + mockToken1 = "SoMeHaShEdToKeN1" + mockTokenID2 = "tokenID2" + mockToken2 = "SoMeHaShEdToKeN2" + mockTokenName = "tokenName" + mockEmptyTokenName = "" + mockExpiresIn = 7 + mockWrongExpiresIn = 4506 ) -func TestUser_AddPATToUser(t *testing.T) { +func TestUser_CreatePAT_ForSameUser(t *testing.T) { store := newStore(t) account := newAccountWithId(mockAccountID, mockUserID, "") @@ -26,24 +33,19 @@ func TestUser_AddPATToUser(t *testing.T) { Store: store, } - pat := PersonalAccessToken{ - ID: mockTokenID, - HashedToken: mockToken, - } - - err = am.AddPATToUser(mockAccountID, mockUserID, &pat) + pat, err := am.CreatePAT(mockAccountID, mockUserID, mockUserID, mockTokenName, mockExpiresIn) if err != nil { t.Fatalf("Error when adding PAT to user: %s", err) } fileStore := am.Store.(*FileStore) - tokenID := fileStore.HashedPAT2TokenID[mockToken] + tokenID := fileStore.HashedPAT2TokenID[pat.HashedToken] if tokenID == "" { t.Fatal("GetTokenIDByHashedToken failed after adding PAT") } - assert.Equal(t, mockTokenID, tokenID) + assert.Equal(t, pat.ID, tokenID) userID := fileStore.TokenID2UserID[tokenID] if userID == "" { @@ -52,15 +54,66 @@ func TestUser_AddPATToUser(t *testing.T) { assert.Equal(t, mockUserID, userID) } +func TestUser_CreatePAT_ForDifferentUser(t *testing.T) { + store := newStore(t) + account := newAccountWithId(mockAccountID, mockUserID, "") + + err := store.SaveAccount(account) + if err != nil { + t.Fatalf("Error when saving account: %s", err) + } + + am := DefaultAccountManager{ + Store: store, + } + + _, err = am.CreatePAT(mockAccountID, mockUserID, mockTargetUserId, mockTokenName, mockExpiresIn) + assert.Errorf(t, err, "Creating PAT for different user should thorw error") +} + +func TestUser_CreatePAT_WithWrongExpiration(t *testing.T) { + store := newStore(t) + account := newAccountWithId(mockAccountID, mockUserID, "") + + err := store.SaveAccount(account) + if err != nil { + t.Fatalf("Error when saving account: %s", err) + } + + am := DefaultAccountManager{ + Store: store, + } + + _, err = am.CreatePAT(mockAccountID, mockUserID, mockUserID, mockTokenName, mockWrongExpiresIn) + assert.Errorf(t, err, "Wrong expiration should thorw error") +} + +func TestUser_CreatePAT_WithEmptyName(t *testing.T) { + store := newStore(t) + account := newAccountWithId(mockAccountID, mockUserID, "") + + err := store.SaveAccount(account) + if err != nil { + t.Fatalf("Error when saving account: %s", err) + } + + am := DefaultAccountManager{ + Store: store, + } + + _, err = am.CreatePAT(mockAccountID, mockUserID, mockUserID, mockEmptyTokenName, mockExpiresIn) + assert.Errorf(t, err, "Wrong expiration should thorw error") +} + func TestUser_DeletePAT(t *testing.T) { store := newStore(t) account := newAccountWithId(mockAccountID, mockUserID, "") account.Users[mockUserID] = &User{ Id: mockUserID, PATs: map[string]*PersonalAccessToken{ - mockTokenID: { - ID: mockTokenID, - HashedToken: mockToken, + mockTokenID1: { + ID: mockTokenID1, + HashedToken: mockToken1, }, }, } @@ -73,12 +126,79 @@ func TestUser_DeletePAT(t *testing.T) { Store: store, } - err = am.DeletePAT(mockAccountID, mockUserID, mockTokenID) + err = am.DeletePAT(mockAccountID, mockUserID, mockUserID, mockTokenID1) if err != nil { t.Fatalf("Error when adding PAT to user: %s", err) } - assert.Nil(t, store.Accounts[mockAccountID].Users[mockUserID].PATs[mockTokenID]) - assert.Empty(t, store.HashedPAT2TokenID[mockToken]) - assert.Empty(t, store.TokenID2UserID[mockTokenID]) + assert.Nil(t, store.Accounts[mockAccountID].Users[mockUserID].PATs[mockTokenID1]) + assert.Empty(t, store.HashedPAT2TokenID[mockToken1]) + assert.Empty(t, store.TokenID2UserID[mockTokenID1]) +} + +func TestUser_GetPAT(t *testing.T) { + store := newStore(t) + account := newAccountWithId(mockAccountID, mockUserID, "") + account.Users[mockUserID] = &User{ + Id: mockUserID, + PATs: map[string]*PersonalAccessToken{ + mockTokenID1: { + ID: mockTokenID1, + HashedToken: mockToken1, + }, + }, + } + err := store.SaveAccount(account) + if err != nil { + t.Fatalf("Error when saving account: %s", err) + } + + am := DefaultAccountManager{ + Store: store, + } + + pat, err := am.GetPAT(mockAccountID, mockUserID, mockUserID, mockTokenID1) + if err != nil { + t.Fatalf("Error when adding PAT to user: %s", err) + } + + assert.Equal(t, mockTokenID1, pat.ID) + assert.Equal(t, mockToken1, pat.HashedToken) +} + +func TestUser_GetAllPATs(t *testing.T) { + store := newStore(t) + account := newAccountWithId(mockAccountID, mockUserID, "") + account.Users[mockUserID] = &User{ + Id: mockUserID, + PATs: map[string]*PersonalAccessToken{ + mockTokenID1: { + ID: mockTokenID1, + HashedToken: mockToken1, + }, + mockTokenID2: { + ID: mockTokenID2, + HashedToken: mockToken2, + }, + }, + } + err := store.SaveAccount(account) + if err != nil { + t.Fatalf("Error when saving account: %s", err) + } + + am := DefaultAccountManager{ + Store: store, + } + + pats, err := am.GetAllPATs(mockAccountID, mockUserID, mockUserID) + if err != nil { + t.Fatalf("Error when adding PAT to user: %s", err) + } + + assert.Equal(t, 2, len(pats)) + assert.Equal(t, mockTokenID1, pats[0].ID) + assert.Equal(t, mockToken1, pats[0].HashedToken) + assert.Equal(t, mockTokenID2, pats[1].ID) + assert.Equal(t, mockToken2, pats[1].HashedToken) }