Add grant scope IDs to role list (#4893)
This adds grant_scope_ids in the output of role listing. The lookup for grant scope IDs was changed to allow taking in a set of roles instead of just a single role, and the results are collated afterwards. --------- Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
This commit is contained in:
1 parent
d43565038f
commit
4e0c2d79ac
8 files changed
+58
-14
No files matched your search
@@ -22,6 +22,8 @@ assumed to be the incoming worker key, which caused the wrong key information to
|
||||
|
||||
* Allow descriptions to contain newlines and other whitespace
|
||||
([PR](https://github.com/hashicorp/boundary/pull/2599))
|
||||
* Listed roles contain grant scope ID information
|
||||
([PR](https://github.com/hashicorp/boundary/pull/4893))
|
||||
|
||||
### Deprecations/Changes
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ func (s Service) ListRoles(ctx context.Context, req *pbs.ListRolesRequest) (*pbs
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
item, err := toProto(ctx, item, nil, nil, nil, outputOpts...)
|
||||
item, err := toProto(ctx, item, nil, nil, item.GrantScopes, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
@@ -220,6 +220,7 @@ func TestList(t *testing.T) {
|
||||
var totalRoles []*pb.Role
|
||||
for i := 0; i < 10; i++ {
|
||||
or := iam.TestRole(t, conn, oWithRoles.GetPublicId())
|
||||
_ = iam.TestRoleGrantScope(t, conn, or.GetPublicId(), globals.GrantScopeChildren)
|
||||
wantOrgRoles = append(wantOrgRoles, &pb.Role{
|
||||
Id: or.GetPublicId(),
|
||||
ScopeId: or.GetScopeId(),
|
||||
@@ -228,6 +229,7 @@ func TestList(t *testing.T) {
|
||||
UpdatedTime: or.GetUpdateTime().GetTimestamp(),
|
||||
Version: or.GetVersion(),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
GrantScopeIds: []string{"this", "children"},
|
||||
})
|
||||
totalRoles = append(totalRoles, wantOrgRoles[i])
|
||||
pr := iam.TestRole(t, conn, pWithRoles.GetPublicId())
|
||||
@@ -239,6 +241,7 @@ func TestList(t *testing.T) {
|
||||
UpdatedTime: pr.GetUpdateTime().GetTimestamp(),
|
||||
Version: pr.GetVersion(),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
GrantScopeIds: []string{"this"},
|
||||
})
|
||||
totalRoles = append(totalRoles, wantProjRoles[i])
|
||||
}
|
||||
@@ -422,7 +425,7 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
|
||||
func roleToProto(r *iam.Role, scope *scopes.ScopeInfo, authorizedActions []string) *pb.Role {
|
||||
return &pb.Role{
|
||||
ret := &pb.Role{
|
||||
Id: r.GetPublicId(),
|
||||
ScopeId: r.GetScopeId(),
|
||||
Scope: scope,
|
||||
@@ -431,6 +434,10 @@ func roleToProto(r *iam.Role, scope *scopes.ScopeInfo, authorizedActions []strin
|
||||
Version: r.GetVersion(),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
}
|
||||
for _, r := range r.GrantScopes {
|
||||
ret.GrantScopeIds = append(ret.GrantScopeIds, r.ScopeIdOrSpecial)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestListPagination(t *testing.T) {
|
||||
|
||||
@@ -185,7 +185,7 @@ func (r *Repository) LookupRole(ctx context.Context, withPublicId string, opt ..
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
rgs, err = repo.ListRoleGrantScopes(ctx, withPublicId)
|
||||
rgs, err = repo.ListRoleGrantScopes(ctx, []string{withPublicId})
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
@@ -311,20 +311,38 @@ func (r *Repository) queryRoles(ctx context.Context, whereClause string, args []
|
||||
const op = "iam.(Repository).queryRoles"
|
||||
|
||||
var transactionTimestamp time.Time
|
||||
var ret []*Role
|
||||
var retRoles []*Role
|
||||
var retRoleGrantScopes []*RoleGrantScope
|
||||
if _, err := r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(rd db.Reader, w db.Writer) error {
|
||||
var inRet []*Role
|
||||
if err := rd.SearchWhere(ctx, &inRet, whereClause, args, opt...); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("failed to query roles"))
|
||||
}
|
||||
ret = inRet
|
||||
retRoles = inRet
|
||||
var err error
|
||||
if len(retRoles) > 0 {
|
||||
roleIds := make([]string, 0, len(retRoles))
|
||||
for _, retRole := range retRoles {
|
||||
roleIds = append(roleIds, retRole.PublicId)
|
||||
}
|
||||
retRoleGrantScopes, err = r.ListRoleGrantScopes(ctx, roleIds)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("failed to query role grant scopes"))
|
||||
}
|
||||
}
|
||||
transactionTimestamp, err = rd.Now(ctx)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
return ret, transactionTimestamp, nil
|
||||
roleGrantScopesMap := make(map[string][]*RoleGrantScope)
|
||||
for _, rgs := range retRoleGrantScopes {
|
||||
roleGrantScopesMap[rgs.RoleId] = append(roleGrantScopesMap[rgs.RoleId], rgs)
|
||||
}
|
||||
for _, role := range retRoles {
|
||||
role.GrantScopes = roleGrantScopesMap[role.PublicId]
|
||||
}
|
||||
return retRoles, transactionTimestamp, nil
|
||||
}
|
||||
|
||||
// listRoleDeletedIds lists the public IDs of any roles deleted since the timestamp provided.
|
||||
|
||||
@@ -391,13 +391,24 @@ func (r *Repository) ListRoleGrants(ctx context.Context, roleId string, opt ...O
|
||||
|
||||
// ListRoleGrantScopes returns the grant scopes for the roleId and supports the WithLimit
|
||||
// option.
|
||||
func (r *Repository) ListRoleGrantScopes(ctx context.Context, roleId string, opt ...Option) ([]*RoleGrantScope, error) {
|
||||
func (r *Repository) ListRoleGrantScopes(ctx context.Context, roleIds []string, opt ...Option) ([]*RoleGrantScope, error) {
|
||||
const op = "iam.(Repository).ListRoleGrantScopes"
|
||||
if roleId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing role id")
|
||||
if len(roleIds) == 0 {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing role ids")
|
||||
}
|
||||
query := "?"
|
||||
var args []any
|
||||
for i, roleId := range roleIds {
|
||||
if roleId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing role ids")
|
||||
}
|
||||
if i > 0 {
|
||||
query = query + ", ?"
|
||||
}
|
||||
args = append(args, roleId)
|
||||
}
|
||||
var roleGrantScopes []*RoleGrantScope
|
||||
if err := r.list(ctx, &roleGrantScopes, "role_id = ?", []any{roleId}, opt...); err != nil {
|
||||
if err := r.list(ctx, &roleGrantScopes, fmt.Sprintf("role_id in (%s)", query), args, opt...); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup role grant scopes"))
|
||||
}
|
||||
return roleGrantScopes, nil
|
||||
|
||||
@@ -23,7 +23,8 @@ const (
|
||||
// Roles are granted permissions and assignable to Users and Groups.
|
||||
type Role struct {
|
||||
*store.Role
|
||||
tableName string `gorm:"-"`
|
||||
GrantScopes []*RoleGrantScope `gorm:"-"`
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
// ensure that Role implements the interfaces of: Resource, Cloneable, and db.VetForWriter.
|
||||
@@ -60,9 +61,13 @@ func allocRole() Role {
|
||||
// Clone creates a clone of the Role.
|
||||
func (role *Role) Clone() any {
|
||||
cp := proto.Clone(role.Role)
|
||||
return &Role{
|
||||
ret := &Role{
|
||||
Role: cp.(*store.Role),
|
||||
}
|
||||
for _, grantScope := range role.GrantScopes {
|
||||
ret.GrantScopes = append(ret.GrantScopes, grantScope.Clone().(*RoleGrantScope))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface.
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestService_ListRoles(t *testing.T) {
|
||||
_, err = sqlDB.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
cmpIgnoreUnexportedOpts := cmpopts.IgnoreUnexported(iam.Role{}, store.Role{}, timestamp.Timestamp{}, timestamppb.Timestamp{})
|
||||
cmpIgnoreUnexportedOpts := cmpopts.IgnoreUnexported(iam.Role{}, store.Role{}, timestamp.Timestamp{}, timestamppb.Timestamp{}, iam.RoleGrantScope{}, store.RoleGrantScope{})
|
||||
|
||||
t.Run("List validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -216,6 +216,7 @@ func TestRole(t testing.TB, conn *db.DB, scopeId string, opt ...Option) *Role {
|
||||
gs, err := NewRoleGrantScope(ctx, id, gsi)
|
||||
require.NoError(err)
|
||||
require.NoError(rw.Create(ctx, gs))
|
||||
role.GrantScopes = append(role.GrantScopes, gs)
|
||||
}
|
||||
require.Equal(opts.withDescription, role.Description)
|
||||
require.Equal(opts.withName, role.Name)
|
||||
|
||||
Reference in new issue
Block a user