Add managed group support to role principals (#1270)
This commit is contained in:
1 parent
ad93315b59
commit
9ecc384007
29 files changed
+1510
-381
No files matched your search
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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],
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
`),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
@@ -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())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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...)...)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user