swift-server / swift-aws-lambda-runtime

Swift implementation of AWS Lambda Runtime
Apache License 2.0
1.13k stars 102 forks source link

Lambda Authorizer - APIGateway.Request #147

Closed rmickeyd closed 3 months ago

rmickeyd commented 4 years ago

Expected behavior

Obtain information passed from a Lambda Authorizer into Lambda.

Note: This is the REST API (V1)

Actual behavior

Inability to access information due to parameter not existing on APIGateway.Request

If possible, minimal yet complete reproducer code (or URL to code)

{
...
"requestContext": {
      "authorizer": {
        "principalId": "user-id",
        "integrationLatency": 557
      }
}
...
}

Maybe it makes sense to add this to APIGateway.Request.

public let authorizer: Authorizer?

public struct Authorizer: Codable {
    public let principalId: String
    public let context: [String: String]?
}

// OR

public let authorizer: [String: String]?
tomerd commented 4 years ago

thanks for reporting @rmickeyd ~is this issue while using lambda vi api gateway?~ is this the feature you are referring to?

wdyt @fabianfett

rmickeyd commented 4 years ago

@tomerd yes, this is the feature. Decoding might not be straight forward though. It seems when you generate an IAM policy you set a principalId which seems to always be present and then user defined attributes. The issue is AWS sends this all lumped together in one container like so:

"requestContext": {
      "authorizer": {
        "principalId": "user-id",
        "integrationLatency": 557,
        "userDefinedString": "stringval",
        "userDefinedNumber": 123,
        "userDefinedBool": true
      }
}
tomerd commented 4 years ago

I see. any ideas on how to do this generically or should it be left as exercise for the Lambda author?

rmickeyd commented 4 years ago

imo the critical piece of information is the principalId. This is what should identify the user that made the authenticated call. I think it would make sense to ensure that is clearly exposed and then leave it up to the author to convert any other values from strings to whatever type they are attempting to pass through. Otherwise, we would need an extension to decode [String: Any] but with this method casting would be needed for every type including strings so the value in doing this is limited.

I think something like this would make the most sense:

            public let authorizer: Authorizer?

            public struct Authorizer: Codable {
                public let principalId: String
                public let context: [String: String]

                public init(from decoder: Decoder) throws {
                    let container = try decoder.container(keyedBy: CodingKeys.self)
                    self.principalId = try container.decode(String.self, forKey: .principalId)
                    self.context = try decoder.singleValueContainer().decode(Dictionary<String, String>.self)
                }
            }

If this sounds good I can throw up a PR with this implemented.

tomerd commented 4 years ago

sounds fine to me if it works correctly. @fabianfett opinion?

fabianfett commented 4 years ago

sounds fine to me if it works correctly. @fabianfett opinion?

+1 from my side. We'll definitely need unit tests for this.

@bmoffatt Is there any document that describes all Authorizer payloads? Can we assume that will always be a dictionary with just String values and at least the principalId key?

Go uses interface{} for the values... https://github.com/aws/aws-lambda-go/blob/eebb9958b0b4c19edcfdff58326d0bf40e8ddf6b/events/apigw.go#L43

The closest thing that we have is AnyCodable, but I guess we don't want to add another dependency?

C# uses a [String: String] dictionary: https://github.com/aws/aws-lambda-dotnet/blob/e2bb81a4b48a402570b0de828772067938ca5671/Libraries/src/Amazon.Lambda.APIGatewayEvents/APIGatewayCustomAuthorizerContext.cs#L114

And thanks for reporting @rmickeyd. Because of the problems outlined above, I refrained from this feature so far. But we should definitely do something about it!

audente commented 3 years ago

Hi,
I have the same issue but I can't see the modified code or a PR with it. Any news on this? Was this implemented?

audente commented 3 years ago

I've added a PR with a [String:String] dictionary.

In my use case (Cognito -> API Gateway -> Lambda), I don't receive a 'principalID' key.

sebsto commented 3 months ago

LambdaAuthorizer is now part of Lambda events project. I'm closing this. Feel free to open an issue on Lambda events if something is not working