Add managed group support to role principals (#1270)

This commit is contained in:
Jeff Mitchell authored and GitHub committed 2021-06-04 10:44:57 -04:00
1 parent ad93315b59
commit 9ecc384007
29 files changed
+1510 -381

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
/*
Globals, in the traditional sense, are usually bad. But there are some
situations where we want either consts or known values that are constant per
invocation but invocation may be in various places, such as a test or via CLI,
and placing such a value in any given package leads to import issues. So think
of this package as "freeing us from circular dependency hell".
This package provides _exported_ globals that might reasonably be used by API
users, Terraform, etc. A separate package, under internal/intglobals, provides
globals that perform a similar function but are only meant for internal use.
There is no race checking; these values should only ever be set at startup of
Boundary or a test, but available to reference from anywhere.
*/
package globals
-4
View File
@@ -1,9 +1,5 @@
package globals
// This set of consts is intended to be a place to collect commonly-used field
// names. Since these might be used outside of the internal code (e.g. by SDK or
// CLI), it's outside internal/ here in globals. Some of these are already const
// elsewhere in the code but we should migrate to using a single source.
const (
IdField = "id"
VersionField = "version"
-7
View File
@@ -2,13 +2,6 @@ package globals
import "time"
// NOTE: Globals, in the traditional sense, are bad. But there are some
// situations where we want a value that is constant per invocation but
// invocation may be in various places, such as a test or via CLI, and placing
// such a value in any given package leads to import issues. So think of this
// package as "freeing us from circular dependency hell". These values should
// only ever be set at startup, but simply available to reference from anywhere.
const (
TcpProxyV1 = "boundary-tcp-proxy-v1"
ServiceTokenV1 = "s1"
+2 -3
View File
@@ -3,6 +3,7 @@ package oidc
import (
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/intglobals"
)
const (
@@ -10,8 +11,6 @@ const (
AuthMethodPrefix = "amoidc"
// AccountPrefix defines the prefix for Account public ids.
AccountPrefix = "acctoidc"
// ManagedGroupPrefix defines the prefix for ManagedGroup public ids.
ManagedGroupPrefix = "mgoidc"
)
func newAuthMethodId() (string, error) {
@@ -43,7 +42,7 @@ func newAccountId(authMethodId, issuer, sub string) (string, error) {
func newManagedGroupId() (string, error) {
const op = "oidc.newManagedGroupId"
id, err := db.NewPublicId(ManagedGroupPrefix)
id, err := db.NewPublicId(intglobals.OidcManagedGroupPrefix)
if err != nil {
return "", errors.Wrap(err, op)
}
+1 -1
View File
@@ -26,7 +26,7 @@ func Test_ManagedGroups_RepoValidate(t *testing.T) {
})
t.Run("valid", func(t *testing.T) {
mg.AuthMethodId = "amoidc_1234567890"
mg.Filter = testFakeManagedGroupFilter
mg.Filter = TestFakeManagedGroupFilter
assert.NoError(mg.validate(op))
})
}
@@ -17,8 +17,6 @@ import (
"github.com/stretchr/testify/require"
)
const testFakeManagedGroupFilter = `"/foo" == "bar"`
func Test_ManagedGroupMemberships(t *testing.T) {
// This tests both managed group membership functions (set/list) as list is
// always called as a return from set and we are validating the values that
@@ -62,7 +60,7 @@ func Test_ManagedGroupMemberships(t *testing.T) {
for i := 0; i < 100; i++ {
mg := oidc.AllocManagedGroup()
mg.AuthMethodId = authMethod.PublicId
mg.Filter = testFakeManagedGroupFilter
mg.Filter = oidc.TestFakeManagedGroupFilter
got, err := repo.CreateManagedGroup(context.Background(), org.GetPublicId(), mg)
require.NoError(t, err)
mgs = append(mgs, got)
@@ -13,14 +13,13 @@ import (
dbassert "github.com/hashicorp/boundary/internal/db/assert"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const testFakeManagedGroupFilter = `"/foo" == "bar"`
func TestRepository_CreateManagedGroup(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
@@ -91,7 +90,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
in: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
PublicId: "mgoidc_OOOOOOOOOO",
},
},
@@ -103,7 +102,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
in: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
},
},
wantIsErr: errors.InvalidParameter,
@@ -115,13 +114,13 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
in: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
},
},
want: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
},
},
},
@@ -131,14 +130,14 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
in: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
Name: "test-name-repo",
},
},
want: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
Name: "test-name-repo",
},
},
@@ -149,7 +148,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
in: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
Description: ("test-description-repo"),
Name: "myname",
},
@@ -157,7 +156,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
want: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
Description: ("test-description-repo"),
Name: "myname",
},
@@ -169,7 +168,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
in: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
AuthMethodId: authMethod.PublicId,
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
Description: ("test-description-repo"),
Name: "myname",
},
@@ -200,7 +199,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
require.NoError(err)
assert.Empty(tt.in.PublicId)
require.NotNil(got)
assertPublicId(t, ManagedGroupPrefix, got.PublicId)
assertPublicId(t, intglobals.OidcManagedGroupPrefix, got.PublicId)
assert.NotSame(tt.in, got)
assert.Equal(tt.want.Name, got.Name)
assert.Equal(tt.want.Description, got.Description)
@@ -231,7 +230,7 @@ func TestRepository_LookupManagedGroup(t *testing.T) {
WithIssuer(TestConvertToUrls(t, "https://www.alice.com")[0]),
WithApiUrl(TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
mg := TestManagedGroup(t, conn, authMethod, testFakeManagedGroupFilter)
mg := TestManagedGroup(t, conn, authMethod, TestFakeManagedGroupFilter)
newMgId, err := newManagedGroupId()
require.NoError(t, err)
@@ -296,7 +295,7 @@ func TestRepository_DeleteManagedGroup(t *testing.T) {
WithIssuer(TestConvertToUrls(t, "https://www.alice.com")[0]),
WithApiUrl(TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
mg := TestManagedGroup(t, conn, authMethod, testFakeManagedGroupFilter)
mg := TestManagedGroup(t, conn, authMethod, TestFakeManagedGroupFilter)
newMgId, err := newManagedGroupId()
require.NoError(t, err)
tests := []struct {
@@ -387,18 +386,18 @@ func TestRepository_ListManagedGroups(t *testing.T) {
WithApiUrl(TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
mgs1 := []*ManagedGroup{
TestManagedGroup(t, conn, authMethod1, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod1, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod1, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod1, TestFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod1, TestFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod1, TestFakeManagedGroupFilter),
}
sort.Slice(mgs1, func(i, j int) bool {
return strings.Compare(mgs1[i].PublicId, mgs1[j].PublicId) < 0
})
mgs2 := []*ManagedGroup{
TestManagedGroup(t, conn, authMethod2, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod2, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod2, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod2, TestFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod2, TestFakeManagedGroupFilter),
TestManagedGroup(t, conn, authMethod2, TestFakeManagedGroupFilter),
}
sort.Slice(mgs2, func(i, j int) bool {
return strings.Compare(mgs2[i].PublicId, mgs2[j].PublicId) < 0
@@ -789,7 +788,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
version: 1,
orig: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
},
},
chgFn: changeFilter(`"/zip" == "zap"`),
@@ -865,7 +864,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
version: 1,
orig: &ManagedGroup{
ManagedGroup: &store.ManagedGroup{
Filter: testFakeManagedGroupFilter,
Filter: TestFakeManagedGroupFilter,
},
},
masks: []string{FilterField},
@@ -923,7 +922,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
assert.NoError(err)
require.NotNil(repo)
orig := TestManagedGroup(t, conn, am, testFakeManagedGroupFilter, WithName(tt.orig.GetName()), WithDescription(tt.orig.GetDescription()))
orig := TestManagedGroup(t, conn, am, TestFakeManagedGroupFilter, WithName(tt.orig.GetName()), WithDescription(tt.orig.GetDescription()))
tt.orig.AuthMethodId = am.PublicId
if tt.chgFn != nil {
@@ -949,7 +948,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
return
}
require.NotNil(got)
assertPublicId(t, ManagedGroupPrefix, got.PublicId)
assertPublicId(t, intglobals.OidcManagedGroupPrefix, got.PublicId)
assert.Equal(tt.wantCount, gotCount, "row count")
assert.NotSame(tt.orig, got)
assert.Equal(tt.orig.AuthMethodId, got.AuthMethodId)
+5 -5
View File
@@ -661,8 +661,8 @@ func Test_ManagedGroupFiltering(t *testing.T) {
// Create two managed groups. We'll use these in tests to set filters and
// then check that the user belongs to the ones we expect.
mgs := []*ManagedGroup{
TestManagedGroup(t, conn, testAuthMethod, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, testAuthMethod, testFakeManagedGroupFilter),
TestManagedGroup(t, conn, testAuthMethod, TestFakeManagedGroupFilter),
TestManagedGroup(t, conn, testAuthMethod, TestFakeManagedGroupFilter),
}
// A reusable oidc.Provider for the tests
@@ -697,15 +697,15 @@ func Test_ManagedGroupFiltering(t *testing.T) {
{
name: "no match",
filters: []string{
testFakeManagedGroupFilter,
testFakeManagedGroupFilter,
TestFakeManagedGroupFilter,
TestFakeManagedGroupFilter,
},
},
{
name: "token match",
filters: []string{
`"/token/nonce" == "nonce"`,
testFakeManagedGroupFilter,
TestFakeManagedGroupFilter,
},
matchingMgs: mgs[0:1],
},
+2
View File
@@ -34,6 +34,8 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"
)
const TestFakeManagedGroupFilter = `"/foo" == "bar"`
// TestAuthMethod creates a test oidc auth method. WithName, WithDescription,
// WithMaxAge, WithApiUrl, WithIssuer, WithCertificates, WithAudClaims, and
// WithSigningAlgs options are supported.
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/intglobals"
)
type Subtype int
@@ -92,7 +93,7 @@ func SubtypeFromId(id string) Subtype {
return PasswordSubtype
case strings.HasPrefix(strings.TrimSpace(id), oidc.AuthMethodPrefix),
strings.HasPrefix(strings.TrimSpace(id), oidc.AccountPrefix),
strings.HasPrefix(strings.TrimSpace(id), oidc.ManagedGroupPrefix):
strings.HasPrefix(strings.TrimSpace(id), intglobals.OidcManagedGroupPrefix):
return OidcSubtype
}
return UnknownSubtype
@@ -565,6 +565,7 @@ $$ language plpgsql;
-- iam_principle_role provides a consolidated view all principal roles assigned
-- (user and group roles).
-- REPLACED in 9/04_oidc_managed_group_principal_role
create view iam_principal_role as
select
ur.create_time,
@@ -672,7 +673,7 @@ before
insert on iam_group_member_user
for each row execute procedure recovery_user_not_allowed('member_id');
-- get_scoped_principal_id is used by the iam_group_member view as a convient
-- get_scoped_member_id is used by the iam_group_member view as a convient
-- way to create <scope_id>:<member_id> to reference members from
-- other scopes than the group's scope.
create or replace function get_scoped_member_id(group_scope text, member_scope text, member_id text) returns text
@@ -0,0 +1,79 @@
begin;
-- iam_managed_group_role contains roles that have been assigned to managed
-- groups. Managed groups can be from any scope. The rows in this table must be
-- immutable after insert, which will be ensured with a before update trigger
-- using iam_immutable_role_principal().
create table iam_managed_group_role (
create_time wt_timestamp,
role_id wt_role_id
references iam_role(public_id)
on delete cascade
on update cascade,
principal_id wt_public_id
references auth_managed_group(public_id)
on delete cascade
on update cascade,
primary key (role_id, principal_id)
);
create trigger immutable_role_principal
before update on iam_managed_group_role
for each row execute procedure iam_immutable_role_principal();
create trigger default_create_time_column
before insert on iam_managed_group_role
for each row execute procedure default_create_time();
-- iam_principal_role provides a consolidated view all principal roles assigned
-- (user and group roles).
create or replace view iam_principal_role as
select
ur.create_time,
ur.principal_id,
ur.role_id,
u.scope_id as principal_scope_id,
r.scope_id as role_scope_id,
get_scoped_principal_id(r.scope_id, u.scope_id, ur.principal_id) as scoped_principal_id,
'user' as type
from
iam_user_role ur,
iam_role r,
iam_user u
where
ur.role_id = r.public_id and
u.public_id = ur.principal_id
union
select
gr.create_time,
gr.principal_id,
gr.role_id,
g.scope_id as principal_scope_id,
r.scope_id as role_scope_id,
get_scoped_principal_id(r.scope_id, g.scope_id, gr.principal_id) as scoped_principal_id,
'group' as type
from
iam_group_role gr,
iam_role r,
iam_group g
where
gr.role_id = r.public_id and
g.public_id = gr.principal_id
union
select
mgr.create_time,
mgr.principal_id,
mgr.role_id,
(select scope_id from auth_method am where am.public_id = amg.auth_method_id) as principal_scope_id,
r.scope_id as role_scope_id,
get_scoped_principal_id(r.scope_id, (select scope_id from auth_method am where am.public_id = amg.auth_method_id), mgr.principal_id) as scoped_principal_id,
'managed group' as type
from
iam_managed_group_role mgr,
iam_role r,
auth_managed_group amg
where
mgr.role_id = r.public_id and
amg.public_id = mgr.principal_id;
commit;
+80 -2
View File
@@ -4,7 +4,7 @@ package schema
func init() {
migrationStates["postgres"] = migrationState{
binarySchemaVersion: 9003,
binarySchemaVersion: 9004,
upMigrations: map[int][]byte{
1: []byte(`
create domain wt_public_id as text
@@ -966,6 +966,7 @@ $$ language plpgsql;
-- iam_principle_role provides a consolidated view all principal roles assigned
-- (user and group roles).
-- REPLACED in 9/04_oidc_managed_group_principal_role
create view iam_principal_role as
select
ur.create_time,
@@ -1073,7 +1074,7 @@ before
insert on iam_group_member_user
for each row execute procedure recovery_user_not_allowed('member_id');
-- get_scoped_principal_id is used by the iam_group_member view as a convient
-- get_scoped_member_id is used by the iam_group_member view as a convient
-- way to create <scope_id>:<member_id> to reference members from
-- other scopes than the group's scope.
create or replace function get_scoped_member_id(group_scope text, member_scope text, member_id text) returns text
@@ -6562,6 +6563,83 @@ select
oidc.member_id
from
auth_oidc_managed_group_member_account oidc;
`),
9004: []byte(`
-- iam_managed_group_role contains roles that have been assigned to managed
-- groups. Managed groups can be from any scope. The rows in this table must be
-- immutable after insert, which will be ensured with a before update trigger
-- using iam_immutable_role_principal().
create table iam_managed_group_role (
create_time wt_timestamp,
role_id wt_role_id
references iam_role(public_id)
on delete cascade
on update cascade,
principal_id wt_public_id
references auth_managed_group(public_id)
on delete cascade
on update cascade,
primary key (role_id, principal_id)
);
create trigger immutable_role_principal
before update on iam_managed_group_role
for each row execute procedure iam_immutable_role_principal();
create trigger default_create_time_column
before insert on iam_managed_group_role
for each row execute procedure default_create_time();
-- iam_principal_role provides a consolidated view all principal roles assigned
-- (user and group roles).
create or replace view iam_principal_role as
select
ur.create_time,
ur.principal_id,
ur.role_id,
u.scope_id as principal_scope_id,
r.scope_id as role_scope_id,
get_scoped_principal_id(r.scope_id, u.scope_id, ur.principal_id) as scoped_principal_id,
'user' as type
from
iam_user_role ur,
iam_role r,
iam_user u
where
ur.role_id = r.public_id and
u.public_id = ur.principal_id
union
select
gr.create_time,
gr.principal_id,
gr.role_id,
g.scope_id as principal_scope_id,
r.scope_id as role_scope_id,
get_scoped_principal_id(r.scope_id, g.scope_id, gr.principal_id) as scoped_principal_id,
'group' as type
from
iam_group_role gr,
iam_role r,
iam_group g
where
gr.role_id = r.public_id and
g.public_id = gr.principal_id
union
select
mgr.create_time,
mgr.principal_id,
mgr.role_id,
(select scope_id from auth_method am where am.public_id = amg.auth_method_id) as principal_scope_id,
r.scope_id as role_scope_id,
get_scoped_principal_id(r.scope_id, (select scope_id from auth_method am where am.public_id = amg.auth_method_id), mgr.principal_id) as scoped_principal_id,
'managed group' as type
from
iam_managed_group_role mgr,
iam_role r,
auth_managed_group amg
where
mgr.role_id = r.public_id and
amg.public_id = mgr.principal_id;
`),
},
}
+4
View File
@@ -5,6 +5,7 @@ import (
"testing"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -26,6 +27,9 @@ func Test_PublicIds(t *testing.T) {
require.NoError(t, err)
assert.True(t, strings.HasPrefix(id, GroupPrefix+"_"))
})
t.Run("oidc managed group", func(t *testing.T) {
assert.True(t, strings.HasPrefix("mgoidc_1234567890", intglobals.OidcManagedGroupPrefix+"_"))
})
t.Run("scopes", func(t *testing.T) {
id, err := newScopeId(scope.Org)
require.NoError(t, err)
+86 -4
View File
@@ -13,9 +13,10 @@ import (
type RoleType uint32
const (
UnknownRoleType RoleType = 0
UserRoleType RoleType = 1
GroupRoleType RoleType = 2
UnknownRoleType RoleType = 0
UserRoleType RoleType = 1
GroupRoleType RoleType = 2
ManagedGroupRoleType RoleType = 3
)
// String returns a string representation of the role type.
@@ -24,6 +25,7 @@ func (r RoleType) String() string {
"unknown",
"user",
"group",
"managed group",
}[r]
}
@@ -31,6 +33,7 @@ const (
principalRoleViewDefaultTable = "iam_principal_role"
userRoleDefaultTable = "iam_user_role"
groupRoleDefaultTable = "iam_group_role"
managedGroupRoleDefaultTable = "iam_managed_group_role"
)
// PrincipalRole provides a common way to return roles regardless of their
@@ -188,7 +191,7 @@ func (role *GroupRole) VetForWrite(ctx context.Context, r db.Reader, opType db.O
return errors.New(errors.InvalidParameter, op, "missing role id")
}
if role.PrincipalId == "" {
return errors.New(errors.InvalidParameter, op, "missing user id")
return errors.New(errors.InvalidParameter, op, "missing group id")
}
return nil
}
@@ -212,3 +215,82 @@ func (r *GroupRole) SetTableName(n string) {
r.tableName = n
}
}
// ManagedGroupRole is a managed group assigned to a role
type ManagedGroupRole struct {
*store.ManagedGroupRole
tableName string `gorm:"-"`
}
// ensure that GroupRole implements the interfaces of: Cloneable and
// db.VetForWriter
var (
_ Cloneable = (*ManagedGroupRole)(nil)
_ db.VetForWriter = (*ManagedGroupRole)(nil)
)
// NewGroupRole creates a new group role in memory. No options are supported
// currently.
func NewManagedGroupRole(roleId, managedGroupId string, opt ...Option) (*ManagedGroupRole, error) {
const op = "iam.NewManagedGroupRole"
if roleId == "" {
return nil, errors.New(errors.InvalidParameter, op, "missing role id")
}
if managedGroupId == "" {
return nil, errors.New(errors.InvalidParameter, op, "missing managed group id")
}
return &ManagedGroupRole{
ManagedGroupRole: &store.ManagedGroupRole{
PrincipalId: managedGroupId,
RoleId: roleId,
},
}, nil
}
// AllocManagedGroupRole returns a new ManagedGroupRole with an initialized
// store.
func AllocManagedGroupRole() ManagedGroupRole {
return ManagedGroupRole{
ManagedGroupRole: &store.ManagedGroupRole{},
}
}
// Clone creates a clone of the ManagedGroupRole.
func (r *ManagedGroupRole) Clone() interface{} {
cp := proto.Clone(r.ManagedGroupRole)
return &ManagedGroupRole{
ManagedGroupRole: cp.(*store.ManagedGroupRole),
}
}
// VetForWrite implements db.VetForWrite() interface for managed group roles.
func (role ManagedGroupRole) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
const op = "iam.(ManagedGroupRole).VetForWrite"
if role.RoleId == "" {
return errors.New(errors.InvalidParameter, op, "missing role id")
}
if role.PrincipalId == "" {
return errors.New(errors.InvalidParameter, op, "missing managed group id")
}
return nil
}
// TableName returns the tablename to override the default gorm table name for
// managed group roles.
func (r *ManagedGroupRole) TableName() string {
if r.tableName != "" {
return r.tableName
}
return managedGroupRoleDefaultTable
}
// SetTableName sets the table name for the resource. If the caller attempts to
// set the name to "" the name will be reset to the default name.
func (r *ManagedGroupRole) SetTableName(n string) {
switch n {
case "":
r.tableName = managedGroupRoleDefaultTable
default:
r.tableName = n
}
}
+387
View File
@@ -0,0 +1,387 @@
package iam_test
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/iam/store"
"github.com/hashicorp/boundary/internal/kms"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
// This is in an iam_test package because managed groups are an abstract type so
// we need to reach into an implementation for testing, which itself reaches
// into IAM. So this avoids a dependency loop.
func TestNewManagedGroupRole(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
repo := iam.TestRepo(t, conn, wrapper)
org, _ := iam.TestScopes(t, repo)
orgRole := iam.TestRole(t, conn, org.PublicId)
const managedGroupId = "mgoidc_1234567890"
type args struct {
roleId string
ManagedGroupId string
opt []iam.Option
}
tests := []struct {
name string
args args
want *iam.ManagedGroupRole
wantErr bool
wantIsErr errors.Code
}{
{
name: "valid-org",
args: args{
roleId: orgRole.PublicId,
ManagedGroupId: managedGroupId,
},
want: func() *iam.ManagedGroupRole {
r := iam.AllocManagedGroupRole()
r.RoleId = orgRole.PublicId
r.PrincipalId = managedGroupId
return &r
}(),
},
{
name: "empty-role-id",
args: args{
roleId: "",
ManagedGroupId: managedGroupId,
},
want: nil,
wantErr: true,
wantIsErr: errors.InvalidParameter,
},
{
name: "empty-ManagedGroup-id",
args: args{
roleId: orgRole.PublicId,
ManagedGroupId: "",
},
want: nil,
wantErr: true,
wantIsErr: errors.InvalidParameter,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
got, err := iam.NewManagedGroupRole(tt.args.roleId, tt.args.ManagedGroupId, tt.args.opt...)
if tt.wantErr {
require.Error(err)
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
return
}
require.NoError(err)
assert.Equal(tt.want, got)
})
}
}
func TestManagedGroupRole_Create(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrap)
repo := iam.TestRepo(t, conn, wrap)
org, _ := iam.TestScopes(t, repo)
org2, _ := iam.TestScopes(t, repo)
ctx := context.Background()
databaseWrapper, err := kmsCache.GetWrapper(ctx, org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, org.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
mg := oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter)
type args struct {
role *iam.ManagedGroupRole
}
tests := []struct {
name string
args args
wantDup bool
wantErr bool
wantErrMsg string
wantIsErr errors.Code
}{
{
name: "valid-with-org",
args: args{
role: func() *iam.ManagedGroupRole {
role := iam.TestRole(t, conn, org.PublicId)
principalRole, err := iam.NewManagedGroupRole(role.PublicId, mg.PublicId)
require.NoError(t, err)
return principalRole
}(),
},
wantErr: false,
},
{
name: "cross-org",
args: args{
role: func() *iam.ManagedGroupRole {
role := iam.TestRole(t, conn, org2.PublicId)
principalRole, err := iam.NewManagedGroupRole(role.PublicId, mg.PublicId)
require.NoError(t, err)
return principalRole
}(),
},
},
{
name: "bad-role-id",
args: args{
role: func() *iam.ManagedGroupRole {
id := testId(t)
principalRole, err := iam.NewManagedGroupRole(id, mg.PublicId)
require.NoError(t, err)
return principalRole
}(),
},
wantErr: true,
wantErrMsg: "db.Create: create failed: insert or update on table \"iam_managed_group_role\" violates foreign key constraint \"iam_managed_group_role_role_id_fkey\"",
},
{
name: "bad-principal-id",
args: args{
role: func() *iam.ManagedGroupRole {
id := testId(t)
role := iam.TestRole(t, conn, org.PublicId)
principalRole, err := iam.NewManagedGroupRole(role.PublicId, id)
require.NoError(t, err)
return principalRole
}(),
},
wantErr: true,
wantErrMsg: "db.Create: create failed: insert or update on table \"iam_managed_group_role\" violates foreign key constraint \"iam_managed_group_role_principal_id_fkey\"",
},
{
name: "missing-role-id",
args: args{
role: func() *iam.ManagedGroupRole {
return &iam.ManagedGroupRole{
ManagedGroupRole: &store.ManagedGroupRole{
RoleId: "",
PrincipalId: mg.PublicId,
},
}
}(),
},
wantErr: true,
wantErrMsg: "db.Create: iam.(ManagedGroupRole).VetForWrite: missing role id: parameter violation: error #100",
wantIsErr: errors.InvalidParameter,
},
{
name: "missing-principal-id",
args: args{
role: func() *iam.ManagedGroupRole {
role := iam.TestRole(t, conn, org.PublicId)
return &iam.ManagedGroupRole{
ManagedGroupRole: &store.ManagedGroupRole{
RoleId: role.PublicId,
PrincipalId: "",
},
}
}(),
},
wantErr: true,
wantErrMsg: "db.Create: iam.(ManagedGroupRole).VetForWrite: missing managed group id: parameter violation: error #100",
wantIsErr: errors.InvalidParameter,
},
{
name: "dup-at-org",
args: args{
role: func() *iam.ManagedGroupRole {
role := iam.TestRole(t, conn, org.PublicId)
principalRole, err := iam.NewManagedGroupRole(role.PublicId, mg.PublicId)
require.NoError(t, err)
return principalRole
}(),
},
wantDup: true,
wantErr: true,
wantErrMsg: `db.Create: create failed: duplicate key value violates unique constraint`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := db.New(conn)
if tt.wantDup {
r := tt.args.role.Clone().(*iam.ManagedGroupRole)
err := w.Create(context.Background(), r)
require.NoError(err)
}
r := tt.args.role.Clone().(*iam.ManagedGroupRole)
err := w.Create(context.Background(), r)
if tt.wantErr {
require.Error(err)
assert.Contains(err.Error(), tt.wantErrMsg)
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
return
}
assert.NoError(err)
found := iam.AllocManagedGroupRole()
err = w.LookupWhere(context.Background(), &found, "role_id = ? and principal_id = ?", r.RoleId, r.PrincipalId)
require.NoError(err)
assert.Equal(r, &found)
})
}
}
func TestManagedGroupRole_Update(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrap)
repo := iam.TestRepo(t, conn, wrap)
org, _ := iam.TestScopes(t, repo)
ctx := context.Background()
databaseWrapper, err := kmsCache.GetWrapper(ctx, org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, org.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
t.Run("updates not allowed", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
r := iam.TestRole(t, conn, org.PublicId)
mg := oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter)
mg2 := oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter)
mgr := iam.TestManagedGroupRole(t, conn, r.PublicId, mg.PublicId)
updateRole := mgr.Clone().(*iam.ManagedGroupRole)
updateRole.PrincipalId = mg2.PublicId
updatedRows, err := rw.Update(context.Background(), updateRole, []string{"PrincipalId"}, nil)
require.Error(err)
assert.Equal(0, updatedRows)
})
}
func TestManagedGroupRole_Delete(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrap)
repo := iam.TestRepo(t, conn, wrap)
org, _ := iam.TestScopes(t, repo)
ctx := context.Background()
databaseWrapper, err := kmsCache.GetWrapper(ctx, org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, org.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
id := testId(t)
mg := oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter)
r := iam.TestRole(t, conn, org.PublicId)
tests := []struct {
name string
role *iam.ManagedGroupRole
wantRowsDeleted int
wantErr bool
wantErrMsg string
}{
{
name: "valid",
role: iam.TestManagedGroupRole(t, conn, r.PublicId, mg.PublicId),
wantErr: false,
wantRowsDeleted: 1,
},
{
name: "bad-id",
role: func() *iam.ManagedGroupRole {
r := iam.AllocManagedGroupRole()
r.PrincipalId = id
r.RoleId = id
return &r
}(),
wantErr: false,
wantRowsDeleted: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
deleteRole := iam.AllocManagedGroupRole()
deleteRole.RoleId = tt.role.GetRoleId()
deleteRole.PrincipalId = tt.role.GetPrincipalId()
deletedRows, err := rw.Delete(context.Background(), &deleteRole)
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
if tt.wantRowsDeleted == 0 {
assert.Equal(tt.wantRowsDeleted, deletedRows)
return
}
assert.Equal(tt.wantRowsDeleted, deletedRows)
found := iam.AllocManagedGroupRole()
err = rw.LookupWhere(context.Background(), &found, "role_id = ? and principal_id = ?", tt.role.GetRoleId(), tt.role.GetPrincipalId())
require.Error(err)
assert.True(errors.IsNotFoundError(err))
})
}
}
func TestManagedGroupRole_Clone(t *testing.T) {
t.Parallel()
t.Run("valid", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
mgr, err := iam.NewManagedGroupRole("r_abc", "mgoidc_abc")
require.NoError(err)
cp := mgr.Clone()
assert.True(proto.Equal(cp.(*iam.ManagedGroupRole).ManagedGroupRole, mgr.ManagedGroupRole))
})
t.Run("not-equal", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
mgr, err := iam.NewManagedGroupRole("r_abc", "mgoidc_abc")
require.NoError(err)
mgr2, err := iam.NewManagedGroupRole("r_xyz", "mgoidc_xyz")
require.NoError(err)
cp := mgr.Clone()
assert.True(!proto.Equal(cp.(*iam.ManagedGroupRole).ManagedGroupRole, mgr2.ManagedGroupRole))
})
}
+38 -2
View File
@@ -571,7 +571,7 @@ func TestGroupRole_Create(t *testing.T) {
wantIsErr: errors.InvalidParameter,
},
{
name: "missing-user-id",
name: "missing-group-id",
args: args{
role: func() *GroupRole {
role := TestRole(t, conn, proj.PublicId)
@@ -584,7 +584,7 @@ func TestGroupRole_Create(t *testing.T) {
}(),
},
wantErr: true,
wantErrMsg: "db.Create: iam.(GroupRole).VetForWrite: missing user id: parameter violation: error #100",
wantErrMsg: "db.Create: iam.(GroupRole).VetForWrite: missing group id: parameter violation: error #100",
wantIsErr: errors.InvalidParameter,
},
{
@@ -865,3 +865,39 @@ func TestGroupRole_SetTableName(t *testing.T) {
})
}
}
func TestManagedGroupRole_SetTableName(t *testing.T) {
defaultTableName := managedGroupRoleDefaultTable
tests := []struct {
name string
initialName string
setNameTo string
want string
}{
{
name: "new-name",
initialName: "",
setNameTo: "new-name",
want: "new-name",
},
{
name: "reset to default",
initialName: "initial",
setNameTo: "",
want: defaultTableName,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
def := AllocManagedGroupRole()
require.Equal(defaultTableName, def.TableName())
s := &ManagedGroupRole{
ManagedGroupRole: &store.ManagedGroupRole{},
tableName: tt.initialName,
}
s.SetTableName(tt.setNameTo)
assert.Equal(tt.want, s.TableName())
})
}
}
+155 -51
View File
@@ -7,6 +7,7 @@ import (
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
)
@@ -24,12 +25,12 @@ func (r *Repository) AddPrincipalRoles(ctx context.Context, roleId string, roleV
if roleVersion == 0 {
return nil, errors.New(errors.InvalidParameter, op, "missing version")
}
userIds, groupIds, err := splitPrincipals(principalIds)
userIds, groupIds, managedGroupIds, err := splitPrincipals(principalIds)
if err != nil {
return nil, errors.Wrap(err, op)
}
if len(userIds) == 0 && len(groupIds) == 0 {
return nil, errors.New(errors.InvalidParameter, op, "missing either user or groups to add")
if len(userIds) == 0 && len(groupIds) == 0 && len(managedGroupIds) == 0 {
return nil, errors.New(errors.InvalidParameter, op, "missing any of users, groups, or managed groups to add")
}
newUserRoles := make([]interface{}, 0, len(userIds))
@@ -48,6 +49,14 @@ func (r *Repository) AddPrincipalRoles(ctx context.Context, roleId string, roleV
}
newGrpRoles = append(newGrpRoles, grpRole)
}
newManagedGrpRoles := make([]interface{}, 0, len(managedGroupIds))
for _, id := range managedGroupIds {
managedGrpRole, err := NewManagedGroupRole(roleId, id)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg("unable to create in memory managed group role"))
}
newManagedGrpRoles = append(newManagedGrpRoles, managedGrpRole)
}
role := allocRole()
role.PublicId = roleId
@@ -98,6 +107,13 @@ func (r *Repository) AddPrincipalRoles(ctx context.Context, roleId string, roleV
}
msgs = append(msgs, grpOplogMsgs...)
}
if len(newManagedGrpRoles) > 0 {
managedGrpOplogMsgs := make([]*oplog.Message, 0, len(newManagedGrpRoles))
if err := w.CreateItems(ctx, newManagedGrpRoles, db.NewOplogMsgs(&managedGrpOplogMsgs)); err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to add managed groups"))
}
msgs = append(msgs, managedGrpOplogMsgs...)
}
metadata := oplog.Metadata{
"op-type": []string{oplog.OpType_OP_TYPE_CREATE.String()},
"scope-id": []string{scope.PublicId},
@@ -147,18 +163,18 @@ func (r *Repository) SetPrincipalRoles(ctx context.Context, roleId string, roleV
// it's "safe" to do this lookup outside the DoTx transaction because we
// have a roleVersion so the principals can’t change without the version
// changing.
userIds, groupIds, err := splitPrincipals(principalIds)
userIds, groupIds, managedGroupIds, err := splitPrincipals(principalIds)
if err != nil {
return nil, db.NoRowsAffected, errors.Wrap(err, op)
}
toSet, err := r.principalsToSet(ctx, &role, userIds, groupIds)
toSet, err := r.PrincipalsToSet(ctx, &role, userIds, groupIds, managedGroupIds)
if err != nil {
return nil, db.NoRowsAffected, errors.Wrap(err, op)
}
// handle no change to existing principal roles
if len(toSet.unchangedPrincipalRoles) > 0 {
return toSet.unchangedPrincipalRoles, db.NoRowsAffected, nil
if len(toSet.UnchangedPrincipalRoles) > 0 {
return toSet.UnchangedPrincipalRoles, db.NoRowsAffected, nil
}
scope, err := role.GetScope(ctx, r.reader)
@@ -204,51 +220,75 @@ func (r *Repository) SetPrincipalRoles(ctx context.Context, roleId string, roleV
}
msgs = append(msgs, &roleOplogMsg)
if len(toSet.deleteUserRoles) > 0 || len(toSet.deleteGroupRoles) > 0 {
if len(toSet.DeleteUserRoles) > 0 ||
len(toSet.DeleteGroupRoles) > 0 ||
len(toSet.DeleteManagedGroupRoles) > 0 {
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
if len(toSet.deleteUserRoles) > 0 {
userOplogMsgs := make([]*oplog.Message, 0, len(toSet.deleteUserRoles))
rowsDeleted, err := w.DeleteItems(ctx, toSet.deleteUserRoles, db.NewOplogMsgs(&userOplogMsgs))
if len(toSet.DeleteUserRoles) > 0 {
userOplogMsgs := make([]*oplog.Message, 0, len(toSet.DeleteUserRoles))
rowsDeleted, err := w.DeleteItems(ctx, toSet.DeleteUserRoles, db.NewOplogMsgs(&userOplogMsgs))
if err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to delete user roles"))
}
if rowsDeleted != len(toSet.deleteUserRoles) {
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("user roles deleted %d did not match request for %d", rowsDeleted, len(toSet.deleteUserRoles)))
if rowsDeleted != len(toSet.DeleteUserRoles) {
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("user roles deleted %d did not match request for %d", rowsDeleted, len(toSet.DeleteUserRoles)))
}
totalRowsAffected += rowsDeleted
msgs = append(msgs, userOplogMsgs...)
}
if len(toSet.deleteGroupRoles) > 0 {
grpOplogMsgs := make([]*oplog.Message, 0, len(toSet.deleteGroupRoles))
rowsDeleted, err := w.DeleteItems(ctx, toSet.deleteGroupRoles, db.NewOplogMsgs(&grpOplogMsgs))
if len(toSet.DeleteGroupRoles) > 0 {
grpOplogMsgs := make([]*oplog.Message, 0, len(toSet.DeleteGroupRoles))
rowsDeleted, err := w.DeleteItems(ctx, toSet.DeleteGroupRoles, db.NewOplogMsgs(&grpOplogMsgs))
if err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to delete groups"))
}
if rowsDeleted != len(toSet.deleteGroupRoles) {
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("group roles deleted %d did not match request for %d", rowsDeleted, len(toSet.deleteGroupRoles)))
if rowsDeleted != len(toSet.DeleteGroupRoles) {
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("group roles deleted %d did not match request for %d", rowsDeleted, len(toSet.DeleteGroupRoles)))
}
totalRowsAffected += rowsDeleted
msgs = append(msgs, grpOplogMsgs...)
}
if len(toSet.DeleteManagedGroupRoles) > 0 {
managedGrpOplogMsgs := make([]*oplog.Message, 0, len(toSet.DeleteManagedGroupRoles))
rowsDeleted, err := w.DeleteItems(ctx, toSet.DeleteManagedGroupRoles, db.NewOplogMsgs(&managedGrpOplogMsgs))
if err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to delete managed groups"))
}
if rowsDeleted != len(toSet.DeleteManagedGroupRoles) {
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("managed group roles deleted %d did not match request for %d", rowsDeleted, len(toSet.DeleteManagedGroupRoles)))
}
totalRowsAffected += rowsDeleted
msgs = append(msgs, managedGrpOplogMsgs...)
}
}
if len(toSet.addUserRoles) > 0 || len(toSet.addGroupRoles) > 0 {
if len(toSet.AddUserRoles) > 0 ||
len(toSet.AddGroupRoles) > 0 ||
len(toSet.AddManagedGroupRoles) > 0 {
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
if len(toSet.addUserRoles) > 0 {
userOplogMsgs := make([]*oplog.Message, 0, len(toSet.addUserRoles))
if err := w.CreateItems(ctx, toSet.addUserRoles, db.NewOplogMsgs(&userOplogMsgs)); err != nil {
if len(toSet.AddUserRoles) > 0 {
userOplogMsgs := make([]*oplog.Message, 0, len(toSet.AddUserRoles))
if err := w.CreateItems(ctx, toSet.AddUserRoles, db.NewOplogMsgs(&userOplogMsgs)); err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to add users"))
}
totalRowsAffected += len(toSet.addUserRoles)
totalRowsAffected += len(toSet.AddUserRoles)
msgs = append(msgs, userOplogMsgs...)
}
if len(toSet.addGroupRoles) > 0 {
grpOplogMsgs := make([]*oplog.Message, 0, len(toSet.addGroupRoles))
if err := w.CreateItems(ctx, toSet.addGroupRoles, db.NewOplogMsgs(&grpOplogMsgs)); err != nil {
if len(toSet.AddGroupRoles) > 0 {
grpOplogMsgs := make([]*oplog.Message, 0, len(toSet.AddGroupRoles))
if err := w.CreateItems(ctx, toSet.AddGroupRoles, db.NewOplogMsgs(&grpOplogMsgs)); err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to add groups"))
}
totalRowsAffected += len(toSet.addGroupRoles)
totalRowsAffected += len(toSet.AddGroupRoles)
msgs = append(msgs, grpOplogMsgs...)
}
if len(toSet.AddManagedGroupRoles) > 0 {
managedGrpOplogMsgs := make([]*oplog.Message, 0, len(toSet.AddManagedGroupRoles))
if err := w.CreateItems(ctx, toSet.AddManagedGroupRoles, db.NewOplogMsgs(&managedGrpOplogMsgs)); err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to add managed groups"))
}
totalRowsAffected += len(toSet.AddManagedGroupRoles)
msgs = append(msgs, managedGrpOplogMsgs...)
}
}
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, roleTicket, metadata, msgs); err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to write oplog"))
@@ -282,12 +322,12 @@ func (r *Repository) DeletePrincipalRoles(ctx context.Context, roleId string, ro
if roleId == "" {
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing role id")
}
userIds, groupIds, err := splitPrincipals(principalIds)
userIds, groupIds, managedGroupIds, err := splitPrincipals(principalIds)
if err != nil {
return db.NoRowsAffected, errors.Wrap(err, op)
}
if len(userIds) == 0 && len(groupIds) == 0 {
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing either user or groups to delete")
if len(userIds) == 0 && len(groupIds) == 0 && len(managedGroupIds) == 0 {
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing any of users, groups, or managed groups to delete")
}
if roleVersion == 0 {
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing version")
@@ -311,6 +351,14 @@ func (r *Repository) DeletePrincipalRoles(ctx context.Context, roleId string, ro
}
deleteGrpRoles = append(deleteGrpRoles, grpRole)
}
deleteManagedGrpRoles := make([]interface{}, 0, len(managedGroupIds))
for _, id := range managedGroupIds {
managedGrpRole, err := NewManagedGroupRole(roleId, id)
if err != nil {
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg("unable to create in memory managed group role"))
}
deleteManagedGrpRoles = append(deleteManagedGrpRoles, managedGrpRole)
}
scope, err := role.GetScope(ctx, r.reader)
if err != nil {
@@ -368,6 +416,18 @@ func (r *Repository) DeletePrincipalRoles(ctx context.Context, roleId string, ro
totalRowsDeleted += rowsDeleted
msgs = append(msgs, grpOplogMsgs...)
}
if len(deleteManagedGrpRoles) > 0 {
managedGrpOplogMsgs := make([]*oplog.Message, 0, len(deleteManagedGrpRoles))
rowsDeleted, err := w.DeleteItems(ctx, deleteManagedGrpRoles, db.NewOplogMsgs(&managedGrpOplogMsgs))
if err != nil {
return errors.Wrap(err, op, errors.WithMsg("unable to delete managed groups"))
}
if rowsDeleted != len(deleteManagedGrpRoles) {
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("managed group roles deleted %d did not match request for %d", rowsDeleted, len(deleteManagedGrpRoles)))
}
totalRowsDeleted += rowsDeleted
msgs = append(msgs, managedGrpOplogMsgs...)
}
metadata := oplog.Metadata{
"op-type": []string{oplog.OpType_OP_TYPE_DELETE.String()},
"scope-id": []string{scope.PublicId},
@@ -401,19 +461,22 @@ func (r *Repository) ListPrincipalRoles(ctx context.Context, roleId string, opt
return principals, nil
}
type principalSet struct {
addUserRoles []interface{}
addGroupRoles []interface{}
deleteUserRoles []interface{}
deleteGroupRoles []interface{}
type PrincipalSet struct {
AddUserRoles []interface{}
AddGroupRoles []interface{}
AddManagedGroupRoles []interface{}
DeleteUserRoles []interface{}
DeleteGroupRoles []interface{}
DeleteManagedGroupRoles []interface{}
// unchangedPrincipalRoles is set iff there are no changes, that is, the
// length of all other members is zero
unchangedPrincipalRoles []PrincipalRole
UnchangedPrincipalRoles []PrincipalRole
}
// TODO: Should this be moved inside the transaction, at this point?
func (r *Repository) principalsToSet(ctx context.Context, role *Role, userIds, groupIds []string) (*principalSet, error) {
const op = "iam.(Repository).principalsToSet"
// PrincipalsToSet sets principals on a role from the given lists.
func (r *Repository) PrincipalsToSet(ctx context.Context, role *Role, userIds, groupIds, managedGroupIds []string) (*PrincipalSet, error) {
const op = "iam.(Repository).PrincipalsToSet"
// TODO(mgaffney) 08/2020: Use SQL to calculate changes.
if role == nil {
return nil, errors.New(errors.InvalidParameter, op, "missing role")
@@ -424,12 +487,15 @@ func (r *Repository) principalsToSet(ctx context.Context, role *Role, userIds, g
}
existingUsers := map[string]PrincipalRole{}
existingGroups := map[string]PrincipalRole{}
existingManagedGroups := map[string]PrincipalRole{}
for _, p := range existing {
switch p.GetType() {
case UserRoleType.String():
existingUsers[p.PrincipalId] = p
case GroupRoleType.String():
existingGroups[p.PrincipalId] = p
case ManagedGroupRoleType.String():
existingManagedGroups[p.PrincipalId] = p
default:
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("%s is unknown principal type %s", p.PrincipalId, p.GetType()))
}
@@ -458,6 +524,18 @@ func (r *Repository) principalsToSet(ctx context.Context, role *Role, userIds, g
newGrpRoles = append(newGrpRoles, grpRole)
}
}
var newManagedGrpRoles []interface{}
managedGroupIdsMap := map[string]struct{}{}
for _, id := range managedGroupIds {
managedGroupIdsMap[id] = struct{}{}
if _, ok := existingManagedGroups[id]; !ok {
managedGrpRole, err := NewManagedGroupRole(role.PublicId, id)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg("unable to create in memory managed group role for add"))
}
newManagedGrpRoles = append(newManagedGrpRoles, managedGrpRole)
}
}
var deleteUserRoles []interface{}
for _, p := range existingUsers {
if _, ok := userIdsMap[p.PrincipalId]; !ok {
@@ -478,35 +556,61 @@ func (r *Repository) principalsToSet(ctx context.Context, role *Role, userIds, g
deleteGrpRoles = append(deleteGrpRoles, grpRole)
}
}
toSet := &principalSet{
addUserRoles: newUserRoles,
addGroupRoles: newGrpRoles,
deleteUserRoles: deleteUserRoles,
deleteGroupRoles: deleteGrpRoles,
var deleteManagedGrpRoles []interface{}
for _, p := range existingManagedGroups {
if _, ok := managedGroupIdsMap[p.PrincipalId]; !ok {
managedGrpRole, err := NewManagedGroupRole(p.GetRoleId(), p.GetPrincipalId())
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg("unable to create in memory managed group role for delete"))
}
deleteManagedGrpRoles = append(deleteManagedGrpRoles, managedGrpRole)
}
}
if len(toSet.addUserRoles) == 0 && len(toSet.addGroupRoles) == 0 && len(toSet.deleteUserRoles) == 0 && len(toSet.deleteGroupRoles) == 0 {
toSet.unchangedPrincipalRoles = existing
toSet := &PrincipalSet{
AddUserRoles: newUserRoles,
AddGroupRoles: newGrpRoles,
AddManagedGroupRoles: newManagedGrpRoles,
DeleteUserRoles: deleteUserRoles,
DeleteGroupRoles: deleteGrpRoles,
DeleteManagedGroupRoles: deleteManagedGrpRoles,
}
if len(toSet.AddUserRoles) == 0 &&
len(toSet.AddGroupRoles) == 0 &&
len(toSet.AddManagedGroupRoles) == 0 &&
len(toSet.DeleteUserRoles) == 0 &&
len(toSet.DeleteGroupRoles) == 0 &&
len(toSet.DeleteManagedGroupRoles) == 0 {
toSet.UnchangedPrincipalRoles = existing
}
return toSet, nil
}
func splitPrincipals(principals []string) ([]string, []string, error) {
func splitPrincipals(principals []string) (users, groups, managedGroups []string, retErr error) {
const op = "iam.splitPrincipals"
var users, groups []string
for _, principal := range principals {
switch {
case strings.HasPrefix(principal, UserPrefix):
if users == nil {
users = make([]string, 0, len(principals))
}
users = append(users, principal)
// TODO: This needs to handle all of the kinds of group prefixes (sg_, dg_, etc.)
case strings.HasPrefix(principal, GroupPrefix):
if groups == nil {
groups = make([]string, 0, len(principals))
}
groups = append(groups, principal)
case strings.HasPrefix(principal, intglobals.OidcManagedGroupPrefix):
if managedGroups == nil {
managedGroups = make([]string, 0, len(principals))
}
managedGroups = append(managedGroups, principal)
default:
return nil, nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("invalid principal ID %q", principal))
return nil, nil, nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("invalid principal ID %q", principal))
}
}
return users, groups, nil
return
}
@@ -0,0 +1,251 @@
package iam_test
import (
"context"
"sort"
"testing"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRepository_PrincipalsToSet(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrap)
repo := iam.TestRepo(t, conn, wrap)
org, proj := iam.TestScopes(t, repo)
ctx := context.Background()
databaseWrapper, err := kmsCache.GetWrapper(ctx, org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, org.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
createUsersFn := func() []string {
results := []string{}
for i := 0; i < 5; i++ {
u := iam.TestUser(t, repo, org.PublicId)
results = append(results, u.PublicId)
}
return results
}
createGrpsFn := func() []string {
results := []string{}
for i := 0; i < 5; i++ {
g := iam.TestGroup(t, conn, proj.PublicId)
results = append(results, g.PublicId)
}
return results
}
createManagedGrpsFn := func() []string {
results := []string{}
for i := 0; i < 5; i++ {
g := oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter)
results = append(results, g.PublicId)
}
return results
}
setupFn := func() (*iam.Role, []string, []string, []string) {
users := createUsersFn()
grps := createGrpsFn()
managedGrps := createManagedGrpsFn()
role := iam.TestRole(t, conn, proj.PublicId)
_, err := repo.AddPrincipalRoles(context.Background(), role.PublicId, 1, append(users, append(grps, managedGrps...)...))
require.NoError(t, err)
return role, users, grps, managedGrps
}
type args struct {
userIds []string
groupIds []string
managedGroupIds []string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "all new",
args: args{
userIds: createUsersFn(),
groupIds: createGrpsFn(),
managedGroupIds: createManagedGrpsFn(),
},
wantErr: false,
},
{
name: "clear all",
args: args{
userIds: nil,
groupIds: nil,
managedGroupIds: nil,
},
wantErr: false,
},
{
name: "just new users",
args: args{
userIds: createUsersFn(),
groupIds: nil,
managedGroupIds: nil,
},
wantErr: false,
},
{
name: "just new groups",
args: args{
userIds: nil,
groupIds: createGrpsFn(),
managedGroupIds: nil,
},
wantErr: false,
},
{
name: "just new managed groups",
args: args{
userIds: nil,
groupIds: nil,
managedGroupIds: createManagedGrpsFn(),
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
r, origUsers, origGrps, origManagedGrps := setupFn()
got, err := repo.PrincipalsToSet(context.Background(), r, tt.args.userIds, tt.args.groupIds, tt.args.managedGroupIds)
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
assertSetResults(t, got, tt.args.userIds, tt.args.groupIds, tt.args.managedGroupIds, origUsers, origGrps, origManagedGrps)
})
}
t.Run("nil role", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, users, grps, managedGrps := setupFn()
got, err := repo.PrincipalsToSet(context.Background(), nil, users, grps, managedGrps)
require.Error(err)
assert.Nil(got)
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
})
t.Run("no change", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
r, users, grps, managedGrps := setupFn()
got, err := repo.PrincipalsToSet(context.Background(), r, users, grps, managedGrps)
require.NoError(err)
assert.Empty(got.AddUserRoles)
assert.Empty(got.AddGroupRoles)
assert.Empty(got.AddManagedGroupRoles)
assert.Empty(got.DeleteUserRoles)
assert.Empty(got.DeleteGroupRoles)
assert.Empty(got.DeleteManagedGroupRoles)
assert.Equal(len(users)+len(grps)+len(managedGrps), len(got.UnchangedPrincipalRoles))
})
t.Run("mixed", func(t *testing.T) {
require := require.New(t)
r, users, grps, managedGrps := setupFn()
var wantSetUsers, wantSetGrps, wantSetManagedGrps, wantDeleteUsers, wantDeleteGrps, wantDeleteManagedGrps []string
for i, id := range users {
if i < 2 {
wantSetUsers = append(wantSetUsers, id)
} else {
wantDeleteUsers = append(wantDeleteUsers, id)
}
}
for i, id := range grps {
if i < 2 {
wantSetGrps = append(wantSetGrps, id)
} else {
wantDeleteGrps = append(wantDeleteGrps, id)
}
}
for i, id := range managedGrps {
if i < 2 {
wantSetManagedGrps = append(wantSetManagedGrps, id)
} else {
wantDeleteManagedGrps = append(wantDeleteManagedGrps, id)
}
}
newUser := iam.TestUser(t, repo, org.PublicId)
newGrp := iam.TestGroup(t, conn, proj.PublicId)
newManagedGrp := oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter)
wantSetUsers = append(wantSetUsers, newUser.PublicId)
wantSetGrps = append(wantSetGrps, newGrp.PublicId)
wantSetManagedGrps = append(wantSetManagedGrps, newManagedGrp.PublicId)
got, err := repo.PrincipalsToSet(context.Background(), r, wantSetUsers, wantSetGrps, wantSetManagedGrps)
require.NoError(err)
assertSetResults(t, got, []string{newUser.PublicId}, []string{newGrp.PublicId}, []string{newManagedGrp.PublicId}, wantDeleteUsers, wantDeleteGrps, wantDeleteManagedGrps)
})
}
func assertSetResults(t *testing.T, got *iam.PrincipalSet, wantAddUsers, wantAddGroups, wantAddManagedGroups, wantDeleteUsers, wantDeleteGroups, wantDeleteManagedGroups []string) {
t.Helper()
assert := assert.New(t)
var gotAddUsers []string
for _, r := range got.AddUserRoles {
gotAddUsers = append(gotAddUsers, r.(*iam.UserRole).PrincipalId)
}
// sort.Strings(wantAddUsers)
// sort.Strings(gotAddUsers)
assert.Equal(wantAddUsers, gotAddUsers)
var gotAddGrps []string
for _, r := range got.AddGroupRoles {
gotAddGrps = append(gotAddGrps, r.(*iam.GroupRole).PrincipalId)
}
// sort.Strings(wantAddGroups)
// sort.Strings(gotAddGrps)
assert.Equal(wantAddGroups, gotAddGrps)
var gotAddManagedGrps []string
for _, r := range got.AddManagedGroupRoles {
gotAddManagedGrps = append(gotAddManagedGrps, r.(*iam.ManagedGroupRole).PrincipalId)
}
// sort.Strings(wantAddGroups)
// sort.Strings(gotAddGrps)
assert.Equal(wantAddManagedGroups, gotAddManagedGrps)
var gotDeleteUsers []string
for _, r := range got.DeleteUserRoles {
gotDeleteUsers = append(gotDeleteUsers, r.(*iam.UserRole).PrincipalId)
}
sort.Strings(wantDeleteUsers)
sort.Strings(gotDeleteUsers)
assert.Equal(wantDeleteUsers, gotDeleteUsers)
var gotDeleteGroups []string
for _, r := range got.DeleteGroupRoles {
gotDeleteGroups = append(gotDeleteGroups, r.(*iam.GroupRole).PrincipalId)
}
sort.Strings(wantDeleteGroups)
sort.Strings(gotDeleteGroups)
assert.Equal(wantDeleteGroups, gotDeleteGroups)
var gotDeleteManagedGroups []string
for _, r := range got.DeleteManagedGroupRoles {
gotDeleteManagedGroups = append(gotDeleteManagedGroups, r.(*iam.ManagedGroupRole).PrincipalId)
}
sort.Strings(wantDeleteManagedGroups)
sort.Strings(gotDeleteManagedGroups)
assert.Equal(wantDeleteManagedGroups, gotDeleteManagedGroups)
}
@@ -677,173 +677,3 @@ func TestRepository_SetPrincipalRoles(t *testing.T) {
})
}
}
func TestRepository_principalsToSet(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
repo := TestRepo(t, conn, wrapper)
org, proj := TestScopes(t, repo)
createUsersFn := func() []string {
results := []string{}
for i := 0; i < 5; i++ {
u := TestUser(t, repo, org.PublicId)
results = append(results, u.PublicId)
}
return results
}
createGrpsFn := func() []string {
results := []string{}
for i := 0; i < 5; i++ {
g := TestGroup(t, conn, proj.PublicId)
results = append(results, g.PublicId)
}
return results
}
setupFn := func() (*Role, []string, []string) {
users := createUsersFn()
grps := createGrpsFn()
role := TestRole(t, conn, proj.PublicId)
_, err := repo.AddPrincipalRoles(context.Background(), role.PublicId, 1, append(users, grps...))
require.NoError(t, err)
return role, users, grps
}
type args struct {
userIds []string
groupIds []string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "all new",
args: args{
userIds: createUsersFn(),
groupIds: createGrpsFn(),
},
wantErr: false,
},
{
name: "clear all",
args: args{
userIds: nil,
groupIds: nil,
},
wantErr: false,
},
{
name: "just new users",
args: args{
userIds: createUsersFn(),
groupIds: nil,
},
wantErr: false,
},
{
name: "just new groups",
args: args{
userIds: nil,
groupIds: createGrpsFn(),
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
r, origUsers, origGrps := setupFn()
got, err := repo.principalsToSet(context.Background(), r, tt.args.userIds, tt.args.groupIds)
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
assertSetResults(t, got, tt.args.userIds, tt.args.groupIds, origUsers, origGrps)
})
}
t.Run("nil role", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, users, grps := setupFn()
got, err := repo.principalsToSet(context.Background(), nil, users, grps)
require.Error(err)
assert.Nil(got)
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
})
t.Run("no change", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
r, users, grps := setupFn()
got, err := repo.principalsToSet(context.Background(), r, users, grps)
require.NoError(err)
assert.Empty(got.addUserRoles)
assert.Empty(got.addGroupRoles)
assert.Empty(got.deleteUserRoles)
assert.Empty(got.deleteGroupRoles)
assert.Equal(len(users)+len(grps), len(got.unchangedPrincipalRoles))
})
t.Run("mixed", func(t *testing.T) {
require := require.New(t)
r, users, grps := setupFn()
var wantSetUsers, wantSetGrps, wantDeleteUsers, wantDeleteGrps []string
for i, id := range users {
if i < 2 {
wantSetUsers = append(wantSetUsers, id)
} else {
wantDeleteUsers = append(wantDeleteUsers, id)
}
}
for i, id := range grps {
if i < 2 {
wantSetGrps = append(wantSetGrps, id)
} else {
wantDeleteGrps = append(wantDeleteGrps, id)
}
}
newUser := TestUser(t, repo, org.PublicId)
newGrp := TestGroup(t, conn, proj.PublicId)
wantSetUsers = append(wantSetUsers, newUser.PublicId)
wantSetGrps = append(wantSetGrps, newGrp.PublicId)
got, err := repo.principalsToSet(context.Background(), r, wantSetUsers, wantSetGrps)
require.NoError(err)
assertSetResults(t, got, []string{newUser.PublicId}, []string{newGrp.PublicId}, wantDeleteUsers, wantDeleteGrps)
})
}
func assertSetResults(t *testing.T, got *principalSet, wantAddUsers, wantAddGroups, wantDeleteUsers, wantDeleteGroups []string) {
t.Helper()
assert := assert.New(t)
var gotAddUsers []string
for _, r := range got.addUserRoles {
gotAddUsers = append(gotAddUsers, r.(*UserRole).PrincipalId)
}
// sort.Strings(wantAddUsers)
// sort.Strings(gotAddUsers)
assert.Equal(wantAddUsers, gotAddUsers)
var gotAddGrps []string
for _, r := range got.addGroupRoles {
gotAddGrps = append(gotAddGrps, r.(*GroupRole).PrincipalId)
}
// sort.Strings(wantAddGroups)
// sort.Strings(gotAddGrps)
assert.Equal(wantAddGroups, gotAddGrps)
var gotDeleteUsers []string
for _, r := range got.deleteUserRoles {
gotDeleteUsers = append(gotDeleteUsers, r.(*UserRole).PrincipalId)
}
sort.Strings(wantDeleteUsers)
sort.Strings(gotDeleteUsers)
assert.Equal(wantDeleteUsers, gotDeleteUsers)
var gotDeleteGroups []string
for _, r := range got.deleteGroupRoles {
gotDeleteGroups = append(gotDeleteGroups, r.(*GroupRole).PrincipalId)
}
sort.Strings(wantDeleteGroups)
sort.Strings(gotDeleteGroups)
assert.Equal(wantDeleteGroups, gotDeleteGroups)
}
+132 -39
View File
@@ -159,6 +159,75 @@ func (x *GroupRole) GetPrincipalId() string {
return ""
}
type ManagedGroupRole struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
CreateTime *timestamp.Timestamp `protobuf:"bytes,1,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
// role_id is the role of this principal.
// @inject_tag: gorm:"primary_key"
RoleId string `protobuf:"bytes,2,opt,name=role_id,json=roleId,proto3" json:"role_id,omitempty" gorm:"primary_key"`
// principal_id is the public_id of the managed group (which is the principal)
// @inject_tag: gorm:"primary_key"
PrincipalId string `protobuf:"bytes,3,opt,name=principal_id,json=principalId,proto3" json:"principal_id,omitempty" gorm:"primary_key"`
}
func (x *ManagedGroupRole) Reset() {
*x = ManagedGroupRole{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ManagedGroupRole) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ManagedGroupRole) ProtoMessage() {}
func (x *ManagedGroupRole) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ManagedGroupRole.ProtoReflect.Descriptor instead.
func (*ManagedGroupRole) Descriptor() ([]byte, []int) {
return file_controller_storage_iam_store_v1_principal_role_proto_rawDescGZIP(), []int{2}
}
func (x *ManagedGroupRole) GetCreateTime() *timestamp.Timestamp {
if x != nil {
return x.CreateTime
}
return nil
}
func (x *ManagedGroupRole) GetRoleId() string {
if x != nil {
return x.RoleId
}
return ""
}
func (x *ManagedGroupRole) GetPrincipalId() string {
if x != nil {
return x.PrincipalId
}
return ""
}
type PrincipalRoleView struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -188,7 +257,7 @@ type PrincipalRoleView struct {
func (x *PrincipalRoleView) Reset() {
*x = PrincipalRoleView{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[2]
mi := &file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -201,7 +270,7 @@ func (x *PrincipalRoleView) String() string {
func (*PrincipalRoleView) ProtoMessage() {}
func (x *PrincipalRoleView) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[2]
mi := &file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -214,7 +283,7 @@ func (x *PrincipalRoleView) ProtoReflect() protoreflect.Message {
// Deprecated: Use PrincipalRoleView.ProtoReflect.Descriptor instead.
func (*PrincipalRoleView) Descriptor() ([]byte, []int) {
return file_controller_storage_iam_store_v1_principal_role_proto_rawDescGZIP(), []int{2}
return file_controller_storage_iam_store_v1_principal_role_proto_rawDescGZIP(), []int{3}
}
func (x *PrincipalRoleView) GetCreateTime() *timestamp.Timestamp {
@@ -296,30 +365,40 @@ var file_controller_storage_iam_store_v1_principal_role_proto_rawDesc = []byte{
0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65,
0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f,
0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69,
0x70, 0x61, 0x6c, 0x49, 0x64, 0x22, 0xb2, 0x02, 0x0a, 0x11, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69,
0x70, 0x61, 0x6c, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x4b, 0x0a, 0x0b, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65,
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70,
0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69,
0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6e,
0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53,
0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x73,
0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72,
0x6f, 0x6c, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x63,
0x6f, 0x70, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69,
0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x50,
0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x70, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76,
0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f,
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64,
0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69, 0x64,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61,
0x6c, 0x49, 0x64, 0x22, 0xb2, 0x02, 0x0a, 0x11, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61,
0x6c, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72,
0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61,
0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12,
0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c,
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6e, 0x63,
0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69,
0x70, 0x61, 0x6c, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01,
0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, 0x63, 0x6f,
0x70, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x73, 0x63, 0x6f,
0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6c,
0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x63, 0x6f, 0x70,
0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18,
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x50, 0x72, 0x69,
0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f,
0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -334,22 +413,24 @@ func file_controller_storage_iam_store_v1_principal_role_proto_rawDescGZIP() []b
return file_controller_storage_iam_store_v1_principal_role_proto_rawDescData
}
var file_controller_storage_iam_store_v1_principal_role_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_controller_storage_iam_store_v1_principal_role_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_controller_storage_iam_store_v1_principal_role_proto_goTypes = []interface{}{
(*UserRole)(nil), // 0: controller.storage.iam.store.v1.UserRole
(*GroupRole)(nil), // 1: controller.storage.iam.store.v1.GroupRole
(*PrincipalRoleView)(nil), // 2: controller.storage.iam.store.v1.PrincipalRoleView
(*timestamp.Timestamp)(nil), // 3: controller.storage.timestamp.v1.Timestamp
(*ManagedGroupRole)(nil), // 2: controller.storage.iam.store.v1.ManagedGroupRole
(*PrincipalRoleView)(nil), // 3: controller.storage.iam.store.v1.PrincipalRoleView
(*timestamp.Timestamp)(nil), // 4: controller.storage.timestamp.v1.Timestamp
}
var file_controller_storage_iam_store_v1_principal_role_proto_depIdxs = []int32{
3, // 0: controller.storage.iam.store.v1.UserRole.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
3, // 1: controller.storage.iam.store.v1.GroupRole.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
3, // 2: controller.storage.iam.store.v1.PrincipalRoleView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
4, // 0: controller.storage.iam.store.v1.UserRole.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 1: controller.storage.iam.store.v1.GroupRole.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 2: controller.storage.iam.store.v1.ManagedGroupRole.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 3: controller.storage.iam.store.v1.PrincipalRoleView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_controller_storage_iam_store_v1_principal_role_proto_init() }
@@ -383,6 +464,18 @@ func file_controller_storage_iam_store_v1_principal_role_proto_init() {
}
}
file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ManagedGroupRole); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_storage_iam_store_v1_principal_role_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PrincipalRoleView); i {
case 0:
return &v.state
@@ -401,7 +494,7 @@ func file_controller_storage_iam_store_v1_principal_role_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_storage_iam_store_v1_principal_role_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
+12
View File
@@ -242,6 +242,18 @@ func TestGroupRole(t *testing.T, conn *gorm.DB, roleId, grpId string, opt ...Opt
return r
}
func TestManagedGroupRole(t *testing.T, conn *gorm.DB, roleId, managedGrpId string, opt ...Option) *ManagedGroupRole {
t.Helper()
require := require.New(t)
rw := db.New(conn)
r, err := NewManagedGroupRole(roleId, managedGrpId, opt...)
require.NoError(err)
err = rw.Create(context.Background(), r)
require.NoError(err)
return r
}
// testAccount is a temporary test function. TODO - replace with an auth
// subsystem testAccount function. If userId is zero value, then an auth
// account will be created with a null IamUserId
+12
View File
@@ -0,0 +1,12 @@
package intglobals
// This set of consts is intended to be a place to collect commonly-used
// prefixes. This can avoid some cross-package dependency issues. Unlike the
// top-level globals package, these are not currently meant to be available to
// clients or test writers.
const (
// OidcManagedGroupPrefix defines the prefix for ManagedGroup public ids
// from the OIDC auth method.
OidcManagedGroupPrefix = "mgoidc"
)
@@ -34,6 +34,20 @@ message GroupRole {
string principal_id = 3;
}
message ManagedGroupRole {
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 1;
// role_id is the role of this principal.
// @inject_tag: gorm:"primary_key"
string role_id = 2;
// principal_id is the public_id of the managed group (which is the principal)
// @inject_tag: gorm:"primary_key"
string principal_id = 3;
}
message PrincipalRoleView {
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
@@ -11,6 +11,7 @@ import (
"github.com/hashicorp/boundary/internal/errors"
pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/managedgroups"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/servers/controller/common"
@@ -576,7 +577,7 @@ func validateGetRequest(req *pbs.GetManagedGroupRequest) error {
if req == nil {
return errors.New(errors.InvalidParameter, op, "nil request")
}
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, oidc.ManagedGroupPrefix)
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, intglobals.OidcManagedGroupPrefix)
}
func validateCreateRequest(req *pbs.CreateManagedGroupRequest) error {
@@ -639,7 +640,7 @@ func validateUpdateRequest(req *pbs.UpdateManagedGroupRequest) error {
}
}
return badFields
}, oidc.ManagedGroupPrefix)
}, intglobals.OidcManagedGroupPrefix)
}
func validateDeleteRequest(req *pbs.DeleteManagedGroupRequest) error {
@@ -647,7 +648,7 @@ func validateDeleteRequest(req *pbs.DeleteManagedGroupRequest) error {
if req == nil {
return errors.New(errors.InvalidParameter, op, "nil request")
}
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, oidc.ManagedGroupPrefix)
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, intglobals.OidcManagedGroupPrefix)
}
func validateListRequest(req *pbs.ListManagedGroupsRequest) error {
@@ -19,6 +19,7 @@ import (
scopepb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
@@ -42,8 +43,6 @@ var oidcAuthorizedActions = []string{
action.Delete.String(),
}
const testFakeManagedGroupFilter = `"/foo" == "bar"`
func TestNewService(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
@@ -107,7 +106,7 @@ func TestGet(t *testing.T) {
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
oidcA := oidc.TestAccount(t, conn, oidcAm, "test-subject")
omg := oidc.TestManagedGroup(t, conn, oidcAm, testFakeManagedGroupFilter)
omg := oidc.TestManagedGroup(t, conn, oidcAm, oidc.TestFakeManagedGroupFilter)
// Set up managed group before getting. First get the current
// managed group to make sure we have the right version, then ensure
@@ -148,7 +147,7 @@ func TestGet(t *testing.T) {
},
{
name: "Get a non existing oidc managed group",
req: &pbs.GetManagedGroupRequest{Id: oidc.ManagedGroupPrefix + "_DoesntExis"},
req: &pbs.GetManagedGroupRequest{Id: intglobals.OidcManagedGroupPrefix + "_DoesntExis"},
res: nil,
err: handlers.ApiErrorWithCode(codes.NotFound),
},
@@ -205,7 +204,7 @@ func TestListOidc(t *testing.T) {
var wantSomeManagedGroups []*pb.ManagedGroup
for i := 0; i < 3; i++ {
mg := oidc.TestManagedGroup(t, conn, amSomeManagedGroups, testFakeManagedGroupFilter, oidc.WithName(strconv.Itoa(i)))
mg := oidc.TestManagedGroup(t, conn, amSomeManagedGroups, oidc.TestFakeManagedGroupFilter, oidc.WithName(strconv.Itoa(i)))
wantSomeManagedGroups = append(wantSomeManagedGroups, &pb.ManagedGroup{
Id: mg.GetPublicId(),
AuthMethodId: mg.GetAuthMethodId(),
@@ -216,7 +215,7 @@ func TestListOidc(t *testing.T) {
Version: 1,
Type: auth.OidcSubtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"filter": structpb.NewStringValue(testFakeManagedGroupFilter),
"filter": structpb.NewStringValue(oidc.TestFakeManagedGroupFilter),
}},
AuthorizedActions: oidcAuthorizedActions,
})
@@ -224,7 +223,7 @@ func TestListOidc(t *testing.T) {
var wantOtherManagedGroups []*pb.ManagedGroup
for i := 0; i < 3; i++ {
mg := oidc.TestManagedGroup(t, conn, amOtherManagedGroups, testFakeManagedGroupFilter, oidc.WithName(strconv.Itoa(i)))
mg := oidc.TestManagedGroup(t, conn, amOtherManagedGroups, oidc.TestFakeManagedGroupFilter, oidc.WithName(strconv.Itoa(i)))
wantOtherManagedGroups = append(wantOtherManagedGroups, &pb.ManagedGroup{
Id: mg.GetPublicId(),
AuthMethodId: mg.GetAuthMethodId(),
@@ -235,7 +234,7 @@ func TestListOidc(t *testing.T) {
Version: 1,
Type: auth.OidcSubtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"filter": structpb.NewStringValue(testFakeManagedGroupFilter),
"filter": structpb.NewStringValue(oidc.TestFakeManagedGroupFilter),
}},
AuthorizedActions: oidcAuthorizedActions,
})
@@ -352,7 +351,7 @@ func TestDelete(t *testing.T) {
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
oidcMg := oidc.TestManagedGroup(t, conn, oidcAm, testFakeManagedGroupFilter)
oidcMg := oidc.TestManagedGroup(t, conn, oidcAm, oidc.TestFakeManagedGroupFilter)
s, err := managed_groups.NewService(oidcRepoFn)
require.NoError(t, err, "Error when getting new user service.")
@@ -373,7 +372,7 @@ func TestDelete(t *testing.T) {
{
name: "Delete bad oidc managed group id",
req: &pbs.DeleteManagedGroupRequest{
Id: oidc.ManagedGroupPrefix + "_doesntexis",
Id: intglobals.OidcManagedGroupPrefix + "_doesntexis",
},
err: handlers.ApiErrorWithCode(codes.NotFound),
},
@@ -423,7 +422,7 @@ func TestDelete_twice(t *testing.T) {
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
oidcMg := oidc.TestManagedGroup(t, conn, oidcAm, testFakeManagedGroupFilter)
oidcMg := oidc.TestManagedGroup(t, conn, oidcAm, oidc.TestFakeManagedGroupFilter)
s, err := managed_groups.NewService(oidcRepoFn)
require.NoError(err, "Error when getting new user service")
@@ -465,7 +464,7 @@ func TestCreateOidc(t *testing.T) {
)
createAttr := func() *structpb.Struct {
attr := &pb.OidcManagedGroupAttributes{Filter: testFakeManagedGroupFilter}
attr := &pb.OidcManagedGroupAttributes{Filter: oidc.TestFakeManagedGroupFilter}
ret, err := handlers.ProtoToStruct(attr)
require.NoError(t, err, "Error converting proto to struct.")
return ret
@@ -489,7 +488,7 @@ func TestCreateOidc(t *testing.T) {
},
},
res: &pbs.CreateManagedGroupResponse{
Uri: fmt.Sprintf("managed-groups/%s_", oidc.ManagedGroupPrefix),
Uri: fmt.Sprintf("managed-groups/%s_", intglobals.OidcManagedGroupPrefix),
Item: &pb.ManagedGroup{
AuthMethodId: am.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "name"},
@@ -499,7 +498,7 @@ func TestCreateOidc(t *testing.T) {
Type: auth.OidcSubtype.String(),
Attributes: func() *structpb.Struct {
a := createAttr()
a.Fields["filter"] = structpb.NewStringValue(testFakeManagedGroupFilter)
a.Fields["filter"] = structpb.NewStringValue(oidc.TestFakeManagedGroupFilter)
return a
}(),
AuthorizedActions: oidcAuthorizedActions,
@@ -515,7 +514,7 @@ func TestCreateOidc(t *testing.T) {
},
},
res: &pbs.CreateManagedGroupResponse{
Uri: fmt.Sprintf("managed-groups/%s_", oidc.ManagedGroupPrefix),
Uri: fmt.Sprintf("managed-groups/%s_", intglobals.OidcManagedGroupPrefix),
Item: &pb.ManagedGroup{
AuthMethodId: am.GetPublicId(),
Scope: &scopepb.ScopeInfo{Id: o.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
@@ -523,7 +522,7 @@ func TestCreateOidc(t *testing.T) {
Type: auth.OidcSubtype.String(),
Attributes: func() *structpb.Struct {
a := createAttr()
a.Fields["filter"] = structpb.NewStringValue(testFakeManagedGroupFilter)
a.Fields["filter"] = structpb.NewStringValue(oidc.TestFakeManagedGroupFilter)
return a
}(),
AuthorizedActions: oidcAuthorizedActions,
@@ -547,7 +546,7 @@ func TestCreateOidc(t *testing.T) {
req: &pbs.CreateManagedGroupRequest{
Item: &pb.ManagedGroup{
AuthMethodId: am.GetPublicId(),
Id: oidc.ManagedGroupPrefix + "_notallowed",
Id: intglobals.OidcManagedGroupPrefix + "_notallowed",
Type: auth.OidcSubtype.String(),
Attributes: createAttr(),
},
@@ -611,7 +610,7 @@ func TestCreateOidc(t *testing.T) {
require.NoError(gErr)
if got != nil {
assert.Contains(got.GetUri(), tc.res.Uri)
assert.True(strings.HasPrefix(got.GetItem().GetId(), oidc.ManagedGroupPrefix+"_"))
assert.True(strings.HasPrefix(got.GetItem().GetId(), intglobals.OidcManagedGroupPrefix+"_"))
// Clear all values which are hard to compare against.
got.Uri, tc.res.Uri = "", ""
got.Item.Id, tc.res.Item.Id = "", ""
@@ -651,7 +650,7 @@ func TestUpdateOidc(t *testing.T) {
defaultScopeInfo := &scopepb.ScopeInfo{Id: o.GetPublicId(), Type: o.GetType(), ParentScopeId: scope.Global.String()}
defaultAttributes := &structpb.Struct{Fields: map[string]*structpb.Value{
"filter": structpb.NewStringValue(testFakeManagedGroupFilter),
"filter": structpb.NewStringValue(oidc.TestFakeManagedGroupFilter),
}}
modifiedFilter := `"/token/zip" == "zap"`
@@ -666,7 +665,7 @@ func TestUpdateOidc(t *testing.T) {
freshManagedGroup := func(t *testing.T) (*oidc.ManagedGroup, func()) {
t.Helper()
mg := oidc.TestManagedGroup(t, conn, am, testFakeManagedGroupFilter, oidc.WithName("default"), oidc.WithDescription("default"))
mg := oidc.TestManagedGroup(t, conn, am, oidc.TestFakeManagedGroupFilter, oidc.WithName("default"), oidc.WithDescription("default"))
clean := func() {
_, err := tested.DeleteManagedGroup(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()),
@@ -852,7 +851,7 @@ func TestUpdateOidc(t *testing.T) {
{
name: "Update a Non Existing ManagedGroup",
req: &pbs.UpdateManagedGroupRequest{
Id: oidc.ManagedGroupPrefix + "_DoesntExis",
Id: intglobals.OidcManagedGroupPrefix + "_DoesntExis",
UpdateMask: &field_mask.FieldMask{
Paths: []string{globals.DescriptionField},
},
@@ -870,7 +869,7 @@ func TestUpdateOidc(t *testing.T) {
Paths: []string{"id"},
},
Item: &pb.ManagedGroup{
Id: oidc.ManagedGroupPrefix + "_somethinge",
Id: intglobals.OidcManagedGroupPrefix + "_somethinge",
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "new desc"},
},
@@ -10,6 +10,7 @@ import (
"github.com/hashicorp/boundary/internal/auth/oidc"
pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/managedgroups"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/fieldmaskpb"
@@ -98,7 +99,7 @@ func TestValidateUpdateRequest(t *testing.T) {
{
name: "oidc to password change type",
req: &pbs.UpdateManagedGroupRequest{
Id: oidc.ManagedGroupPrefix + "_1234567890",
Id: intglobals.OidcManagedGroupPrefix + "_1234567890",
Item: &pb.ManagedGroup{
Type: auth.PasswordSubtype.String(),
},
@@ -108,7 +109,7 @@ func TestValidateUpdateRequest(t *testing.T) {
{
name: "oidc bad attributes",
req: &pbs.UpdateManagedGroupRequest{
Id: oidc.ManagedGroupPrefix + "_1234567890",
Id: intglobals.OidcManagedGroupPrefix + "_1234567890",
Item: &pb.ManagedGroup{
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"test": structpb.NewStringValue("something"),
@@ -120,7 +121,7 @@ func TestValidateUpdateRequest(t *testing.T) {
{
name: "no error",
req: &pbs.UpdateManagedGroupRequest{
Id: oidc.ManagedGroupPrefix + "_1234567890",
Id: intglobals.OidcManagedGroupPrefix + "_1234567890",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{}},
Item: &pb.ManagedGroup{
Version: 1,
@@ -11,6 +11,7 @@ import (
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/iam/store"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/servers/controller/common"
@@ -967,8 +968,10 @@ func validateAddRolePrincipalsRequest(req *pbs.AddRolePrincipalsRequest) error {
badFields["principal_ids"] = "Must be non-empty."
}
for _, id := range req.GetPrincipalIds() {
if !handlers.ValidId(handlers.Id(id), iam.GroupPrefix) && !handlers.ValidId(handlers.Id(id), iam.UserPrefix) {
badFields["principal_ids"] = "Must only have valid group and/or user ids."
if !handlers.ValidId(handlers.Id(id), iam.GroupPrefix) &&
!handlers.ValidId(handlers.Id(id), iam.UserPrefix) &&
!handlers.ValidId(handlers.Id(id), intglobals.OidcManagedGroupPrefix) {
badFields["principal_ids"] = "Must only have valid user, group, and/or managed group ids."
break
}
if id == "u_recovery" {
@@ -991,8 +994,10 @@ func validateSetRolePrincipalsRequest(req *pbs.SetRolePrincipalsRequest) error {
badFields["version"] = "Required field."
}
for _, id := range req.GetPrincipalIds() {
if !handlers.ValidId(handlers.Id(id), iam.GroupPrefix) && !handlers.ValidId(handlers.Id(id), iam.UserPrefix) {
badFields["principal_ids"] = "Must only have valid group and/or user ids."
if !handlers.ValidId(handlers.Id(id), iam.GroupPrefix) &&
!handlers.ValidId(handlers.Id(id), iam.UserPrefix) &&
!handlers.ValidId(handlers.Id(id), intglobals.OidcManagedGroupPrefix) {
badFields["principal_ids"] = "Must only have valid user, group, and/or managed group ids."
break
}
if id == "u_recovery" {
@@ -1018,8 +1023,10 @@ func validateRemoveRolePrincipalsRequest(req *pbs.RemoveRolePrincipalsRequest) e
badFields["principal_ids"] = "Must be non-empty."
}
for _, id := range req.GetPrincipalIds() {
if !handlers.ValidId(handlers.Id(id), iam.GroupPrefix) && !handlers.ValidId(handlers.Id(id), iam.UserPrefix) {
badFields["principal_ids"] = "Must only have valid group and/or user ids."
if !handlers.ValidId(handlers.Id(id), iam.GroupPrefix) &&
!handlers.ValidId(handlers.Id(id), iam.UserPrefix) &&
!handlers.ValidId(handlers.Id(id), intglobals.OidcManagedGroupPrefix) {
badFields["principal_ids"] = "Must only have valid user, group, and/or managed group ids."
break
}
}
@@ -9,15 +9,18 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/boundary/internal/auth"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/db"
pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/roles"
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/roles"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/kr/pretty"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -1010,10 +1013,23 @@ func TestAddPrincipal(t *testing.T) {
repoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
o, p := iam.TestScopes(t, iamRepo)
s, err := roles.NewService(repoFn)
require.NoError(t, err, "Error when getting new role service.")
o, p := iam.TestScopes(t, iamRepo)
ctx := context.Background()
kmsCache := kms.TestKms(t, conn, wrap)
databaseWrapper, err := kmsCache.GetWrapper(ctx, o.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, o.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
users := []*iam.User{
iam.TestUser(t, iamRepo, o.GetPublicId()),
iam.TestUser(t, iamRepo, o.GetPublicId()),
@@ -1024,15 +1040,22 @@ func TestAddPrincipal(t *testing.T) {
iam.TestGroup(t, conn, o.GetPublicId()),
iam.TestGroup(t, conn, o.GetPublicId()),
}
managedGroups := []*oidc.ManagedGroup{
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
}
addCases := []struct {
name string
setup func(*iam.Role)
addUsers []string
addGroups []string
resultUsers []string
resultGroups []string
wantErr bool
name string
setup func(*iam.Role)
addUsers []string
addGroups []string
addManagedGroups []string
resultUsers []string
resultGroups []string
resultManagedGroups []string
wantErr bool
}{
{
name: "Add user on empty role",
@@ -1078,6 +1101,28 @@ func TestAddPrincipal(t *testing.T) {
addGroups: []string{groups[1].GetPublicId(), groups[1].GetPublicId()},
resultGroups: []string{groups[0].GetPublicId(), groups[1].GetPublicId()},
},
{
name: "Add managed group on empty role",
setup: func(r *iam.Role) {},
addManagedGroups: []string{managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[1].GetPublicId()},
},
{
name: "Add managed group on populated role",
setup: func(r *iam.Role) {
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[0].GetPublicId())
},
addManagedGroups: []string{managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[0].GetPublicId(), managedGroups[1].GetPublicId()},
},
{
name: "Add duplicate managed group on populated role",
setup: func(r *iam.Role) {
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[0].GetPublicId())
},
addManagedGroups: []string{managedGroups[1].GetPublicId(), managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[0].GetPublicId(), managedGroups[1].GetPublicId()},
},
{
name: "Add invalid u_recovery on role",
setup: func(r *iam.Role) {},
@@ -1094,7 +1139,7 @@ func TestAddPrincipal(t *testing.T) {
req := &pbs.AddRolePrincipalsRequest{
Id: role.GetPublicId(),
Version: role.GetVersion(),
PrincipalIds: append(tc.addUsers, tc.addGroups...),
PrincipalIds: append(tc.addUsers, append(tc.addGroups, tc.addManagedGroups...)...),
}
got, err := s.AddRolePrincipals(auth.DisabledAuthTestContext(repoFn, o.GetPublicId()), req)
@@ -1103,10 +1148,10 @@ func TestAddPrincipal(t *testing.T) {
return
}
s, ok := status.FromError(err)
require.True(t, ok)
require.True(t, ok, fmt.Sprintf("Could not run FromError; input was %s", pretty.Sprint(err)))
require.NoError(t, err, "Got error: %v", s)
assert.True(t, equalPrincipals(got.GetItem(), append(tc.resultUsers, tc.resultGroups...)))
assert.True(t, equalPrincipals(got.GetItem(), append(tc.resultUsers, append(tc.resultGroups, tc.resultManagedGroups...)...)))
})
}
}
@@ -1168,6 +1213,20 @@ func TestSetPrincipal(t *testing.T) {
require.NoError(t, err, "Error when getting new role service.")
o, p := iam.TestScopes(t, iamRepo)
ctx := context.Background()
kmsCache := kms.TestKms(t, conn, wrap)
databaseWrapper, err := kmsCache.GetWrapper(ctx, o.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, o.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
users := []*iam.User{
iam.TestUser(t, iamRepo, o.GetPublicId()),
iam.TestUser(t, iamRepo, o.GetPublicId()),
@@ -1178,15 +1237,22 @@ func TestSetPrincipal(t *testing.T) {
iam.TestGroup(t, conn, o.GetPublicId()),
iam.TestGroup(t, conn, o.GetPublicId()),
}
managedGroups := []*oidc.ManagedGroup{
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
}
setCases := []struct {
name string
setup func(*iam.Role)
setUsers []string
setGroups []string
resultUsers []string
resultGroups []string
wantErr bool
name string
setup func(*iam.Role)
setUsers []string
setGroups []string
setManagedGroups []string
resultUsers []string
resultGroups []string
resultManagedGroups []string
wantErr bool
}{
{
name: "Set user on empty role",
@@ -1233,6 +1299,20 @@ func TestSetPrincipal(t *testing.T) {
setGroups: []string{groups[1].GetPublicId()},
resultGroups: []string{groups[1].GetPublicId()},
},
{
name: "Set managed group on empty role",
setup: func(r *iam.Role) {},
setManagedGroups: []string{managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[1].GetPublicId()},
},
{
name: "Set managed group on populated role",
setup: func(r *iam.Role) {
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[0].GetPublicId())
},
setManagedGroups: []string{managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[1].GetPublicId()},
},
{
name: "Set invalid u_recovery on role",
setup: func(r *iam.Role) {},
@@ -1249,7 +1329,7 @@ func TestSetPrincipal(t *testing.T) {
req := &pbs.SetRolePrincipalsRequest{
Id: role.GetPublicId(),
Version: role.GetVersion(),
PrincipalIds: append(tc.setUsers, tc.setGroups...),
PrincipalIds: append(tc.setUsers, append(tc.setGroups, tc.setManagedGroups...)...),
}
got, err := s.SetRolePrincipals(auth.DisabledAuthTestContext(repoFn, o.GetPublicId()), req)
@@ -1258,10 +1338,10 @@ func TestSetPrincipal(t *testing.T) {
return
}
s, ok := status.FromError(err)
require.True(t, ok)
require.True(t, ok, fmt.Sprintf("Could not run FromError; input was %s", pretty.Sprint(err)))
require.NoError(t, err, "Got error: %v", s)
assert.True(t, equalPrincipals(got.GetItem(), append(tc.resultUsers, tc.resultGroups...)))
assert.True(t, equalPrincipals(got.GetItem(), append(tc.resultUsers, append(tc.resultGroups, tc.resultManagedGroups...)...)))
})
}
}
@@ -1323,6 +1403,20 @@ func TestRemovePrincipal(t *testing.T) {
require.NoError(t, err, "Error when getting new role service.")
o, p := iam.TestScopes(t, iamRepo)
ctx := context.Background()
kmsCache := kms.TestKms(t, conn, wrap)
databaseWrapper, err := kmsCache.GetWrapper(ctx, o.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
authMethod := oidc.TestAuthMethod(
t, conn, databaseWrapper, o.GetPublicId(), oidc.ActivePrivateState,
"alice-rp", "fido",
oidc.WithSigningAlgs(oidc.RS256),
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
)
users := []*iam.User{
iam.TestUser(t, iamRepo, o.GetPublicId()),
iam.TestUser(t, iamRepo, o.GetPublicId()),
@@ -1333,15 +1427,22 @@ func TestRemovePrincipal(t *testing.T) {
iam.TestGroup(t, conn, o.GetPublicId()),
iam.TestGroup(t, conn, o.GetPublicId()),
}
managedGroups := []*oidc.ManagedGroup{
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
oidc.TestManagedGroup(t, conn, authMethod, oidc.TestFakeManagedGroupFilter),
}
addCases := []struct {
name string
setup func(*iam.Role)
removeUsers []string
removeGroups []string
resultUsers []string
resultGroups []string
wantErr bool
name string
setup func(*iam.Role)
removeUsers []string
removeGroups []string
removeManagedGroups []string
resultUsers []string
resultGroups []string
resultManagedGroups []string
wantErr bool
}{
{
name: "Remove user on empty role",
@@ -1416,6 +1517,39 @@ func TestRemovePrincipal(t *testing.T) {
removeGroups: []string{groups[0].GetPublicId(), groups[1].GetPublicId()},
resultGroups: []string{},
},
{
name: "Remove managed group on empty role",
setup: func(r *iam.Role) {},
removeGroups: []string{groups[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove 1 of 2 managed groups from role",
setup: func(r *iam.Role) {
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[0].GetPublicId())
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[1].GetPublicId())
},
removeManagedGroups: []string{managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[0].GetPublicId()},
},
{
name: "Remove 1 duplicate managed group of 2 managed groups from role",
setup: func(r *iam.Role) {
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[0].GetPublicId())
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[1].GetPublicId())
},
removeManagedGroups: []string{managedGroups[1].GetPublicId(), managedGroups[1].GetPublicId()},
resultManagedGroups: []string{managedGroups[0].GetPublicId()},
},
{
name: "Remove all managed groups from role",
setup: func(r *iam.Role) {
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[0].GetPublicId())
iam.TestManagedGroupRole(t, conn, r.GetPublicId(), managedGroups[1].GetPublicId())
},
removeManagedGroups: []string{managedGroups[0].GetPublicId(), managedGroups[1].GetPublicId()},
resultManagedGroups: []string{},
},
}
for _, tc := range addCases {
@@ -1426,7 +1560,7 @@ func TestRemovePrincipal(t *testing.T) {
req := &pbs.RemoveRolePrincipalsRequest{
Id: role.GetPublicId(),
Version: role.GetVersion(),
PrincipalIds: append(tc.removeUsers, tc.removeGroups...),
PrincipalIds: append(tc.removeUsers, append(tc.removeGroups, tc.removeManagedGroups...)...),
}
got, err := s.RemoveRolePrincipals(auth.DisabledAuthTestContext(repoFn, o.GetPublicId()), req)
@@ -1438,7 +1572,7 @@ func TestRemovePrincipal(t *testing.T) {
require.True(t, ok)
require.NoError(t, err, "Got error: %v", s)
assert.True(t, equalPrincipals(got.GetItem(), append(tc.resultUsers, tc.resultGroups...)))
assert.True(t, equalPrincipals(got.GetItem(), append(tc.resultUsers, append(tc.resultGroups, tc.resultManagedGroups...)...)))
})
}
}