feat: Check permissions endpoint (#1389)

* feat: Check permissions endpoint

Allows FE to query backend for permission capabilities.
Batch requests supported
This commit is contained in:
Steven Masley
2022-05-12 15:56:23 -05:00
committed by GitHub
parent 75a5877c1d
commit 64e408c954
8 changed files with 282 additions and 20 deletions

View File

@ -43,3 +43,16 @@ func (c *Client) ListOrganizationRoles(ctx context.Context, org uuid.UUID) ([]Ro
var roles []Role
return roles, json.NewDecoder(res.Body).Decode(&roles)
}
func (c *Client) CheckPermissions(ctx context.Context, checks UserPermissionCheckRequest) (UserPermissionCheckResponse, error) {
res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/users/%s/authorization", uuidOrMe(Me)), checks)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, readBodyAsError(res)
}
var roles UserPermissionCheckResponse
return roles, json.NewDecoder(res.Body).Decode(&roles)
}

View File

@ -76,6 +76,56 @@ type UserRoles struct {
OrganizationRoles map[uuid.UUID][]string `json:"organization_roles"`
}
type UserPermissionCheckResponse map[string]bool
// UserPermissionCheckRequest is a structure instead of a map because
// go-playground/validate can only validate structs. If you attempt to pass
// a map into 'httpapi.Read', you will get an invalid type error.
type UserPermissionCheckRequest struct {
// Checks is a map keyed with an arbitrary string to a permission check.
// The key can be any string that is helpful to the caller, and allows
// multiple permission checks to be run in a single request.
// The key ensures that each permission check has the same key in the
// response.
Checks map[string]UserPermissionCheck `json:"checks"`
}
// UserPermissionCheck is used to check if a user can do a given action
// to a given set of objects.
type UserPermissionCheck struct {
// Object can represent a "set" of objects, such as:
// - All workspaces in an organization
// - All workspaces owned by me
// - All workspaces across the entire product
// When defining an object, use the most specific language when possible to
// produce the smallest set. Meaning to set as many fields on 'Object' as
// you can. Example, if you want to check if you can update all workspaces
// owned by 'me', try to also add an 'OrganizationID' to the settings.
// Omitting the 'OrganizationID' could produce the incorrect value, as
// workspaces have both `user` and `organization` owners.
Object UserPermissionCheckObject `json:"object"`
// Action can be 'create', 'read', 'update', or 'delete'
Action string `json:"action"`
}
type UserPermissionCheckObject struct {
// ResourceType is the name of the resource.
// './coderd/rbac/object.go' has the list of valid resource types.
ResourceType string `json:"resource_type"`
// OwnerID (optional) is a user_id. It adds the set constraint to all resources owned
// by a given user.
OwnerID string `json:"owner_id,omitempty"`
// OrganizationID (optional) is an organization_id. It adds the set constraint to
// all resources owned by a given organization.
OrganizationID string `json:"organization_id,omitempty"`
// ResourceID (optional) reduces the set to a singular resource. This assigns
// a resource ID to the resource type, eg: a single workspace.
// The rbac library will not fetch the resource from the database, so if you
// are using this option, you should also set the 'OwnerID' and 'OrganizationID'
// if possible. Be as specific as possible using all the fields relevant.
ResourceID string `json:"resource_id,omitempty"`
}
// LoginWithPasswordRequest enables callers to authenticate with email and password.
type LoginWithPasswordRequest struct {
Email string `json:"email" validate:"required,email"`