Chef Server API requests are eventually routed to a module in the oc_chef_wm application. These modules implement the 'chef_wm' behavior. A behavior defines a set of callback functions that are used to process each request.
For authorization, the relevant callback function is auth_info/2. auth_info/2 takes 2 arguments: The Request (which holds all the information about the HTTP request, such as method, path, etc) and the resource state, which holds things like the authz_id of the actor making the request.
The response from auth_info determines which permissions are checked before allowing the given request to proceed. The following are the possible return values:
-
{{halt, 403}, Req, State}
: typically returned when the module needs to implement its own permissions check that isn't covered by the cases below and that custom check has failed. In this case, no additional check is performed and thea 403 is returned to the user. -
{{halt, 403, Message}, Req, State}
: same as above but with a custom message -
{{halt, Code}, Req1, State1}
: Similar to the above, but for when we want to fail with a different error code. This is commonly used to return 404 when a named object cannot be found. In this case, no permission check can be done. -
{{create_in_container, Container}, Req, State}
: Check if the user has CREATE and the specified container. This is typically what is used for POSTs to create new objects -
{{container, Container}, Req, State}
: Check whether you have the required permission on the container specified by name. The permission check is inferred from the HTTP method (see below). -
{{container_id, Container}, Req, State}}
: Check whether you have the required permission on the container specified by authz_id. The permission check is inferred from the HTTP method (see below). -
{{group, AuthzId}, Req, State}
-
{{group_id, AuthzId}, Req, State}
: Check whether you have the required permission (again based on HTTP method) for the group specified by AuthzId. Why do we have both of these? -
{{actor, ObjectID}, Req, State}
-
{{object, ObjectID}, Req, State}
-> Check whether you have the required permission (based on HTTP method) for the actor or object identified by their object id. -
{{object, ObjectID, Perm}, Req State}
-
{{actor, ObjectID, Perm}, Req State}
: Check whether you have the specified permission (Perm) for the actor or object identified by ObjectID. -
{superuser_only, Req, State}
: Only allows the request if you are the superuser (pivotal). -
{authorized, Req, State}
: Allow the request with no authz lookup. Used for endpoints that don't require authorization or when the module has implemented its own check and needs to indicate that access is granted.
It is possible to specify multiple checks by providing an array as the first argument in your response. Members of the array must be one of:
{create_in_container, Container}
{container, Container, Perm}
{object, ObjectId, Perm}
{actor, ObjectId, Perm}
In most cases, controllers don't specify the permission they need. They allow it to be inferred from the HTTP request method:
- DELETE -> delete
- GET -> read
- POST -> create
- PUT -> update
The auth_info/2
function is called by the forbidden/2
webmachine callback in oc_chef_wm_base. That is where the rules explained above are codified. In most cases, these eventually boil down to a call being made to oc_chef_authz:is_authorized_on_resource
which is the library that makes API requests to bifrost.