mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
[management] permission manager validate account access (#3444)
This commit is contained in:
@@ -30,8 +30,8 @@ func (am *DefaultAccountManager) createServiceUser(ctx context.Context, accountI
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !initiatorUser.HasAdminPower() {
|
||||
@@ -93,8 +93,8 @@ func (am *DefaultAccountManager) inviteNewUser(ctx context.Context, accountID, u
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inviterID := userID
|
||||
@@ -142,12 +142,21 @@ func (am *DefaultAccountManager) inviteNewUser(ctx context.Context, accountID, u
|
||||
|
||||
// createNewIdpUser validates the invite and creates a new user in the IdP
|
||||
func (am *DefaultAccountManager) createNewIdpUser(ctx context.Context, accountID string, inviterID string, invite *types.UserInfo) (*idp.UserData, error) {
|
||||
inviter, err := am.GetUserByID(ctx, inviterID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get inviter user: %w", err)
|
||||
}
|
||||
|
||||
// inviterUser is the one who is inviting the new user
|
||||
inviterUser, err := am.lookupUserInCache(ctx, inviterID, accountID)
|
||||
inviterUser, err := am.lookupUserInCache(ctx, inviterID, inviter.AccountID)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(status.NotFound, "inviter user with ID %s doesn't exist in IdP", inviterID)
|
||||
}
|
||||
|
||||
if inviterUser == nil {
|
||||
return nil, status.Errorf(status.NotFound, "inviter user with ID %s is empty", inviterID)
|
||||
}
|
||||
|
||||
// check if the user is already registered with this email => reject
|
||||
user, err := am.lookupUserInCacheByEmail(ctx, invite.Email, accountID)
|
||||
if err != nil {
|
||||
@@ -188,7 +197,7 @@ func (am *DefaultAccountManager) GetUserFromUserAuth(ctx context.Context, userAu
|
||||
|
||||
err = am.Store.SaveUserLastLogin(ctx, userAuth.AccountId, userAuth.UserId, userAuth.LastLogin)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed saving user last login: %v", err)
|
||||
log.WithContext(ctx).Debugf("failed to update user last login: %v", err)
|
||||
}
|
||||
|
||||
if newLogin {
|
||||
@@ -228,8 +237,8 @@ func (am *DefaultAccountManager) DeleteUser(ctx context.Context, accountID, init
|
||||
return err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !initiatorUser.HasAdminPower() {
|
||||
@@ -290,8 +299,8 @@ func (am *DefaultAccountManager) InviteUser(ctx context.Context, accountID strin
|
||||
return err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if the user is already registered with this ID
|
||||
@@ -338,8 +347,8 @@ func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
targetUser, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, targetUserID)
|
||||
@@ -376,8 +385,8 @@ func (am *DefaultAccountManager) DeletePAT(ctx context.Context, accountID string
|
||||
return err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if initiatorUserID != targetUserID && initiatorUser.IsRegularUser() {
|
||||
@@ -411,8 +420,8 @@ func (am *DefaultAccountManager) GetPAT(ctx context.Context, accountID string, i
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUserID != targetUserID && initiatorUser.IsRegularUser() {
|
||||
@@ -429,8 +438,8 @@ func (am *DefaultAccountManager) GetAllPATs(ctx context.Context, accountID strin
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUserID != targetUserID && initiatorUser.IsRegularUser() {
|
||||
@@ -476,8 +485,8 @@ func (am *DefaultAccountManager) SaveOrAddUsers(ctx context.Context, accountID,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !initiatorUser.HasAdminPower() || initiatorUser.IsBlocked() {
|
||||
@@ -511,7 +520,7 @@ func (am *DefaultAccountManager) SaveOrAddUsers(ctx context.Context, accountID,
|
||||
}
|
||||
|
||||
userHadPeers, updatedUser, userPeersToExpire, userEvents, err := am.processUserUpdate(
|
||||
ctx, transaction, groupsMap, initiatorUser, update, addIfNotExists, settings,
|
||||
ctx, transaction, groupsMap, accountID, initiatorUser, update, addIfNotExists, settings,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to process user update: %w", err)
|
||||
@@ -597,13 +606,13 @@ func (am *DefaultAccountManager) prepareUserUpdateEvents(ctx context.Context, ac
|
||||
}
|
||||
|
||||
func (am *DefaultAccountManager) processUserUpdate(ctx context.Context, transaction store.Store, groupsMap map[string]*types.Group,
|
||||
initiatorUser, update *types.User, addIfNotExists bool, settings *types.Settings) (bool, *types.User, []*nbpeer.Peer, []func(), error) {
|
||||
accountID string, initiatorUser, update *types.User, addIfNotExists bool, settings *types.Settings) (bool, *types.User, []*nbpeer.Peer, []func(), error) {
|
||||
|
||||
if update == nil {
|
||||
return false, nil, nil, nil, status.Errorf(status.InvalidArgument, "provided user update is nil")
|
||||
}
|
||||
|
||||
oldUser, err := getUserOrCreateIfNotExists(ctx, transaction, update, addIfNotExists)
|
||||
oldUser, err := getUserOrCreateIfNotExists(ctx, transaction, accountID, update, addIfNotExists)
|
||||
if err != nil {
|
||||
return false, nil, nil, nil, err
|
||||
}
|
||||
@@ -614,7 +623,6 @@ func (am *DefaultAccountManager) processUserUpdate(ctx context.Context, transact
|
||||
|
||||
// only auto groups, revoked status, and integration reference can be updated for now
|
||||
updatedUser := oldUser.Copy()
|
||||
updatedUser.AccountID = initiatorUser.AccountID
|
||||
updatedUser.Role = update.Role
|
||||
updatedUser.Blocked = update.Blocked
|
||||
updatedUser.AutoGroups = update.AutoGroups
|
||||
@@ -657,17 +665,23 @@ func (am *DefaultAccountManager) processUserUpdate(ctx context.Context, transact
|
||||
}
|
||||
|
||||
// getUserOrCreateIfNotExists retrieves the existing user or creates a new one if it doesn't exist.
|
||||
func getUserOrCreateIfNotExists(ctx context.Context, transaction store.Store, update *types.User, addIfNotExists bool) (*types.User, error) {
|
||||
func getUserOrCreateIfNotExists(ctx context.Context, transaction store.Store, accountID string, update *types.User, addIfNotExists bool) (*types.User, error) {
|
||||
existingUser, err := transaction.GetUserByUserID(ctx, store.LockingStrengthShare, update.Id)
|
||||
if err != nil {
|
||||
if sErr, ok := status.FromError(err); ok && sErr.Type() == status.NotFound {
|
||||
if !addIfNotExists {
|
||||
return nil, status.Errorf(status.NotFound, "user to update doesn't exist: %s", update.Id)
|
||||
}
|
||||
update.AccountID = accountID
|
||||
return update, nil // use all fields from update if addIfNotExists is true
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingUser.AccountID != accountID {
|
||||
return nil, status.Errorf(status.InvalidArgument, "user account ID mismatch")
|
||||
}
|
||||
|
||||
return existingUser, nil
|
||||
}
|
||||
|
||||
@@ -705,6 +719,7 @@ func (am *DefaultAccountManager) getUserInfo(ctx context.Context, user *types.Us
|
||||
|
||||
// validateUserUpdate validates the update operation for a user.
|
||||
func validateUserUpdate(groupsMap map[string]*types.Group, initiatorUser, oldUser, update *types.User) error {
|
||||
// @todo double check these
|
||||
if initiatorUser.HasAdminPower() && initiatorUser.Id == update.Id && oldUser.Blocked != update.Blocked {
|
||||
return status.Errorf(status.PermissionDenied, "admins can't block or unblock themselves")
|
||||
}
|
||||
@@ -790,8 +805,8 @@ func (am *DefaultAccountManager) GetUsersFromAccount(ctx context.Context, accoun
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if initiatorUser.AccountID != accountID {
|
||||
return nil, status.NewUserNotPartOfAccountError()
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return am.BuildUserInfosForAccount(ctx, accountID, initiatorUserID, accountUsers)
|
||||
@@ -967,6 +982,10 @@ func (am *DefaultAccountManager) DeleteRegularUsers(ctx context.Context, account
|
||||
return err
|
||||
}
|
||||
|
||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !initiatorUser.HasAdminPower() {
|
||||
return status.NewAdminPermissionError()
|
||||
}
|
||||
@@ -1081,6 +1100,25 @@ func (am *DefaultAccountManager) deleteRegularUser(ctx context.Context, accountI
|
||||
return updateAccountPeers, nil
|
||||
}
|
||||
|
||||
// GetOwnerInfo retrieves the owner information for a given account ID.
|
||||
func (am *DefaultAccountManager) GetOwnerInfo(ctx context.Context, accountID string) (*types.UserInfo, error) {
|
||||
owner, err := am.Store.GetAccountOwner(ctx, store.LockingStrengthShare, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if owner == nil {
|
||||
return nil, status.Errorf(status.NotFound, "owner not found")
|
||||
}
|
||||
|
||||
userInfo, err := am.getUserInfo(ctx, owner, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
// updateUserPeersInGroups updates the user's peers in the specified groups by adding or removing them.
|
||||
func updateUserPeersInGroups(accountGroups map[string]*types.Group, peers []*nbpeer.Peer, groupsToAdd, groupsToRemove []string) (groupsToUpdate []*types.Group, err error) {
|
||||
if len(groupsToAdd) == 0 && len(groupsToRemove) == 0 {
|
||||
|
||||
Reference in New Issue
Block a user