mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
* chore: Allow RecordingAuthorizer to record multiple rbac authz calls Prior iteration only recorded the last call. This is required for more comprehensive testing
305 lines
7.3 KiB
Go
305 lines
7.3 KiB
Go
package rbac
|
|
|
|
import (
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const WildcardSymbol = "*"
|
|
|
|
// Objecter returns the RBAC object for itself.
|
|
type Objecter interface {
|
|
RBACObject() Object
|
|
}
|
|
|
|
// Resources are just typed objects. Making resources this way allows directly
|
|
// passing them into an Authorize function and use the chaining api.
|
|
var (
|
|
// ResourceWorkspace CRUD. Org + User owner
|
|
// create/delete = make or delete workspaces
|
|
// read = access workspace
|
|
// update = edit workspace variables
|
|
ResourceWorkspace = Object{
|
|
Type: "workspace",
|
|
}
|
|
|
|
// ResourceWorkspaceExecution CRUD. Org + User owner
|
|
// create = workspace remote execution
|
|
// read = ?
|
|
// update = ?
|
|
// delete = ?
|
|
ResourceWorkspaceExecution = Object{
|
|
Type: "workspace_execution",
|
|
}
|
|
|
|
// ResourceWorkspaceApplicationConnect CRUD. Org + User owner
|
|
// create = connect to an application
|
|
// read = ?
|
|
// update = ?
|
|
// delete = ?
|
|
ResourceWorkspaceApplicationConnect = Object{
|
|
Type: "application_connect",
|
|
}
|
|
|
|
// ResourceAuditLog
|
|
// read = access audit log
|
|
ResourceAuditLog = Object{
|
|
Type: "audit_log",
|
|
}
|
|
|
|
// ResourceTemplate CRUD. Org owner only.
|
|
// create/delete = Make or delete a new template
|
|
// update = Update the template, make new template versions
|
|
// read = read the template and all versions associated
|
|
ResourceTemplate = Object{
|
|
Type: "template",
|
|
}
|
|
|
|
// ResourceGroup CRUD. Org admins only.
|
|
// create/delete = Make or delete a new group.
|
|
// update = Update the name or members of a group.
|
|
// read = Read groups and their members.
|
|
ResourceGroup = Object{
|
|
Type: "group",
|
|
}
|
|
|
|
ResourceFile = Object{
|
|
Type: "file",
|
|
}
|
|
|
|
ResourceProvisionerDaemon = Object{
|
|
Type: "provisioner_daemon",
|
|
}
|
|
|
|
// ResourceOrganization CRUD. Has an org owner on all but 'create'.
|
|
// create/delete = make or delete organizations
|
|
// read = view org information (Can add user owner for read)
|
|
// update = ??
|
|
ResourceOrganization = Object{
|
|
Type: "organization",
|
|
}
|
|
|
|
// ResourceRoleAssignment might be expanded later to allow more granular permissions
|
|
// to modifying roles. For now, this covers all possible roles, so having this permission
|
|
// allows granting/deleting **ALL** roles.
|
|
// Never has an owner or org.
|
|
// create = Assign roles
|
|
// update = ??
|
|
// read = View available roles to assign
|
|
// delete = Remove role
|
|
ResourceRoleAssignment = Object{
|
|
Type: "assign_role",
|
|
}
|
|
|
|
// ResourceOrgRoleAssignment is just like ResourceRoleAssignment but for organization roles.
|
|
ResourceOrgRoleAssignment = Object{
|
|
Type: "assign_org_role",
|
|
}
|
|
|
|
// ResourceAPIKey is owned by a user.
|
|
// create = Create a new api key for user
|
|
// update = ??
|
|
// read = View api key
|
|
// delete = Delete api key
|
|
ResourceAPIKey = Object{
|
|
Type: "api_key",
|
|
}
|
|
|
|
// ResourceUser is the user in the 'users' table.
|
|
// ResourceUser never has any owners or in an org, as it's site wide.
|
|
// create/delete = make or delete a new user.
|
|
// read = view all 'user' table data
|
|
// update = update all 'user' table data
|
|
ResourceUser = Object{
|
|
Type: "user",
|
|
}
|
|
|
|
// ResourceUserData is any data associated with a user. A user has control
|
|
// over their data (profile, password, etc). So this resource has an owner.
|
|
ResourceUserData = Object{
|
|
Type: "user_data",
|
|
}
|
|
|
|
// ResourceOrganizationMember is a user's membership in an organization.
|
|
// Has ONLY an organization owner.
|
|
// create/delete = Create/delete member from org.
|
|
// update = Update organization member
|
|
// read = View member
|
|
ResourceOrganizationMember = Object{
|
|
Type: "organization_member",
|
|
}
|
|
|
|
// ResourceWildcard represents all resource types
|
|
ResourceWildcard = Object{
|
|
Type: WildcardSymbol,
|
|
}
|
|
|
|
// ResourceLicense is the license in the 'licenses' table.
|
|
// ResourceLicense is site wide.
|
|
// create/delete = add or remove license from site.
|
|
// read = view license claims
|
|
// update = not applicable; licenses are immutable
|
|
ResourceLicense = Object{
|
|
Type: "license",
|
|
}
|
|
|
|
// ResourceDeploymentConfig
|
|
ResourceDeploymentConfig = Object{
|
|
Type: "deployment_config",
|
|
}
|
|
|
|
ResourceReplicas = Object{
|
|
Type: "replicas",
|
|
}
|
|
|
|
// ResourceDebugInfo controls access to the debug routes `/api/v2/debug/*`.
|
|
ResourceDebugInfo = Object{
|
|
Type: "debug_info",
|
|
}
|
|
)
|
|
|
|
// 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
|
|
// that represents the set of workspaces you are trying to get access too.
|
|
// Do not export this type, as it can be created from a resource type constant.
|
|
type Object struct {
|
|
// ID is the resource's uuid
|
|
ID string `json:"id"`
|
|
Owner string `json:"owner"`
|
|
// OrgID specifies which org the object is a part of.
|
|
OrgID string `json:"org_owner"`
|
|
|
|
// Type is "workspace", "project", "app", etc
|
|
Type string `json:"type"`
|
|
|
|
ACLUserList map[string][]Action ` json:"acl_user_list"`
|
|
ACLGroupList map[string][]Action ` json:"acl_group_list"`
|
|
}
|
|
|
|
func (z Object) Equal(b Object) bool {
|
|
if z.ID != b.ID {
|
|
return false
|
|
}
|
|
if z.Owner != b.Owner {
|
|
return false
|
|
}
|
|
if z.OrgID != b.OrgID {
|
|
return false
|
|
}
|
|
if z.Type != b.Type {
|
|
return false
|
|
}
|
|
|
|
if !equalACLLists(z.ACLUserList, b.ACLUserList) {
|
|
return false
|
|
}
|
|
|
|
if !equalACLLists(z.ACLGroupList, b.ACLGroupList) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func equalACLLists(a, b map[string][]Action) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
|
|
for k, actions := range a {
|
|
if len(actions) != len(b[k]) {
|
|
return false
|
|
}
|
|
for i, a := range actions {
|
|
if a != b[k][i] {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (z Object) RBACObject() Object {
|
|
return z
|
|
}
|
|
|
|
// All returns an object matching all resources of the same type.
|
|
func (z Object) All() Object {
|
|
return Object{
|
|
Owner: "",
|
|
OrgID: "",
|
|
Type: z.Type,
|
|
ACLUserList: map[string][]Action{},
|
|
ACLGroupList: map[string][]Action{},
|
|
}
|
|
}
|
|
|
|
func (z Object) WithIDString(id string) Object {
|
|
return Object{
|
|
ID: id,
|
|
Owner: z.Owner,
|
|
OrgID: z.OrgID,
|
|
Type: z.Type,
|
|
ACLUserList: z.ACLUserList,
|
|
ACLGroupList: z.ACLGroupList,
|
|
}
|
|
}
|
|
|
|
func (z Object) WithID(id uuid.UUID) Object {
|
|
return Object{
|
|
ID: id.String(),
|
|
Owner: z.Owner,
|
|
OrgID: z.OrgID,
|
|
Type: z.Type,
|
|
ACLUserList: z.ACLUserList,
|
|
ACLGroupList: z.ACLGroupList,
|
|
}
|
|
}
|
|
|
|
// InOrg adds an org OwnerID to the resource
|
|
func (z Object) InOrg(orgID uuid.UUID) Object {
|
|
return Object{
|
|
ID: z.ID,
|
|
Owner: z.Owner,
|
|
OrgID: orgID.String(),
|
|
Type: z.Type,
|
|
ACLUserList: z.ACLUserList,
|
|
ACLGroupList: z.ACLGroupList,
|
|
}
|
|
}
|
|
|
|
// WithOwner adds an OwnerID to the resource
|
|
func (z Object) WithOwner(ownerID string) Object {
|
|
return Object{
|
|
ID: z.ID,
|
|
Owner: ownerID,
|
|
OrgID: z.OrgID,
|
|
Type: z.Type,
|
|
ACLUserList: z.ACLUserList,
|
|
ACLGroupList: z.ACLGroupList,
|
|
}
|
|
}
|
|
|
|
// WithACLUserList adds an ACL list to a given object
|
|
func (z Object) WithACLUserList(acl map[string][]Action) Object {
|
|
return Object{
|
|
ID: z.ID,
|
|
Owner: z.Owner,
|
|
OrgID: z.OrgID,
|
|
Type: z.Type,
|
|
ACLUserList: acl,
|
|
ACLGroupList: z.ACLGroupList,
|
|
}
|
|
}
|
|
|
|
func (z Object) WithGroupACL(groups map[string][]Action) Object {
|
|
return Object{
|
|
ID: z.ID,
|
|
Owner: z.Owner,
|
|
OrgID: z.OrgID,
|
|
Type: z.Type,
|
|
ACLUserList: z.ACLUserList,
|
|
ACLGroupList: groups,
|
|
}
|
|
}
|