Aws-lambda-dotnet: Claims from authorizer lost in deserialisation and not mapped to HttpContext.User

Created on 10 Apr 2017  路  14Comments  路  Source: aws/aws-lambda-dotnet

In APIGatewayProxyFunction.FunctionHandlerAsync where the requestStream gets deserialised into APIGatewayProxyRequest we lose all custom claims that were present in the requestStream's json.

It'd be nice if apiGatewayRequest.RequestContext.Authorizer would contain a Dictionary<string,string> with claims which get added to HttpContext.User.

Thanks,
Lars

feature-request

Most helpful comment

As part of the .NET Core 2.0 Lambda release today I updated Amazon.Lambda.APIGatewayEvents and Amazon.Lambda.AspNetCoreServer to pass along the claims and create the HttpContext.User similar to how @ljacobsson was doing in his code.

I'm going to close this as I believe that solves the problem. Feel free to reopen or open a new issue if there are more use cases that are not met.

All 14 comments

Any updates on this, I have just experienced the same limitation. Having the apiGatewayRequest.RequestContext.Authorizer as a dictionary would be a great solution.

Also running into this. Would love a fix!

I am also hitting this issue, Any idea on when a fix might become available?

If somebody could send me a sample request that would speed up my time to getting this implemented. To send a sample request add the environment variable LAMBDA_NET_SERIALIZER_DEBUG with a value of true. Then after executing the request where the claims are stripped go to your CloudWatch logs and grab the JSON request string.

Hi I added this but it didnt give me much info,

you can get the raw request by taking the input as a Stream

public APIGatewayProxyResponse ProxyFunctionHandler(System.IO.Stream input, ILambdaContext context) {
            StreamReader reader = new StreamReader(input);
            string request = reader.ReadToEnd();
            Console.WriteLine(request);
            return new APIGatewayProxyResponse { StatusCode = 200 };
}

The full request is quite big but the data that is missing looks like this.

{
    "requestContext": {
        "authorizer": {
            "claims": {
                "sub": "XXXX",
                "aud": "XXXX",
                "token_use": "id",
                "auth_time": "1503560181",
                "iss": "https://cognito-idp.eu-west-1.amazonaws.com/eu-west-1_XXXXXX",
                "cognito:username": "TestUser",
                "exp": "Thu Aug 24 08:36:21 UTC 2017",
                "iat": "Thu Aug 24 07:36:21 UTC 2017"
            }
        }
    }
}

It is possible to deserialize the object to the classes below using JsonConvert as a work around

var claimsFix = JsonConvert.DeserializeObject<ClaimsFix>(request);

   class ClaimsFix
    {
        public RequestContext RequestContext;
    }

    public class RequestContext
    {
        public Authorizer Authorizer;
    }

    public class Authorizer
    {
        public Dictionary<string, string> Claims { get; set; }
    }

As part of the .NET Core 2.0 Lambda release today I updated Amazon.Lambda.APIGatewayEvents and Amazon.Lambda.AspNetCoreServer to pass along the claims and create the HttpContext.User similar to how @ljacobsson was doing in his code.

I'm going to close this as I believe that solves the problem. Feel free to reopen or open a new issue if there are more use cases that are not met.

@normj Thanks for this.

I think it is a great addition that we can now use APIGatewayCustomAuthorizerContext as a dictionary, however, I'm not sure how I should go about this when returning an APIGatewayCustomAuthorizerResponse in my custom authorizer?

In particular, when doing a custom authorizer, we can return an APIGatewayCustomAuthorizerResponse with the Context property being of type: APIGatewayCustomAuthorizerContextOutput.

However, looking at APIGatewayCustomAuthorizerContextOutput, it is still using:

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

... which are now marked obsolete in APIGatewayCustomAuthorizerContext.

I guess the APIGatewayCustomAuthorizerContextOutput should derive from Dictionary<string, object> as well, in order to make it compatible with the new APIGatewayCustomAuthorizerContext? ( and likewise, mark the StringKey, Numkey, and BoolKey attributes as obsolete? )

@swlasse I believe your issue is covered by this github issue https://github.com/aws/aws-lambda-dotnet/issues/159 which I still need to look into.

@normj, yeah, that looks right. At the moment we serialize our custom context into the StringKey parameter of the APIGatewayCustomAuthorizerContextOutput. It works, but its not ideal.

It could be nice though if we could send through Claims and see them getting picked up by the new Claims property on APIGatewayCustomAuthorizerContext.

With #159 resolved, we can now add a key-val pair to APIGatewayCustomAuthorizerContextOutput holding our own custom context serialized as a JSON string. Strictly speaking, we could do that before with the StringKey property, but the property name was a bit confusing. With APIGatewayCustomAuthorizerContextOutput now deriving from Dictionary<string, object> we can set our own key, and name it as we like. This gives us the flexibility we need in order to send trough claims, etc. Thanks for resolving this.

Hi, I am a new bee to API Gateway and Lambda. I am trying to get the authorized user from my custom authorizer that returns user object. After enabling APIGatewayProxyRequest logging (LAMBDA_NET_SERIALIZER_DEBUG) I can see my user object getting logged in cloudwatch but when I am serializing the request in my lambda the authorizer section is empty.

Lambda Deserialize Amazon.Lambda.APIGatewayEvents.APIGatewayProxyRequest:
"requestContext": {
"authorizer": {
"principalId": "**",
"user": ""
},
"resourcePath": "/{proxy+}",
"httpMethod": "GET" .....
}
}

My Lambda: "Authorizer": {}

I highly appreciate your help.
Thank you.

@normj : I think I'm missing something. I have a CustomAuthorizer returning a valid policy (taken from the blueprint). I want my underlying Lambda service to be able to access the PrincipalId, ideally in the HttpContext.User object. It looks as if this is only set when Claims are present in the request? I'm missing how to add Claims in my custom Authorizer? I'm returning a policy statement that looks like this:
PrincipalId: "id-i-want-to-get"
Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "arn:aws:execute-api:us-east-1:xxxxx:/qa//*"
}
]
}
It looks like I can get the ID by override the PostCreateContext function myself, though it feels like I shouldn't need to do that? Am I missing something? Thanks!

@normj : I have a rather connected question, and decided not to open another thread. What you've done with the APIGatewayProxyRequest is great, but do you have any plans for APIGatewayCustomAuthorizerContextOutput and more specific - allowing the values to be something more than a string value. In general the class is a Dictionary, but according to the https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html - _The returned values are all stringified. Notice that you cannot set a JSON object or array as a valid value of any key in the context map._ This is kind of frustrating, because you can't send back an array of claims from the authorizer, and then pass them to the lambda you want to execute. Of course there are ways to put all the claims in the response, but then we are loosing the purpose of the change you made for the ClaimsIdentity and the HttpContext.User. Am I missing something, or my assumption is right?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Kralizek picture Kralizek  路  3Comments

pandaedward picture pandaedward  路  6Comments

ghost picture ghost  路  3Comments

martincostello picture martincostello  路  4Comments

JustinGrote picture JustinGrote  路  5Comments