Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom authorizer data with Amazon.Lambda.AspNetCoreServer

Having worked extensively with Node.js in the past, we are currently investigating ASP.NET Core as an alternative Lambda platform.

In the past, our API Gateway-fronted services relied on a custom authorizer, which authenticated the user and retrieved a list of resource-based permission policies from our company's IAM service. The authorizer attaches that list to the authContext key. Our services would integrate with API Gateway via Lambda Proxy and extract the principal object from the raw proxy request.

When using Amazon.Lambda.AspNetCoreServer to translate between API Gateway and ASP.NET, we are unable to arrive at a similar scenario.

Amazon.Lambda.AspNetCoreServer::ApiGatewayProxyFunction::FunctionHandlerAsync(Stream responseStream, ILambdaContext lambdaContext), or any equivalent Lambda handler signature for that matter, receives the complete, raw request in the first parameter. It is possible to serialize the stream (for example, into a JSON.NET JObject) and extract the principal object there.

However, what proves difficult is accessing that data within the ASP.NET application. I am not convinced that the authorizer response is passed to the HTTP context. When checking it, the ClaimsPrincipal context.User key contains no data.

Several solutions were thrown around:

  • retrieving IAM information in the overriden FunctionHandlerAsync and storing them globally using environment variables or sessions
  • creating an interface and a complementary implementation of an IAM provider service. It would expose a method to retrieve IAM information. The implementation would simply return a deserialized list of claims. The service would be configured in an overriden Init(IWebHostBuilder) method.
  • gluing together a (Claims/General)Principal object and attempting to pass it to the HTTP context

Is there a way to achieve this cleanly?

like image 796
Igor Sowinski Avatar asked Nov 07 '22 23:11

Igor Sowinski


1 Answers

We've in the exact same situation and I can by no means offer a nice and clean solution, but I have a workaround.

If you look at the request payload, the json is formatted like this:

{
    [...]
    "requestContext": {
        [...]
        "authorizer": {
            "claims": {
                "claim1": "value1",
                "claim2": "value2",
                "claim3": "value3",
            }
        },
        [...]

In APIGatewayProxyFunction.FunctionHandlerAsync they deserialize the requestStream into an APIGatewayProxyRequest. If you step into that class you'll find that the Authorizer part of the json gets deserialized into:

public class APIGatewayCustomAuthorizerContext
{
    public string PrincipalId { get; set; }
    public string StringKey { get; set; }
    public int? NumKey { get; set; }
    public bool? BoolKey { get; set; }
}

I.e all claims are lost in deserialization. I've posted this issue here: https://github.com/aws/aws-lambda-dotnet/issues/98

Now to the workaround, I've just put something that "works" together here (Code here):

Note that it's very untested. :-)

Usage:

public class LambdaEntryPoint : APIGatewayAuthorizerProxyFunction
{
    protected override void Init(IWebHostBuilder builder)
    {
        builder
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseApiGateway();
    }
}
like image 57
lars-august Avatar answered Nov 14 '22 22:11

lars-august