@@ -39,9 +39,6 @@ func (r *Repository) AddRoleGrantScopes(ctx context.Context, roleId string, role
3939	if  err  !=  nil  {
4040		return  nil , errors .Wrap (ctx , err , op , errors .WithMsg (fmt .Sprintf ("unable to get role %s scope id" , roleId )))
4141	}
42- 	if  scp .Type  ==  scope .Project .String () {
43- 		return  nil , errors .New (ctx , errors .InvalidParameter , op , "grant scope cannot be added to project roles" )
44- 	}
4542
4643	// Find existing grant scopes to find duplicate grants 
4744	originalGrantScopes , err  :=  listRoleGrantScopes (ctx , r .reader , []string {roleId })
@@ -99,15 +96,22 @@ func (r *Repository) AddRoleGrantScopes(ctx context.Context, roleId string, role
9996		if  _ , ok  :=  originalGrantScopeMap [globals .GrantScopeChildren ]; ok  {
10097			return  nil , errors .New (ctx , errors .InvalidParameter , op , "grant scope children already exists, only one of descendants or children grant scope can be specified" )
10198		}
102- 		updateRole .setGrantScope (globals .GrantScopeDescendants )
99+ 		err  =  updateRole .setGrantScope (ctx , globals .GrantScopeDescendants )
100+ 		if  err  !=  nil  {
101+ 			return  nil , errors .Wrap (ctx , err , op )
102+ 		}
103103		updateMask  =  append (updateMask , "GrantScope" )
104104		finalGrantScope  =  globals .GrantScopeDescendants 
105105	case  addChildren :
106106		// cannot add 'children' when descendant is already set, only one hierarchical grant scope can be set 
107107		if  _ , ok  :=  originalGrantScopeMap [globals .GrantScopeDescendants ]; ok  {
108108			return  nil , errors .New (ctx , errors .InvalidParameter , op , "grant scope descendants already exists, only one of descendants or children grant scope can be specified" )
109109		}
110- 		updateRole .setGrantScope (globals .GrantScopeChildren )
110+ 		err  =  updateRole .setGrantScope (ctx , globals .GrantScopeChildren )
111+ 		if  err  !=  nil  {
112+ 			return  nil , errors .Wrap (ctx , err , op )
113+ 		}
114+ 
111115		updateMask  =  append (updateMask , "GrantScope" )
112116		finalGrantScope  =  globals .GrantScopeChildren 
113117	default :
@@ -155,7 +159,10 @@ func (r *Repository) AddRoleGrantScopes(ctx context.Context, roleId string, role
155159			return  nil , errors .Wrap (ctx , err , op , errors .WithMsg ("unable to split org roles grant scopes" ))
156160		}
157161	default :
158- 		return  nil , errors .New (ctx , errors .InvalidParameter , op , "invalid role scope" )
162+ 		// granting individual grant scope to roles is only allowed for roles in global and org scopes 
163+ 		if  len (individualScopesToAdd ) >  0  {
164+ 			return  nil , errors .New (ctx , errors .InvalidParameter , op , "individual role grant scope can only be set for global roles or org roles" )
165+ 		}
159166	}
160167
161168	oplogWrapper , err  :=  r .kms .GetWrapper (ctx , scp .GetPublicId (), kms .KeyPurposeOplog )
@@ -179,7 +186,9 @@ func (r *Repository) AddRoleGrantScopes(ctx context.Context, roleId string, role
179186				return  errors .Wrap (ctx , err , op , errors .WithMsg ("unable to update role" ))
180187			}
181188			if  addThis  {
182- 				retRoleGrantScopes  =  append (retRoleGrantScopes , updateRole .grantThisRoleScope ())
189+ 				if  g , ok  :=  updateRole .grantThisRoleScope (); ok  {
190+ 					retRoleGrantScopes  =  append (retRoleGrantScopes , g )
191+ 				}
183192			}
184193			if  addDescendants  ||  addChildren  {
185194				if  g , ok  :=  updateRole .grantScope (); ok  {
@@ -256,9 +265,6 @@ func (r *Repository) DeleteRoleGrantScopes(ctx context.Context, roleId string, r
256265	if  err  !=  nil  {
257266		return  db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg (fmt .Sprintf ("unable to get role %s scope id" , roleId )))
258267	}
259- 	if  scp .Type  ==  scope .Project .String () {
260- 		return  db .NoRowsAffected , errors .New (ctx , errors .InvalidParameter , op , "grant scope cannot be deleted from a project role" )
261- 	}
262268
263269	oplogWrapper , err  :=  r .kms .GetWrapper (ctx , scp .GetPublicId (), kms .KeyPurposeOplog )
264270	if  err  !=  nil  {
@@ -316,8 +322,8 @@ func (r *Repository) DeleteRoleGrantScopes(ctx context.Context, roleId string, r
316322
317323	// handle case where hierarchical grant scope ['children', 'descendants'] is removed 
318324	// these grants are mutually exclusive so an OR operation is safe here 
319- 	if  removeChildren  ||  removeDescendants  {
320- 		updateRole .setGrantScope ( globals . GrantScopeIndividual )
325+ 	if  ( removeChildren  ||  removeDescendants )  &&   scp . Type   !=   scope . Project . String ()  {
326+ 		updateRole .removeGrantScope ( )
321327		updateMask  =  append (updateMask , "GrantScope" )
322328		// manually bump rows deleted when for deleting hierarchical grant scope since this is now 
323329		// a DB row update instead of deleting a row. 
@@ -354,7 +360,9 @@ func (r *Repository) DeleteRoleGrantScopes(ctx context.Context, roleId string, r
354360			return  db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg ("unable to split org roles grant scopes" ))
355361		}
356362	default :
357- 		return  db .NoRowsAffected , errors .New (ctx , errors .InvalidParameter , op , "invalid role scope" )
363+ 		// granting individual grant scope to roles is only allowed for roles in global and org scopes 
364+ 		// but deleting individual grant scopes when the grant scope doesn't exist on a role is allowed 
365+ 		// so we don't return an error here and treat this as a no-op 
358366	}
359367
360368	_ , err  =  r .writer .DoTx (
@@ -453,9 +461,6 @@ func (r *Repository) SetRoleGrantScopes(ctx context.Context, roleId string, role
453461	if  err  !=  nil  {
454462		return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg (fmt .Sprintf ("unable to get role %s scope id" , roleId )))
455463	}
456- 	if  scp .Type  ==  scope .Project .String () {
457- 		return  nil , db .NoRowsAffected , errors .New (ctx , errors .InvalidParameter , op , "cannot modify grant scopes of a project scoped role" )
458- 	}
459464
460465	// NOTE: Set calculation can safely take place out of the transaction since 
461466	// we are using roleVersion to ensure that we end up operating on the same 
@@ -521,7 +526,6 @@ func (r *Repository) SetRoleGrantScopes(ctx context.Context, roleId string, role
521526	}
522527
523528	// return early if the there's a conflict in grant_scopes we're trying to add 
524- 	finalGrantScope  :=  globals .GrantScopeIndividual 
525529	_ , addDescendants  :=  toAdd [globals .GrantScopeDescendants ]
526530	_ , addChildren  :=  toAdd [globals .GrantScopeChildren ]
527531	if  addDescendants  &&  addChildren  {
@@ -538,19 +542,37 @@ func (r *Repository) SetRoleGrantScopes(ctx context.Context, roleId string, role
538542		totalRowsDeleted ++ 
539543	}
540544
541- 	// determine the final hierarchical grant scopes stored in 'grant_scope' column ['descendants', 'children'] 
545+ 	// finalGrantScopeForIndividualGrantScope is the final value of what 'grant_scope' column of the role will be. 
546+ 	// this is only important for global roles with individual scopes IDs granted to the role. 
547+ 	// A foreign key between iam_role_global.grant_scope and iam_role_global_individual_project_grant_scope.grant_scope 
548+ 	// can either be ['children', 'individual'] which will prevents inserting if the values don't match. 
549+ 	// Assuming that the value is 'individual' and only set it to 'children' if we're adding a 'children' grant 
550+ 	// the current value in the database does not matter and will be overridden by this method 
551+ 	finalGrantScopeForIndividualGrantScope  :=  globals .GrantScopeIndividual 
552+ 
553+ 	// determine the final hierarchical grant scopes stored in `grant_scope` column [`descendants`, `children`] 
542554	// depending on if we're adding or removing grants 
555+ 	// if descendants or children is being added, set finalGrantScope to the grant-to-be-added 
556+ 	// to resolve the 
543557	switch  {
544558	case  addDescendants :
545- 		updateRole .setGrantScope (globals .GrantScopeDescendants )
546- 		finalGrantScope  =  globals .GrantScopeDescendants 
559+ 		err  :=  updateRole .setGrantScope (ctx , globals .GrantScopeDescendants )
560+ 		if  err  !=  nil  {
561+ 			return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op )
562+ 		}
547563		updateMask  =  append (updateMask , "GrantScope" )
548564	case  addChildren :
549- 		updateRole .setGrantScope (globals .GrantScopeChildren )
550- 		finalGrantScope  =  globals .GrantScopeChildren 
565+ 		err  :=  updateRole .setGrantScope (ctx , globals .GrantScopeChildren )
566+ 		if  err  !=  nil  {
567+ 			return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op )
568+ 		}
551569		updateMask  =  append (updateMask , "GrantScope" )
570+ 		// set final grant scope to 'children'. finalGrantScopeForIndividualGrantScope will be used later 
571+ 		// when constructing entries for individual project grant scope 
572+ 		finalGrantScopeForIndividualGrantScope  =  globals .GrantScopeChildren 
573+ 
552574	case  removeDescendants  ||  removeChildren :
553- 		updateRole .setGrantScope ( globals . GrantScopeIndividual )
575+ 		updateRole .removeGrantScope ( )
554576		updateMask  =  append (updateMask , "GrantScope" )
555577	}
556578
@@ -591,11 +613,11 @@ func (r *Repository) SetRoleGrantScopes(ctx context.Context, roleId string, role
591613
592614	switch  scp .Type  {
593615	case  scope .Global .String ():
594- 		globalRoleIndividualOrgToAdd , globalRoleIndividualProjToAdd , err  =  individualGlobalRoleGrantScope (ctx , roleId , finalGrantScope , individualScopesToAdd )
616+ 		globalRoleIndividualOrgToAdd , globalRoleIndividualProjToAdd , err  =  individualGlobalRoleGrantScope (ctx , roleId , finalGrantScopeForIndividualGrantScope , individualScopesToAdd )
595617		if  err  !=  nil  {
596618			return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg ("failed to convert global role individual org scopes to scope specific scope object for grant scope addition" ))
597619		}
598- 		globalRoleIndividualOrgToRemove , globalRoleIndividualProjToRemove , err  =  individualGlobalRoleGrantScope (ctx , roleId , finalGrantScope , individualScopesToRemove )
620+ 		globalRoleIndividualOrgToRemove , globalRoleIndividualProjToRemove , err  =  individualGlobalRoleGrantScope (ctx , roleId , finalGrantScopeForIndividualGrantScope , individualScopesToRemove )
599621		if  err  !=  nil  {
600622			return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg ("failed to convert global role individual proj scopes to scope specific scope object for grant scope removal" ))
601623		}
@@ -609,14 +631,16 @@ func (r *Repository) SetRoleGrantScopes(ctx context.Context, roleId string, role
609631		if  err  !=  nil  {
610632			return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg ("failed to convert org role individual proj scopes to scope specific scope object for grant scope removal" ))
611633		}
612- 
613634	default :
614- 		return  nil , db .NoRowsAffected , errors .New (ctx , errors .InvalidParameter , op , fmt .Sprintf ("invalid role scope type %s" , scp .Type ))
635+ 		if  len (individualScopesToRemove ) >  0  ||  len (individualScopesToAdd ) >  0  {
636+ 			return  nil , db .NoRowsAffected , errors .New (ctx , errors .InvalidParameter , op ,
637+ 				fmt .Sprintf ("roles in scope type %s does not allow individual role grant scope" , scp .Type ))
638+ 		}
615639	}
616640
617641	oplogWrapper , err  :=  r .kms .GetWrapper (ctx , scp .GetPublicId (), kms .KeyPurposeOplog )
618642	if  err  !=  nil  {
619- 		return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg ("unable to get oplog wrapper " ))
643+ 		return  nil , db .NoRowsAffected , errors .Wrap (ctx , err , op , errors .WithMsg ("unable to get oplog wra pper " ))
620644	}
621645
622646	var  retGrantScopes  []* RoleGrantScope 
@@ -823,6 +847,10 @@ func allocRoleScopeGranter(ctx context.Context, roleId string, scopeType string)
823847		o  :=  allocOrgRole ()
824848		o .PublicId  =  roleId 
825849		res  =  & o 
850+ 	case  scope .Project .String ():
851+ 		p  :=  allocProjectRole ()
852+ 		p .PublicId  =  roleId 
853+ 		res  =  & p 
826854	default :
827855		return  nil , errors .New (ctx , errors .InvalidParameter , op , "invalid role scope" )
828856	}
0 commit comments