aws / aws-lambda-dotnet

Libraries, samples and tools to help .NET Core developers develop AWS Lambda functions.
Apache License 2.0
1.58k stars 478 forks source link

HttpContext is null for AWS Lambda Function Handler (Executable assembly) #1665

Closed vladyslav-sosnov closed 5 months ago

vladyslav-sosnov commented 9 months ago

Describe the bug

HttpContext is always null after it has been injected into AWS Lambda Function Handler. For comparison, it is populated while using the MinimalAPI approach.

Expected Behavior

HttpContext is populated with Items (and Session data when AWS DynamoDB session provider is used)

Current Behavior

HttpContext object is always null when injected in the AWS Lambda Function Handler.

Reproduction Steps

Code sample illustrating the absence of HttpContext.

using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport;
using Amazon.Lambda.Serialization.SystemTextJson;
using Microsoft.AspNetCore.DataProtection;

var authorizerSettings = new SessionAuthorizerSettings();
var serviceCollection = new ServiceCollection();

serviceCollection.AddAWSLambdaHosting(LambdaEventSource.HttpApi);

serviceCollection.AddSingleton<ISessionAuthorizerSettings, SessionAuthorizerSettings>();

serviceCollection
    .AddDataProtection()
    .SetApplicationName(authorizerSettings.DataProtectionAppName)
    .DisableAutomaticKeyGeneration();

serviceCollection
    .AddHttpContextAccessor();

serviceCollection
    .AddAWSDynamoDBDistributedCache(options =>
    {
        options.TableName = authorizerSettings.CacheTableName;
        options.PartitionKeyName = authorizerSettings.PartitionKeyName;
        options.TTLAttributeName = authorizerSettings.TTLAttributeName;
    })
    .AddSession(options =>
    {
        options.Cookie.Name = ".Cookie.Session";
        options.IdleTimeout = TimeSpan.FromMinutes(30);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });

var serviceProvider = serviceCollection.BuildServiceProvider();

var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();

var httpContext = httpContextAccessor?.HttpContext;

var handler = (APIGatewayHttpApiV2ProxyRequest request, ILambdaContext lambdaContext) =>
{
    var userId = "12345";

    // ISSUE: 'httpContext' is always null and therefore, the session can not be accessed.
    var session = httpContext.Session;
    var sessionData = ObjectSerializer.Deserialize<SessionPermissions>(session.GetString(userId));

    // An example of a typical response from the authorizer to invoke the requested Lambda.
    var response = new APIGatewayCustomAuthorizerResponse
    {
        PolicyDocument = new APIGatewayCustomAuthorizerPolicy
        {
            Version = "2012-10-17",
            Statement = new List<APIGatewayCustomAuthorizerPolicy.IAMPolicyStatement>
            {
                 new()
                 {
                     Action = new HashSet<string> {"execute-api:Invoke"},
                     Effect = "Allow",
                     Resource = new HashSet<string> { $"arn:aws:execute-api:{lambdaContext.InvokedFunctionArn}:{request.RequestContext.AccountId}:{request.RequestContext.ApiId}/$default/*" }
                 }
            },
        },
        PrincipalID = userId,
        Context = new APIGatewayCustomAuthorizerContextOutput
        {
            ["data"] = sessionData.Data
        }
    };
};

await LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
        .Build()
        .RunAsync();

Possible Solution

No response

Additional Information/Context

Alternatively, a Minimal API approach was trialed where HttpContext was populated with Items and Session data, however, it returned a response that is incorrect for a Custom Authorizer (Raised in a separate issue)

Context HttpContext is required to access session data.

For this purpose, AWS DynamoDB session provider has been integrated and API Gateway HTTP Payload v2.0 was used.

Apart from the use of Function Handler, the Lambda Entry Point approach was used. This approach faces the same issue as the Function Handler, where HttpContext is null. Amazon.Lambda.AspNetCoreServer

AWS .NET SDK and/or Package version used

Targeted .NET Platform

.Net 6

Operating System and version

AWS Lambda

ashishdhingra commented 7 months ago

@vladyslav-sosnov Good afternoon. I'm unsure if I understand your code, per my knowledge, HttpContext by default is available only in the context of web applications. Although your code calls serviceCollection.AddHttpContextAccessor();, this per HttpServiceCollectionExtensions.AddHttpContextAccessor, adds a default implementation for the IHttpContextAccessor service, which provides access to the current HttpContext, if one is available. The handler you are configuring is a simple Lambda function handler. Refer ASP.NET Core minimal APIs section at https://aws.amazon.com/blogs/compute/introducing-the-net-6-runtime-for-aws-lambda/ on how to use Amazon.Lambda.AspNetCoreServer.Hosting package.

CCing @normj for any inputs.

Thanks, Ashish

github-actions[bot] commented 7 months ago

This issue has not received a response in 5 days. If you want to keep this issue open, please just leave a comment below and auto-close will be canceled.

vladyslav-sosnov commented 7 months ago

Hello, @ashishdhingra. Indeed, within this Lambda function handler, accessing HttpContext is not possible, which is the exact challenge I'm facing. I understand this might be by design, but I'm curious if there are any intentions to introduce HttpContext support. Alternatively, is there a method to inject it effectively so the context becomes available?

normj commented 7 months ago

@vladyslav-sosnov There are no plans to add HttpContext support into the basic Lambda programming model. That is an ASP.NET Core concept that brings with it a lot of dependencies and concepts that we would not introduce into the basic Lambda programming model. What is it you need from HttpContext that isn't available in the APIGatewayHttpApiV2ProxyRequest.

vladyslav-sosnov commented 6 months ago

@normj Hello! We need to access the session from AWS Dynamo DB Distributed Cache. Alternatively, if we use the Minimal API approach as described in #1666, we are already able to retrieve the session from the HttpContext but Minimal API does not return the correct Custom Authorizer response (as it wraps the response in the body property).

For this issue, the response is in the correct format (for a Custom Authorizer) but the session can not be retrieved.

Our preference, if possible, is to be able to use the Minimal API approach (#1666) if the response could be fixed to return the correct response for a Custom Authorizer.

ashishdhingra commented 5 months ago

Per @normj in https://github.com/aws/aws-lambda-dotnet/issues/1665#issuecomment-2026285737, there are no plans to add HttpContext support into the basic Lambda programming model. Hence, closing this issue.

github-actions[bot] commented 5 months ago

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.