mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
feat!: drop reading other 'user' permission (#8650)
* feat: drop reading other 'user' permission Members of the platform can no longer read or list other users. Resources that have "created_by" or "initiated_by" still retain user context, but only include username and avatar url. Attempting to read a user found via those means will result in a 404. * Hide /users page for regular users * make groups a privledged endpoint * Permissions page for template perms * Admin for a given template enables an endpoint for listing users/groups.
This commit is contained in:
@ -195,6 +195,11 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// ResourceUserObject is a helper function to create a user object for authz checks.
|
||||
func ResourceUserObject(userID uuid.UUID) Object {
|
||||
return ResourceUser.WithID(userID).WithOwner(userID.String())
|
||||
}
|
||||
|
||||
// Object is used to create objects for authz checks when you have none in
|
||||
// hand to run the check on.
|
||||
// An example is if you want to list all workspaces, you can create a Object
|
||||
|
@ -259,7 +259,7 @@ neq(input.object.owner, "");
|
||||
},
|
||||
VariableConverter: regosql.UserConverter(),
|
||||
ExpectedSQL: p(
|
||||
p("'10d03e62-7703-4df5-a358-4f76577d4e2f' = ''") + " AND " + p("'' != ''") + " AND " + p("'' = ''"),
|
||||
p("'10d03e62-7703-4df5-a358-4f76577d4e2f' = id :: text") + " AND " + p("id :: text != ''") + " AND " + p("'' = ''"),
|
||||
),
|
||||
},
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ func UserConverter() *sqltypes.VariableConverter {
|
||||
// Users are never owned by an organization, so always return the empty string
|
||||
// for the org owner.
|
||||
sqltypes.StringVarMatcher("''", []string{"input", "object", "org_owner"}),
|
||||
// Users never have an owner, and are only owned site wide.
|
||||
sqltypes.StringVarMatcher("''", []string{"input", "object", "owner"}),
|
||||
// Users are always owned by themselves.
|
||||
sqltypes.StringVarMatcher("id :: text", []string{"input", "object", "owner"}),
|
||||
)
|
||||
matcher.RegisterMatcher(
|
||||
// No ACLs on the user type
|
||||
|
@ -145,14 +145,18 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
Name: member,
|
||||
DisplayName: "",
|
||||
Site: Permissions(map[string][]Action{
|
||||
// All users can read all other users and know they exist.
|
||||
ResourceUser.Type: {ActionRead},
|
||||
ResourceRoleAssignment.Type: {ActionRead},
|
||||
// All users can see the provisioner daemons.
|
||||
ResourceProvisionerDaemon.Type: {ActionRead},
|
||||
}),
|
||||
Org: map[string][]Permission{},
|
||||
User: allPermsExcept(ResourceWorkspaceLocked),
|
||||
Org: map[string][]Permission{},
|
||||
User: append(allPermsExcept(ResourceWorkspaceLocked, ResourceUser, ResourceOrganizationMember),
|
||||
Permissions(map[string][]Action{
|
||||
// Users cannot do create/update/delete on themselves, but they
|
||||
// can read their own details.
|
||||
ResourceUser.Type: {ActionRead},
|
||||
})...,
|
||||
),
|
||||
}.withCachedRegoValue()
|
||||
|
||||
auditorRole := Role{
|
||||
@ -163,6 +167,10 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
// are not in.
|
||||
ResourceTemplate.Type: {ActionRead},
|
||||
ResourceAuditLog.Type: {ActionRead},
|
||||
ResourceUser.Type: {ActionRead},
|
||||
ResourceGroup.Type: {ActionRead},
|
||||
// Org roles are not really used yet, so grant the perm at the site level.
|
||||
ResourceOrganizationMember.Type: {ActionRead},
|
||||
}),
|
||||
Org: map[string][]Permission{},
|
||||
User: []Permission{},
|
||||
@ -180,6 +188,10 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
ResourceProvisionerDaemon.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
|
||||
// Needs to read all organizations since
|
||||
ResourceOrganization.Type: {ActionRead},
|
||||
ResourceUser.Type: {ActionRead},
|
||||
ResourceGroup.Type: {ActionRead},
|
||||
// Org roles are not really used yet, so grant the perm at the site level.
|
||||
ResourceOrganizationMember.Type: {ActionRead},
|
||||
}),
|
||||
Org: map[string][]Permission{},
|
||||
User: []Permission{},
|
||||
@ -249,11 +261,6 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
Site: []Permission{},
|
||||
Org: map[string][]Permission{
|
||||
organizationID: {
|
||||
{
|
||||
// All org members can read the other members in their org.
|
||||
ResourceType: ResourceOrganizationMember.Type,
|
||||
Action: ActionRead,
|
||||
},
|
||||
{
|
||||
// All org members can read the organization
|
||||
ResourceType: ResourceOrganization.Type,
|
||||
@ -264,13 +271,14 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
ResourceType: ResourceOrgRoleAssignment.Type,
|
||||
Action: ActionRead,
|
||||
},
|
||||
{
|
||||
ResourceType: ResourceGroup.Type,
|
||||
Action: ActionRead,
|
||||
},
|
||||
},
|
||||
},
|
||||
User: []Permission{},
|
||||
User: []Permission{
|
||||
{
|
||||
ResourceType: ResourceOrganizationMember.Type,
|
||||
Action: ActionRead,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -106,10 +106,10 @@ func TestRolePermissions(t *testing.T) {
|
||||
{
|
||||
Name: "MyUser",
|
||||
Actions: []rbac.Action{rbac.ActionRead},
|
||||
Resource: rbac.ResourceUser.WithID(currentUser),
|
||||
Resource: rbac.ResourceUserObject(currentUser),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, memberMe, orgMemberMe, orgAdmin, otherOrgMember, otherOrgAdmin, templateAdmin, userAdmin},
|
||||
false: {},
|
||||
true: {orgMemberMe, owner, memberMe, templateAdmin, userAdmin},
|
||||
false: {otherOrgMember, otherOrgAdmin, orgAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -281,7 +281,7 @@ func TestRolePermissions(t *testing.T) {
|
||||
{
|
||||
Name: "ManageOrgMember",
|
||||
Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete},
|
||||
Resource: rbac.ResourceOrganizationMember.WithID(currentUser).InOrg(orgID),
|
||||
Resource: rbac.ResourceOrganizationMember.WithID(currentUser).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin},
|
||||
false: {orgMemberMe, memberMe, otherOrgAdmin, otherOrgMember, templateAdmin},
|
||||
@ -290,10 +290,10 @@ func TestRolePermissions(t *testing.T) {
|
||||
{
|
||||
Name: "ReadOrgMember",
|
||||
Actions: []rbac.Action{rbac.ActionRead},
|
||||
Resource: rbac.ResourceOrganizationMember.WithID(currentUser).InOrg(orgID),
|
||||
Resource: rbac.ResourceOrganizationMember.WithID(currentUser).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, orgMemberMe, userAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, templateAdmin},
|
||||
true: {owner, orgAdmin, userAdmin, orgMemberMe, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -314,8 +314,8 @@ func TestRolePermissions(t *testing.T) {
|
||||
Actions: []rbac.Action{rbac.ActionRead},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin, orgMemberMe},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, templateAdmin},
|
||||
true: {owner, orgAdmin, userAdmin, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, orgMemberMe, otherOrgMember},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
Reference in New Issue
Block a user