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>
pull/4567/head
Jeff Mitchell 2 years ago committed by GitHub
parent d43565038f
commit 4e0c2d79ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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)

Loading…
Cancel
Save