Policies
It is not uncommon to restrict access to different routes based on who is making the request. For example, you many want to restrict access to a route based a request's origin, IP address, or if the request has the correct authorizations.
Blueprint realizes this need through its policy framework. In this part of the tutorial, we will explore how to create a simple policy, attach it to a route, and then write a unit test to test the policy.
Defining a policy
Let's say we want to restrict access to GET /api/rentals
to requests that only have the header Secret-Key
and the value of the header is set to ssshhh
.
This example is for demonstration purposes only. Please do not do anything this simple in a production environment when it comes to securing an API.
To do this, we are going to create a policy as shown below. As shown in the example, our policy is first placed in the /app/policies
directory. We then organize our policy under the /rental
directory since this policy pertains to the rental resource. Lastly, we place the policy in a file named getAll.js
. This help us remember the policy is for getting all rentals (more on this later).
Each policy must implement the runCheck(req)
method because this is the main entry point the framework uses to execute a policy. If the policy succeeds, it must return true
. If the policy fails, it can return either false
, or a failure object. The failure object is a hash that contains a failureCode
and failureMessage
property. As you see in the example above, the policy can also define a default failureCode
and failureMessage
at the top-level of the policy. The default failure code and failure message are used when the policy returns false
.
In the example above, we are checking the request header for the value of the Secret-Key
header. If the value is ssshhh
, the policy returns true
. If the value is not ssshhh
, then the policy returns false
.
Policies that return true are allowed to continue its routing process either to the next policy, or to the controller action for the route. Policies that return false stop the request handling, and return 403
to the client. The body of the response will contain the corresponding failureCode
and failureMessage
associated with the failed policy.
Attaching the policy to a route
Now that we have defined a policy, we need to attach (or bind) the policy to the correct route. We do this in the router specification.
Let's assume that we go back to the router we defined before we started using resources. This router is illustrated below. The router has a policy
property that is used to define the policy for a route or an action. As shown below, we have specified the policy created above on the /rentals
route defined below.
Policies for resources
The example above illustrated how to manually attach a policy to a route. This works when you manually bind routes to actions in a router specification. When we use resources, however, we have to use a different approach. Instead, the framework automatically attaches policies to resource routes. This is done by searching for a policy that matches resource name + action.
If you recall, we defined the policy for our example in a file named /app/policies/rental/getAll.js
. We did this in preparation for replacing the manually specification of a policy with the automatic specification of a policy when using a resource. If we revert our design above back to the resource approach, then we do not have to manually specify the policies. Instead, the Blueprint framework will search for policies that match this resource for each inferred action of a resource, such as getOne
, getAll
, and update
.
For the example above, the framework will search for the following optional policies in app/policies
:
Testing your policies
You unit test your policies the same way you unit test any route. The main difference is instead of expecting a 200
response, you are expecting a 403
response. You can also check the body of the response to make sure its returning the correct failure code and failure message. Below is an example of checking the policy we created above.
Last updated