Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Claims from authorizer lost in deserialisation and not mapped to HttpContext.User #98

Closed
ljacobsson opened this issue Apr 10, 2017 · 14 comments
Labels
feature-request A feature should be added or improved.

Comments

@ljacobsson
Copy link

ljacobsson commented Apr 10, 2017

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

@ShaneGMamet
Copy link

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

@ljacobsson
Copy link
Author

@MattEttler
Copy link

Also running into this. Would love a fix!

@PaulKGray
Copy link

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

@normj
Copy link
Member

normj commented Aug 24, 2017

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.

@PaulKGray
Copy link

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; }
    }

normj added a commit that referenced this issue Jan 15, 2018
…equest to be serialized into APIGatewayCustomAuthorizerContext.

If there are claims create ClaimsPrincipal for the HttpContext.User with the claims for the AspNetCoreServer

This address GitHub issue #98
@normj
Copy link
Member

normj commented Jan 16, 2018

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.

@swlasse
Copy link

swlasse commented Jan 22, 2018

@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? )

@normj
Copy link
Member

normj commented Jan 25, 2018

@swlasse I believe your issue is covered by this github issue #159 which I still need to look into.

@swlasse
Copy link

swlasse commented Feb 2, 2018

@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.

@swlasse
Copy link

swlasse commented Feb 9, 2018

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.

@kaurranjeet12
Copy link

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.

@diehlaws diehlaws added feature-request A feature should be added or improved. and removed Enhancement labels Jan 3, 2019
@dandonovan78
Copy link

dandonovan78 commented Feb 14, 2019

@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!

@Babalev
Copy link

Babalev commented Mar 7, 2019

@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<string, object>, 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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved.
Projects
None yet
Development

No branches or pull requests

10 participants