-
Notifications
You must be signed in to change notification settings - Fork 497
Added FromCustomAuthorizerAttribute and tests. #1466
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
base: dev
Are you sure you want to change the base?
Conversation
normj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool PR!
Can you fix the whitespaces changes to the LambdaFunctionTemplate.tt file? The whole file is looks different.
Who should we handle the other type of authorizer properties. For example on the APIGatewayHttpApiV2ProxyRequest besides the Lambda property there is also Jwt and IAM properties. Should we make the string accessing the authorizer field have the prefix of the property.
|
Wiil do my best with the withspace. |
|
don't seem to be able to fix the whitespace issue to save my life :( Tried setting EOL to LF and CR, both cause problems with the generated file. The correct one seems to be CRLF . Please feel free to edit. |
|
Would be really nice to get this avail;able. I will gladly fix the conflicts if this can be looked at again. |
|
I can see you did a major refactoring in the dev branch will push again once released. If i might be so bold, I looked at what you did. Just a thought. |
|
@kabaluk I suspect adding new attributes would be done in separate files. For example if we added SQS or S3 I would put them in separate TT. One of my goals with the refactor was to make it easier to add new attributes as the previous monolithic tt file was really hard to reconcile with. Another goal I had was I wanted to generate the exact same code including whitespaces to make the PR review easier and then later I could do more specific refactoring. Otherwise the PR review would have been every line is different and that is hard to review. But going forward I could see putting each of the |
I was talking specifically of the FromXXX attributes. Apologies, I should have been more explicit. Sounds like a great change and it would make it a lot easier to add and test more FromXXX attributes. Looking forward to have that in main so i can re add the FromCustomAuthorizer attribute. |
|
Readded CustomAuthorizerAttribute.. Hope you like it :) |
|
Any possibility of having this looked at again, please? |
normj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did an initial scan and it looks good. I had one comment so far. I need to test the experience end to end next. I'll try and find time to do that soon.
Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt
Outdated
Show resolved
Hide resolved
|
im working on rebasing this |
f14bd0b to
48afb69
Compare
| try | ||
| { | ||
| var __authValue_<#= parameter.Name #>__ = __request__.RequestContext.Authorizer["<#= authKey #>"]; | ||
| <#= parameter.Name #> = (<#= parameter.Type.FullName #>)Convert.ChangeType(__authValue_<#= parameter.Name #>__?.ToString(), typeof(<#= parameter.Type.FullNameWithoutAnnotations #>)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why We Need .ToString() for Custom Authorizer Values
The Data Flow
-
Authorizer Lambda returns context: When your custom authorizer runs, it returns a context dictionary:
Context = new Dictionary<string, object> { { "userId", "12345" }, { "permissions", "admin" } }
-
API Gateway passes this to the protected Lambda in the request payload as JSON:
{ "requestContext": { "authorizer": { "userId": "12345", "permissions": "admin" } } } -
Lambda deserializes the request using the configured serializer (System.Text.Json or Newtonsoft.Json).
The Problem: Dictionary<string, object> Deserialization
The Authorizer property is typed as Dictionary<string, object>:
public class APIGatewayCustomAuthorizerContext : Dictionary<string, object>When the serializer encounters a JSON value like "12345" and needs to deserialize it into object, it doesn't know what concrete type to use. So:
- System.Text.Json wraps it in a
JsonElementstruct - Newtonsoft.Json wraps it in a
JToken(likeJValue)
so rather than having statements like
if (__authValue__ is System.Text.Json.JsonElement jsonElement)
{
userId = Convert.ChangeType(jsonElement.ToString(), typeof(string));
}
i just call toString which both of these serializers have.
not sure if there is a better way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@normj not sure if you have any better ideas here of it ToString is good enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the values be numerics instead of strings? If so how would that work out with this approach? Or are we saying for the FromCustomerAuthorizer we only support string parameters. If so we should make sure we are enforcing that and put out diagnostic warnings if they attempt something we don't support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so what im doing here is converting it to a string then using https://learn.microsoft.com/en-us/dotnet/api/system.convert.changetype?view=net-10.0 afterwards to convert to the parameters type.
i will add an integration test to confirm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so i added integration tests to confirm
- int values work
- string values work
- boolean values work
double values do not work because of a limitation with api gateway not supporting it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt
Show resolved
Hide resolved
...ceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs
Show resolved
Hide resolved
.../Snapshots/CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs
Show resolved
Hide resolved
.../Snapshots/CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 31 out of 31 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs
Show resolved
Hide resolved
...ambda.Annotations.SourceGenerators.Tests/Snapshots/AuthNameFallback_GetUserId_Generated.g.cs
Show resolved
Hide resolved
...ambda.Annotations.SourceGenerators.Tests/Snapshots/AuthNameFallback_GetUserId_Generated.g.cs
Show resolved
Hide resolved
| using Amazon.CloudFormation; | ||
| using Amazon.CloudFormation.Model; | ||
|
|
||
| namespace IntegrationTests.Helpers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is all existing code just moved into a common project to share between the two integration test projects
Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt
Show resolved
Hide resolved
Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt
Show resolved
Hide resolved
| try | ||
| { | ||
| var __authValue_<#= parameter.Name #>__ = __request__.RequestContext.Authorizer["<#= authKey #>"]; | ||
| <#= parameter.Name #> = (<#= parameter.Type.FullName #>)Convert.ChangeType(__authValue_<#= parameter.Name #>__?.ToString(), typeof(<#= parameter.Type.FullNameWithoutAnnotations #>)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the values be numerics instead of strings? If so how would that work out with this approach? Or are we saying for the FromCustomerAuthorizer we only support string parameters. If so we should make sure we are enforcing that and put out diagnostic warnings if they attempt something we don't support.
Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt
Show resolved
Hide resolved
Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 56 out of 56 changed files in this pull request and generated 42 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Libraries/test/TestServerlessApp.IntegrationTests/IntegrationTestContextFixture.cs
Outdated
Show resolved
Hide resolved
| { | ||
| var expectedTemplateContent = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "authorizerHttpApi.template")); | ||
| var expectedRestAuthorizerGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs")); | ||
|
|
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable name expectedRestAuthorizerGenerated is misleading in this HTTP API test (it contains the expected HttpApi generated output). Rename it to something like expectedHttpApiAuthorizerGenerated to avoid confusion and make future maintenance easier.
| # Response: "Hello user-12345! You are a admin in tenant 42." | ||
| ``` |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor grammar in the example response: "You are a admin" should be "You are an admin".
| public async Task HttpApiV1UserInfo_WithValidAuth_ReturnsAuthorizerContext() | ||
| { | ||
| // Arrange | ||
| var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/http-v1-user-info"); |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disposable 'HttpRequestMessage' is created but not disposed.
| public async Task HttpApiV1UserInfo_WithMissingAuthorizerContextKey_ReturnsUnauthorized() | ||
| { | ||
| // Arrange - use partial-context token that authorizes but omits expected context keys | ||
| var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/http-v1-user-info"); |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disposable 'HttpRequestMessage' is created but not disposed.
| #if NET6_0_OR_GREATER | ||
| __context__.Logger.LogError(e, "Failed to convert authorizer attribute 'theAuthKey', returning unauthorized."); | ||
| #else | ||
| __context__.Logger.Log("Failed to convert authorizer attribute 'theAuthKey', returning unauthorized. Exception: " + e.ToString()); |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant call to 'ToString' on a String object.
| if (val is System.Text.Json.JsonElement jsonElement) | ||
| { | ||
| context.Logger.LogLine($" JsonElement.ValueKind: {jsonElement.ValueKind}"); | ||
| context.Logger.LogLine($" JsonElement.ToString(): '{jsonElement.ToString()}'"); |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant call to 'ToString' on a String object.
| // Try to get context values if Lambda dictionary exists | ||
| if (request.RequestContext.Authorizer.Lambda != null) | ||
| { | ||
| var userId = request.RequestContext.Authorizer.Lambda.ContainsKey("userId") |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inefficient use of 'ContainsKey' and indexer.
| var userId = request.RequestContext.Authorizer.Lambda.ContainsKey("userId") | ||
| ? request.RequestContext.Authorizer.Lambda["userId"]?.ToString() | ||
| : "NOT_FOUND"; | ||
| var tenantId = request.RequestContext.Authorizer.Lambda.ContainsKey("tenantId") |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inefficient use of 'ContainsKey' and indexer.
| var tenantId = request.RequestContext.Authorizer.Lambda.ContainsKey("tenantId") | ||
| ? request.RequestContext.Authorizer.Lambda["tenantId"]?.ToString() | ||
| : "NOT_FOUND"; | ||
| var userRole = request.RequestContext.Authorizer.Lambda.ContainsKey("userRole") |
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inefficient use of 'ContainsKey' and indexer.
PR Description:
[FromCustomAuthorizer]Attribute SupportSummary
Adds
[FromCustomAuthorizer]attribute to extract Lambda authorizer context values directly into method parameters.Usage
Supported API Types
RequestContext.Authorizer["key"]RequestContext.Authorizer["key"]RequestContext.Authorizer.Lambda["key"]Behavior
Nameproperty if specified, otherwise falls back to parameter nameIHttpResultreturn typesTesting