Sunday, December 08, 2019

Use Azure Functions to control access to Azure API Management APIs


In some custom scenarios the authorization logic can be implemented using advanced Azure API Management policies (https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies), but  this option is tightly coupled to the requirement to maintain access control logic within Azure API Management policy as Azure API Management asset, which may lead to complicated CI/CD strategies and processes and so on).

Another approach is to “outsource” the access control logic to an external service, maintain it separately from Azure API Management instance and use it from Azure API management inbound policy (https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-policies) to control access to APIs or single methods using appropriated policy scope (https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-policies#apply-policies-specified-at-different-scopes).

The idea behind this approach:

  •         Implement an access control [micro]service to make decision to allow or to deny access control to certain Azure API Management API or method (for example, Azure Function),
  •      Incoming request to an API method is received by Azure API Management instance,
  •         Inbound policy of the API or method extract from request information, essential to allow or to deny access to the API or method,
  •         Inbound policy issues request to the access control service (s. above) using information, extracted from request,
  •         Access control service returns response with either allowed or denied permission,
  •         Inbound policy uses the response from access control service to deny access or to pass it thru to the backend.
The flow of events in this diagram:







      1 An  API client sends a request to an API method (including information for access control) in Azure API Management instance.
2 The request is intercepted and analyzed by inbound policy, Azure API Management instance sends another request to an external access control service.
3 Access control service responds to Azure API Management instance with information about allowed or denied access.
4 If access is allowed, inbound policy passes the request thru the chain to backend service
             4* If access is denied, according response is returned to the API client and request is not passed to backend.

Let’s look at a sample implementation of this approach.

Assume an access control service implemented as Azure Function:

#r "Newtonsoft.Json"
using System.Net;
using System.Text;
using Newtonsoft.Json;

//
// Sample implementation of access control service
// for Azure APi Management API and method protection
// making decision to allow or deny access based on
// custom token value and API name.
//
// This function is intented to use from Azure API Management
// inbound policy to implement fine granulated custom access
// control to APIs and single methods
//
// HTTP GET request parameters:
// - token: custom access token string
// - API: API name
//
// Response JSON
// { "permitted": true | false}
//

public static async Task Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");

    // parse query parameter - access token value
    string token = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "token", true) == 0)
        .Value;

    // parse query parameter - API name
    string api = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "API", true) == 0)
        .Value;

    //
    // This primitive access control logic must be replaced by custom
    //
    var access = new {permitted = (token=="permittedTokenValue"?true:false)};
    var jsonObject = JsonConvert.SerializeObject(access);
   
    return new HttpResponseMessage(HttpStatusCode.OK) {
        Content = new StringContent(jsonObject, Encoding.UTF8, "application/json")
    };
}


This primitive function can be used as custom access control service using HTTP GET requests with two query parameters: custom token and API name:
https:///api/CheckAccess?token=mytoken&API=test
getting JSON response either
{"permitted":false}
Or
{"permitted":true}
Assume for simplicity the API client sends custom access token information in a custom HTTP header named “token” (in real life you may want to extract access control specific information from JWT token as referenced above).
The inbound policy of an API method with customized access control looks then like


<inbound>
       
        <set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("token",""))" />
       
        <send-request mode="new" response-variable-name="access" timeout="20" ignore-error="true">
           
            <set-url>@("https://mbecho.azurewebsites.net/api/CheckAccess?token="+(string)context.Variables["token"]+"&API=protectedAPI")</set-url>
            <set-method>GET</set-method>
            <set-header name="Authorization" exists-action="override">
                <value>whatever</value>
            </set-header>
            <set-header name="Content-Type" exists-action="override">
                <value>application/x-www-form-urlencoded</value>
            </set-header>
            <set-body />
        </send-request>
        <choose>
           
            <when condition="@((bool)((IResponse)context.Variables["access"]).Body.As()["permitted"] == false)">
               
                <return-response response-variable-name="existing response variable">
                    <set-status code="401" reason="Unauthorized" />
                </return-response>
            </when>
        </choose>
       
        <base />

    </inbound>

Test the protected API method with “permittedTokenValue” succeeds

…and fails with any other values

The “Trace” tab in Test pane of Azure API Management section in Azure portal contains detailed info about flow of events and request and policy processing. The additional latency caused by use of an external access control service in this sample is under 50 msecs





Wednesday, November 27, 2019

Just another quick approach to test Azure API Management policies using requestbin


Here a short dump how to use requestbin (https://requestbin.com/) for API Management policy testing.

Navigate to requestbin (https://requestbin.com/)

Create a Request Bin

Get a new endpoint

Press „Generate Test Events“ to learn how to record and inspect incoming requests

Click a request in the left pane (live incoming requests sequence) and inspect request content (headers, body) in the right pane



Copy and store the endpoint URL for use as backend URL in Azure API Management
Open Azure portal and login to your account [or create new one – https://azure.microsoft.com/en-us/free/]
Navigate to your API Management instance
Navigate to APIs
Add new blank API
Enter data for new blank API (set Web service URL to URL copied from requestbin as described above)
Create new API operation
Set operation parameters as required (here we use POST sample)
Save the operation and return to API design pane
Switch to „Test“ pane, enter test data (headers, body) for test request, press “Send”

Inspect response in Test pane

Inspect „Trace“ records
Switch to requestbin and inspect incoming request


Back to API portal, start policy editor
Enter policy to test, for example

<policies>
    <inbound>
        <base />
        <set-body>@(context.Request.Body.As<String>().ToUpper())</set-body>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Be aware to enter policy on the right place (selected operation, all operations etc.), save it finally
Return to Test pane, enter test request data, send the request
Inspect response data in Test pane
Inspect Trace records (specially, details about how the policy was applied)
Requestbin console lists this request as
And the contents are [uppercased due to applied sample policy]
Enjoy!