mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: allow group members to read group information (#14200)
* - allow group members to read basic Group info - allow group members to see they are part of the group, but not see that information about other members - add a GetGroupMembersCountByGroupID SQL query, which allows group members to see members count without revealing other information about the members - add the group_members_expanded db view - rewrite group member queries to use the group_members_expanded view - add the RBAC ResourceGroupMember and add it to relevant roles - rewrite GetGroupMembersByGroupID permission checks - make the GroupMember type contain all user fields - fix type issues coming from replacing User with GroupMember in group member queries - add the MemberTotalCount field to codersdk.Group - display `group.total_member_count` instead of `group.members.length` on the account page
This commit is contained in:
@@ -93,6 +93,13 @@ var (
|
||||
Type: "group",
|
||||
}
|
||||
|
||||
// ResourceGroupMember
|
||||
// Valid Actions
|
||||
// - "ActionRead" :: read group members
|
||||
ResourceGroupMember = Object{
|
||||
Type: "group_member",
|
||||
}
|
||||
|
||||
// ResourceLicense
|
||||
// Valid Actions
|
||||
// - "ActionCreate" :: create a license
|
||||
@@ -287,6 +294,7 @@ func AllResources() []Objecter {
|
||||
ResourceDeploymentStats,
|
||||
ResourceFile,
|
||||
ResourceGroup,
|
||||
ResourceGroupMember,
|
||||
ResourceLicense,
|
||||
ResourceNotificationPreference,
|
||||
ResourceNotificationTemplate,
|
||||
|
||||
@@ -149,6 +149,11 @@ var RBACPermissions = map[string]PermissionDefinition{
|
||||
ActionUpdate: actDef("update a group"),
|
||||
},
|
||||
},
|
||||
"group_member": {
|
||||
Actions: map[Action]ActionDefinition{
|
||||
ActionRead: actDef("read group members"),
|
||||
},
|
||||
},
|
||||
"file": {
|
||||
Actions: map[Action]ActionDefinition{
|
||||
ActionCreate: actDef("create a file"),
|
||||
|
||||
@@ -301,10 +301,11 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
Site: Permissions(map[string][]policy.Action{
|
||||
// Should be able to read all template details, even in orgs they
|
||||
// are not in.
|
||||
ResourceTemplate.Type: {policy.ActionRead, policy.ActionViewInsights},
|
||||
ResourceAuditLog.Type: {policy.ActionRead},
|
||||
ResourceUser.Type: {policy.ActionRead},
|
||||
ResourceGroup.Type: {policy.ActionRead},
|
||||
ResourceTemplate.Type: {policy.ActionRead, policy.ActionViewInsights},
|
||||
ResourceAuditLog.Type: {policy.ActionRead},
|
||||
ResourceUser.Type: {policy.ActionRead},
|
||||
ResourceGroup.Type: {policy.ActionRead},
|
||||
ResourceGroupMember.Type: {policy.ActionRead},
|
||||
// Allow auditors to query deployment stats and insights.
|
||||
ResourceDeploymentStats.Type: {policy.ActionRead},
|
||||
ResourceDeploymentConfig.Type: {policy.ActionRead},
|
||||
@@ -329,6 +330,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
ResourceOrganization.Type: {policy.ActionRead},
|
||||
ResourceUser.Type: {policy.ActionRead},
|
||||
ResourceGroup.Type: {policy.ActionRead},
|
||||
ResourceGroupMember.Type: {policy.ActionRead},
|
||||
// Org roles are not really used yet, so grant the perm at the site level.
|
||||
ResourceOrganizationMember.Type: {policy.ActionRead},
|
||||
}),
|
||||
@@ -351,6 +353,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
// Full perms to manage org members
|
||||
ResourceOrganizationMember.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||
ResourceGroup.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||
ResourceGroupMember.Type: {policy.ActionRead},
|
||||
}),
|
||||
Org: map[string][]Permission{},
|
||||
User: []Permission{},
|
||||
@@ -461,6 +464,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
ResourceAssignOrgRole.Type: {policy.ActionAssign, policy.ActionDelete, policy.ActionRead},
|
||||
ResourceOrganizationMember.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||
ResourceGroup.Type: ResourceGroup.AvailableActions(),
|
||||
ResourceGroupMember.Type: ResourceGroupMember.AvailableActions(),
|
||||
}),
|
||||
},
|
||||
User: []Permission{},
|
||||
@@ -480,6 +484,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
// Assigning template perms requires this permission.
|
||||
ResourceOrganizationMember.Type: {policy.ActionRead},
|
||||
ResourceGroup.Type: {policy.ActionRead},
|
||||
ResourceGroupMember.Type: {policy.ActionRead},
|
||||
}),
|
||||
},
|
||||
User: []Permission{},
|
||||
|
||||
@@ -112,6 +112,7 @@ func TestRolePermissions(t *testing.T) {
|
||||
// Subjects to user
|
||||
memberMe := authSubject{Name: "member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember()}}}
|
||||
orgMemberMe := authSubject{Name: "org_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID)}}}
|
||||
groupMemberMe := authSubject{Name: "group_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID)}, Groups: []string{groupID.String()}}}
|
||||
|
||||
owner := authSubject{Name: "owner", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleOwner()}}}
|
||||
templateAdmin := authSubject{Name: "template-admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleTemplateAdmin()}}}
|
||||
@@ -382,21 +383,47 @@ func TestRolePermissions(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Groups",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionDelete, policy.ActionUpdate},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID),
|
||||
Name: "Groups",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionDelete, policy.ActionUpdate},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID).WithGroupACL(map[string][]policy.Action{
|
||||
groupID.String(): {
|
||||
policy.ActionRead,
|
||||
},
|
||||
}),
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, orgUserAdmin},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, templateAdmin, orgTemplateAdmin, orgAuditor},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, templateAdmin, orgTemplateAdmin, orgAuditor, groupMemberMe},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GroupsRead",
|
||||
Name: "GroupsRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID).WithGroupACL(map[string][]policy.Action{
|
||||
groupID.String(): {
|
||||
policy.ActionRead,
|
||||
},
|
||||
}),
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, groupMemberMe},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GroupMemberMeRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID),
|
||||
Resource: rbac.ResourceGroupMember.WithID(currentUser).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgMemberMe, groupMemberMe},
|
||||
false: {setOtherOrg, memberMe, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GroupMemberOtherRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceGroupMember.WithID(adminID).InOrg(orgID).WithOwner(adminID.String()),
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, orgAuditor},
|
||||
false: {setOtherOrg, memberMe, orgAuditor, orgMemberMe, groupMemberMe},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user