In this tutorial we’re going to look at how the Layer 7 Gateway can be used to secure and constrain an OData API. For some analysis of the vulnerabilities of OData and the importance of securing APIs based on this technology, this blog entry by our CTO Scott Morrison is a good primer. (http://www.layer7tech.com/feed/securing-odata).
Scott’s blog uses the experimental Netflix OData API as an example. The premise of this example is to constrain the view of the API based on a particular class of user. In this case we’re restricting the list of available ‘Titles’ retrievable from Netflix for ‘minors’. While this is a rather simple example, it’s sufficient to get the point across so we’ll use it in this tutorial as well.
The first order of business is to publish a service on the Layer 7 gateway to act as a proxy endpoint for the OData API. In this case we’ll publish an XML Application service that has as its entry point any resource URI that starts with ‘/Catalog
We then construct the policy for this published service. Below is a simplified view of the policy with some folders collapsed to show the basic structure of the policy.
The first action this policy takes is to audit the resource URI and the URL query string for the inbound request (lines 2-3). Lines 4-5 assert that the inbound request must have arrived over SSL and include HTTP basic authentication credentials. We could just have easily required Windows Integrated Authentication, HTTP Digest credentials or even an OR condition that accepted one of the three credential types.
Line 6 is where the policy is branched based on the user making the request. We require that the credentials in the inbound request are a member of the ‘adults’ group or the ‘minors’ group. If they are a member of the ‘adults’ group, we simply forward the request as is to the Netflix API endpoint (lines 9-10).
However, if the credentials are a member of the ‘minors’ group we have some additional work to do to constrain the request to only return Netflix titles rated ‘G’ or ‘PG-13’. Below is a full view of the policy.
We constrain the request by modifying the request’s query string, but before we do this we must check to ensure that the request is indeed asking for ‘Titles’ in the first place. (The Netflix API can return other entities such as People and Genres, that don’t require a filter.) We do this by checking for the ‘Titles’ keyword in the request URI and adding a custom audit that we are filtering the request if this keyword exists (lines 17 & 18). If this keyword does not exist we set our additional ‘filterQueryString’ value to be empty (line 29).
Once we have established that the request does indeed need to be modified to constrain the set of returned data, we must test the policy once more to determine whether we need to add the ‘$filter’ parameter or append to an existing one. The Comparison assertion on line 22 tests for the keyword ‘?$filter’. If this test succeeds we must append an additional condition to existing filter using an or condition (line 23). If no ‘$filter’ condition exists we create one with our ‘Rating’ restriction (line 26). Note that this ‘Rating’ condition is URL encoded.
Our ‘Rating’ condition is written to the ‘filterQueryString’ context variable which is used on line 30 when routing the request to the Netflix API. Note that this context variable contains only the additional, URL encoded string to be appended to the existing resource URI + URL query string. Line 31 simply audits the routing URL for debugging purposes.
This is all that is required. We’ve successfully and securely exposed a constrained view of the Netflix API for a particular subset of users!