Introduction
This tutorial takes you through the steps to introduce fine-grained authorization, into an API, using Enforcer. Although not essential, you might find it beneficial to do the ALFA Tutorial before this one to give you some context of the features of Attribute Based Access Control and the OASIS model. This tutorial assumes you are familiar with building API projects.
Learning objectives:
- Know how to add Enforcer to an API application
- Learn how to use the Embedded Policy Store
- Add authorization to an API controller
- Use Identity claims in authorization rules
- Extend the Policy Information Point (PIP) to provide additional information to the PDP
- Use a custom handler for authorization failures
Scenario
AcmeCorp has an API for delivering stock quotes to customers. Customers can access live quotes which are accurate at the point of request and delayed quotes which lag by two hours. The delayed quotes are fine if doing trend analysis but you would not want to base investment decisions on data this out of date.
Customers take out a subscription to the stock quote service at one of three levels
Level | Access | Limits |
---|---|---|
pro | Access both live and delayed quotes | None |
standard | Access delayed quotes but not live | None |
free | Access delayed quotes but not live | Limited number of requests per day. Set by product owners and currently set to 50 |
Once a customer takes out a subscription, they are issued with am API key that they must include in the request. The API key is mapped to a subscription level. If the API key is ommitted from the request the caller receives an HTTP Status code of 401 - Unauthorized.
The goal of this tutorial is to enforce the subscription level rules when accessing the API.
During this tutorial, you will be creating and modifying ALFA policies. We recommend installing an ALFA plugin for your .NET IDE; this will colorize and highlight syntax errors in the ALFA.
Finally, if you don't have a license key for Enforcer, obtain a demo one by visiting https://identityserver.com/products/enforcer
The starter solution
To get the starter solution, clone the following GIT repository to your machine
https://github.com/RockSolidKnowledge/Samples.Enforcer
Go to the WebApiTutorial/Before
folder and open the WebApiTutorial.sln
in your development environment
The code you will be working from has a number of features already implemented. The API is fully functional but unprotected. API keys are required and are being mapped into claims. To ensure there is no smoke and mirrors, lets look at the code to see how its working.
The quote controller
The QuoteController
implements the two endpoints for the API: GetLive
and GetDelayed
. The actual logic of the operations is provided by an implementation of IQuoteService
that is injected into the controller in the constructor. The relative URLs for the two operations are:
/quote/{stock symbol}
for delayed quotes
/quote/{stock symbol}/live
for live quotes
Both operations are served using GET
on the relevant URL.
API key authentication
The requester must add an API key in the request query string. The code that deals with mapping this key to a claim is based on the AspNetCore.Authentication.ApiKey
Nuget package. This package has two core abstractions:
IApiKey
represents an identity with their claims
IApiKeyProvider
that maps an API key to an instance of an IApiKey
object
In the starter project these abstractions are implemented by the ApiKey
and ApiKeyProvider
classes respectively.
Enabling the API key authentication is relatively straightforward and can be seen being configured in the Startup.cs
ConfigureServices
method.
services.AddAuthentication(ApiKeyDefaults.AuthenticationScheme)
.AddApiKeyInHeaderOrQueryParams<ApiKeyProvider>(o =>
{
o.Realm = "WebApiTutorial";
o.KeyName = "apiKey";
});
Notice that the AddApiKeyInHeaderOrQueryParams
method identifies the ApiKeyProvider
class to perform the identity mapping and that we are expecting the key to be identified by a query parameter called apiKey
.
For testing, there are three apiKeys known to this implementation (you can see them in the implementation of ApiKeyProvider
)
API Key | Subscription Level |
---|---|
123 | pro |
456 | std |
789 | free |
Any other apiKey is mapped to a free subscription
If you run the project you can use either of the following URLs to get a JSON response
https://localhost:5001/quote/<symbol>?apiKey=<key>
https://localhost:5001/quote/<symbol>/live?apiKey=<key>
Authorization policies
There is a Policy
folder in the solution. This contains an empty file called quotes.alfa
. You will be defining your authorization policy in this file during the tutorial.