From 1a37b12d1ba22350bf010013699b307cc331a5e7 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Tue, 1 Oct 2024 00:55:32 +0300 Subject: [PATCH] refactor user PAT Signed-off-by: bcmmbaga --- management/server/personal_access_token.go | 3 +- management/server/user.go | 91 +++++++--------------- 2 files changed, 28 insertions(+), 66 deletions(-) diff --git a/management/server/personal_access_token.go b/management/server/personal_access_token.go index f46666112..47a5e13d7 100644 --- a/management/server/personal_access_token.go +++ b/management/server/personal_access_token.go @@ -58,7 +58,7 @@ type PersonalAccessTokenGenerated struct { // CreateNewPAT will generate a new PersonalAccessToken that can be assigned to a User. // Additionally, it will return the token in plain text once, to give to the user and only save a hashed version -func CreateNewPAT(name string, expirationInDays int, createdBy string) (*PersonalAccessTokenGenerated, error) { +func CreateNewPAT(name string, expirationInDays int, targetUserID, createdBy string) (*PersonalAccessTokenGenerated, error) { hashedToken, plainToken, err := generateNewToken() if err != nil { return nil, err @@ -67,6 +67,7 @@ func CreateNewPAT(name string, expirationInDays int, createdBy string) (*Persona return &PersonalAccessTokenGenerated{ PersonalAccessToken: PersonalAccessToken{ ID: xid.New().String(), + UserID: targetUserID, Name: name, HashedToken: hashedToken, ExpirationDate: currentTime.AddDate(0, 0, expirationInDays), diff --git a/management/server/user.go b/management/server/user.go index 6d01561c6..c36797f96 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -543,9 +543,6 @@ func (am *DefaultAccountManager) InviteUser(ctx context.Context, accountID strin // CreatePAT creates a new PAT for the given user func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*PersonalAccessTokenGenerated, error) { - unlock := am.Store.AcquireWriteLockByUID(ctx, accountID) - defer unlock() - if tokenName == "" { return nil, status.Errorf(status.InvalidArgument, "token name can't be empty") } @@ -554,35 +551,28 @@ func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string return nil, status.Errorf(status.InvalidArgument, "expiration has to be between 1 and 365") } - account, err := am.Store.GetAccount(ctx, accountID) + executingUser, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, initiatorUserID) if err != nil { return nil, err } - targetUser, ok := account.Users[targetUserID] - if !ok { - return nil, status.Errorf(status.NotFound, "user not found") + targetUser, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, targetUserID) + if err != nil { + return nil, err } - executingUser, ok := account.Users[initiatorUserID] - if !ok { - return nil, status.Errorf(status.NotFound, "user not found") - } - - if !(initiatorUserID == targetUserID || (executingUser.HasAdminPower() && targetUser.IsServiceUser)) { + if !(initiatorUserID == targetUserID || (executingUser.HasAdminPower() && targetUser.IsServiceUser)) || + executingUser.AccountID != accountID { return nil, status.Errorf(status.PermissionDenied, "no permission to create PAT for this user") } - pat, err := CreateNewPAT(tokenName, expiresIn, executingUser.Id) + pat, err := CreateNewPAT(tokenName, expiresIn, targetUser.Id, executingUser.Id) if err != nil { return nil, status.Errorf(status.Internal, "failed to create PAT: %v", err) } - targetUser.PATs[pat.ID] = &pat.PersonalAccessToken - - err = am.Store.SaveAccount(ctx, account) - if err != nil { - return nil, status.Errorf(status.Internal, "failed to save account: %v", err) + if err = am.Store.SavePAT(ctx, LockingStrengthUpdate, &pat.PersonalAccessToken); err != nil { + return nil, fmt.Errorf("failed to save PAT: %w", err) } meta := map[string]any{"name": pat.Name, "is_service_user": targetUser.IsServiceUser, "user_name": targetUser.ServiceUserName} @@ -593,51 +583,33 @@ func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string // DeletePAT deletes a specific PAT from a user func (am *DefaultAccountManager) DeletePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) error { - unlock := am.Store.AcquireWriteLockByUID(ctx, accountID) - defer unlock() - - account, err := am.Store.GetAccount(ctx, accountID) + executingUser, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, initiatorUserID) if err != nil { - return status.Errorf(status.NotFound, "account not found: %s", err) + return err } - targetUser, ok := account.Users[targetUserID] - if !ok { - return status.Errorf(status.NotFound, "user not found") + targetUser, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, targetUserID) + if err != nil { + return err } - executingUser, ok := account.Users[initiatorUserID] - if !ok { - return status.Errorf(status.NotFound, "user not found") - } - - if !(initiatorUserID == targetUserID || (executingUser.HasAdminPower() && targetUser.IsServiceUser)) { + if !(initiatorUserID == targetUserID || (executingUser.HasAdminPower() && targetUser.IsServiceUser)) || + executingUser.AccountID != accountID { return status.Errorf(status.PermissionDenied, "no permission to delete PAT for this user") } - pat := targetUser.PATs[tokenID] - if pat == nil { - return status.Errorf(status.NotFound, "PAT not found") + pat, err := am.Store.GetPATByID(ctx, LockingStrengthShare, tokenID, targetUserID) + if err != nil { + return err } - err = am.Store.DeleteTokenID2UserIDIndex(pat.ID) - if err != nil { - return status.Errorf(status.Internal, "Failed to delete token id index: %s", err) - } - err = am.Store.DeleteHashedPAT2TokenIDIndex(pat.HashedToken) - if err != nil { - return status.Errorf(status.Internal, "Failed to delete hashed token index: %s", err) + if err = am.Store.DeletePAT(ctx, LockingStrengthUpdate, tokenID, targetUserID); err != nil { + return fmt.Errorf("failed to delete PAT: %w", err) } meta := map[string]any{"name": pat.Name, "is_service_user": targetUser.IsServiceUser, "user_name": targetUser.ServiceUserName} am.StoreEvent(ctx, initiatorUserID, targetUserID, accountID, activity.PersonalAccessTokenDeleted, meta) - delete(targetUser.PATs, tokenID) - - err = am.Store.SaveAccount(ctx, account) - if err != nil { - return status.Errorf(status.Internal, "Failed to save account: %s", err) - } return nil } @@ -648,22 +620,11 @@ func (am *DefaultAccountManager) GetPAT(ctx context.Context, accountID string, i return nil, err } - targetUser, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, targetUserID) - if err != nil { - return nil, err - } - if (initiatorUserID != targetUserID && !initiatorUser.IsAdminOrServiceUser()) || initiatorUser.AccountID != accountID { return nil, status.Errorf(status.PermissionDenied, "no permission to get PAT for this user") } - for _, pat := range targetUser.PATsG { - if pat.ID == tokenID { - return pat.Copy(), nil - } - } - - return nil, status.Errorf(status.NotFound, "PAT not found") + return am.Store.GetPATByID(ctx, LockingStrengthShare, tokenID, targetUserID) } // GetAllPATs returns all PATs for a user @@ -673,15 +634,15 @@ func (am *DefaultAccountManager) GetAllPATs(ctx context.Context, accountID strin return nil, err } + if (initiatorUserID != targetUserID && !initiatorUser.IsAdminOrServiceUser()) || initiatorUser.AccountID != accountID { + return nil, status.Errorf(status.PermissionDenied, "no permission to get PAT for this user") + } + targetUser, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, targetUserID) if err != nil { return nil, err } - if (initiatorUserID != targetUserID && !initiatorUser.IsAdminOrServiceUser()) || initiatorUser.AccountID != accountID { - return nil, status.Errorf(status.PermissionDenied, "no permission to get PAT for this user") - } - pats := make([]*PersonalAccessToken, 0, len(targetUser.PATsG)) for _, pat := range targetUser.PATsG { pats = append(pats, pat.Copy())