diff --git a/lib/services/presets.go b/lib/services/presets.go index 068bccba13e04..1d6a4bfc5c6c1 100644 --- a/lib/services/presets.go +++ b/lib/services/presets.go @@ -182,6 +182,7 @@ func NewPresetEditorRole() types.Role { types.NewRule(types.KindNotification, RW()), types.NewRule(types.KindStaticHostUser, RW()), types.NewRule(types.KindUserTask, RW()), + types.NewRule(types.KindIdentityCenterAccount, RW()), }, }, }, diff --git a/lib/services/role.go b/lib/services/role.go index 083b277c9b81f..97eb20c03fdb3 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -78,6 +78,8 @@ var DefaultImplicitRules = []types.Rule{ types.NewRule(types.KindUsageEvent, []string{types.VerbCreate}), types.NewRule(types.KindVnetConfig, RO()), types.NewRule(types.KindSPIFFEFederation, RO()), + types.NewRule(types.KindSAMLIdPServiceProvider, RO()), + types.NewRule(types.KindIdentityCenterAccount, RO()), } // DefaultCertAuthorityRules provides access the minimal set of resources diff --git a/lib/services/role_test.go b/lib/services/role_test.go index 9beb05cfe0d2b..ae4b1c9167817 100644 --- a/lib/services/role_test.go +++ b/lib/services/role_test.go @@ -2441,6 +2441,78 @@ func TestCheckRuleAccess(t *testing.T) { } } +func TestDefaultImplicitRules(t *testing.T) { + type check struct { + hasAccess bool + verb string + namespace string + rule string + context testContext + } + testCases := []struct { + name string + role types.Role + checks []check + }{ + { + name: "KindIdentityCenterAccount with NewPresetAccessRole", + role: NewPresetAccessRole(), + checks: []check{ + {rule: types.KindIdentityCenterAccount, verb: types.VerbRead, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbList, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbCreate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbUpdate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbDelete, namespace: apidefaults.Namespace, hasAccess: false}, + }, + }, + { + name: "KindIdentityCenterAccount with a custom role that does not explicitly target read and list verbs for KindIdentityCenterAccount", + role: newRole(func(r *types.RoleV6) {}), + checks: []check{ + {rule: types.KindIdentityCenterAccount, verb: types.VerbRead, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbList, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbCreate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbUpdate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindIdentityCenterAccount, verb: types.VerbDelete, namespace: apidefaults.Namespace, hasAccess: false}, + }, + }, + { + name: "KindSAMLIdPServiceProvider with NewPresetAccessRole", + role: NewPresetAccessRole(), + checks: []check{ + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbRead, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbList, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbCreate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbUpdate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbDelete, namespace: apidefaults.Namespace, hasAccess: false}, + }, + }, + { + name: "KindSAMLIdPServiceProvider with a custom role that does not explicitly target read and list verbs for KindSAMLIdPServiceProvider", + role: newRole(func(r *types.RoleV6) {}), + checks: []check{ + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbRead, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbList, namespace: apidefaults.Namespace, hasAccess: true}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbCreate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbUpdate, namespace: apidefaults.Namespace, hasAccess: false}, + {rule: types.KindSAMLIdPServiceProvider, verb: types.VerbDelete, namespace: apidefaults.Namespace, hasAccess: false}, + }, + }, + } + for _, tc := range testCases { + roleSet := NewRoleSet(tc.role) + for _, check := range tc.checks { + result := roleSet.CheckAccessToRule(&check.context, check.namespace, check.rule, check.verb) + if check.hasAccess { + require.NoError(t, result) + } else { + require.True(t, trace.IsAccessDenied(result)) + } + + } + } +} + func TestMFAVerificationInterval(t *testing.T) { testCases := []struct { name string