Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ public static AttributeModel Build(AttributeData att, GeneratorExecutionContext
Type = TypeModelBuilder.Build(att.AttributeClass, context)
};
}
else if(att.AttributeClass.Equals(context.Compilation.GetTypeByMetadataName(TypeFullNames.FromCustomAuthorizerAttribute), SymbolEqualityComparer.Default))
{
var data = FromCustomAuthorizerAttributeBuilder.Build(att);
model = new AttributeModel<FromCustomAuthorizerAttribute>
{
Data = data,
Type = TypeModelBuilder.Build(att.AttributeClass, context)
};
}
else if (att.AttributeClass.Equals(context.Compilation.GetTypeByMetadataName(TypeFullNames.HttpApiAttribute), SymbolEqualityComparer.Default))
{
var data = HttpApiAttributeBuilder.Build(att);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Amazon.Lambda.Annotations.APIGateway;
using Microsoft.CodeAnalysis;

namespace Amazon.Lambda.Annotations.SourceGenerator.Models.Attributes
{
public class FromCustomAuthorizerAttributeBuilder
{
public static FromCustomAuthorizerAttribute Build(AttributeData att)
{
var data = new FromCustomAuthorizerAttribute();
foreach (var pair in att.NamedArguments)
{
if (pair.Key == nameof(data.Name) && pair.Value.Value is string value)
{
data.Name = value;
}
}

return data;
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,85 @@
validationErrors.Add($"Value {__request__.Body} at 'body' failed to satisfy constraint: {e.Message}");
}

<#
}
}
else if (parameter.Attributes.Any(att => att.Type.FullName == TypeFullNames.FromCustomAuthorizerAttribute))
{
var fromAuthorizerAttribute = parameter.Attributes?.FirstOrDefault(att => att.Type.FullName == TypeFullNames.FromCustomAuthorizerAttribute) as AttributeModel<Amazon.Lambda.Annotations.APIGateway.FromCustomAuthorizerAttribute>;

// Use parameter name as key, if Name has not specified explicitly in the attribute definition.
var authKey = fromAuthorizerAttribute?.Data?.Name ?? parameter.Name;
if(restApiAttribute != null)
{
#>
var <#= parameter.Name #> = default(<#= parameter.Type.FullName #>);
if (__request__.RequestContext?.Authorizer == null || __request__.RequestContext?.Authorizer.ContainsKey("<#= authKey #>") == false)
{
return new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #>
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

try
{
<#= parameter.Name #> = (<#= parameter.Type.FullName #>)Convert.ChangeType(__request__.RequestContext.Authorizer["<#= authKey #>"], typeof(<#= parameter.Type.FullNameWithoutAnnotations #>));
}
catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException)
{
return new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #>
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

<#
}
else
{
#>
var <#= parameter.Name #> = default(<#= parameter.Type.FullName #>);
if (__request__.RequestContext?.Authorizer?.Lambda == null || __request__.RequestContext?.Authorizer?.Lambda.ContainsKey("<#= authKey #>") == false)
{
return new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #>
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

try
{
<#= parameter.Name #> = (<#= parameter.Type.FullName #>)Convert.ChangeType(__request__.RequestContext.Authorizer.Lambda["<#= authKey #>"], typeof(<#= parameter.Type.FullNameWithoutAnnotations #>));
}
catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException)
{
return new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #>
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

<#
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public static class TypeFullNames
public const string FromHeaderAttribute = "Amazon.Lambda.Annotations.APIGateway.FromHeaderAttribute";
public const string FromBodyAttribute = "Amazon.Lambda.Annotations.APIGateway.FromBodyAttribute";
public const string FromRouteAttribute = "Amazon.Lambda.Annotations.APIGateway.FromRouteAttribute";
public const string FromCustomAuthorizerAttribute = "Amazon.Lambda.Annotations.APIGateway.FromCustomAuthorizerAttribute";

public const string LambdaSerializerAttribute = "Amazon.Lambda.Core.LambdaSerializerAttribute";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

namespace Amazon.Lambda.Annotations.APIGateway
{
/// <summary>
/// Maps this parameter to a custom authorizer item
/// </summary>
/// <remarks>
/// Will try to get the specified key from Custom Authorizer values
/// </remarks>
[AttributeUsage(AttributeTargets.Parameter)]
public class FromCustomAuthorizerAttribute : Attribute, INamedAttribute
{
/// <summary>
/// Key of the value
/// </summary>
public string Name { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
</ItemGroup>

<ItemGroup>
<None Remove="snapshots\serverlesstemplates\authorizerHttpApi.template" />
<None Remove="Snapshots\ServerlessTemplates\authorizerrest.template" />
<None Remove="Snapshots\ServerlessTemplates\customizeResponse.template" />
<None Remove="Snapshots\ServerlessTemplates\dynamicexample.template" />
<None Remove="Snapshots\ServerlessTemplates\intrinsicexample.template" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Amazon.Lambda.Core;

namespace TestServerlessApp
{
public class CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated
{
private readonly CustomAuthorizerHttpApiExample customAuthorizerHttpApiExample;

public CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated()
{
SetExecutionEnvironment();
customAuthorizerHttpApiExample = new CustomAuthorizerHttpApiExample();
}

public async System.Threading.Tasks.Task<Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse> HttpApiAuthorizer(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__)
{
var validationErrors = new List<string>();

var authorizerValue = default(string);
if (__request__.RequestContext?.Authorizer?.Lambda == null || __request__.RequestContext?.Authorizer?.Lambda.ContainsKey("authKey") == false)
{
return new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

try
{
authorizerValue = (string)Convert.ChangeType(__request__.RequestContext.Authorizer.Lambda["authKey"], typeof(string));
}
catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException)
{
return new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

// return 400 Bad Request if there exists a validation error
if (validationErrors.Any())
{
var errorResult = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse
{
Body = @$"{{""message"": ""{validationErrors.Count} validation error(s) detected: {string.Join(",", validationErrors)}""}}",
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "ValidationException"}
},
StatusCode = 400
};
return errorResult;
}

await customAuthorizerHttpApiExample.HttpApiAuthorizer(authorizerValue, __context__);

return new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse
{
StatusCode = 200
};
}

private static void SetExecutionEnvironment()
{
const string envName = "AWS_EXECUTION_ENV";

var envValue = new StringBuilder();

// If there is an existing execution environment variable add the annotations package as a suffix.
if(!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName)))
{
envValue.Append($"{Environment.GetEnvironmentVariable(envName)}_");
}

envValue.Append("amazon-lambda-annotations_1.0.0.0");

Environment.SetEnvironmentVariable(envName, envValue.ToString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Amazon.Lambda.Core;

namespace TestServerlessApp
{
public class CustomAuthorizerRestExample_RestAuthorizer_Generated
{
private readonly CustomAuthorizerRestExample customAuthorizerRestExample;

public CustomAuthorizerRestExample_RestAuthorizer_Generated()
{
SetExecutionEnvironment();
customAuthorizerRestExample = new CustomAuthorizerRestExample();
}

public async System.Threading.Tasks.Task<Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse> RestAuthorizer(Amazon.Lambda.APIGatewayEvents.APIGatewayProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__)
{
var validationErrors = new List<string>();

var authorizerValue = default(string);
if (__request__.RequestContext?.Authorizer == null || __request__.RequestContext?.Authorizer.ContainsKey("theAuthKey") == false)
{
return new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

try
{
authorizerValue = (string)Convert.ChangeType(__request__.RequestContext.Authorizer["theAuthKey"], typeof(string));
}
catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException)
{
return new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse
{
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "AccessDeniedException"}
},
StatusCode = 401
};
}

// return 400 Bad Request if there exists a validation error
if (validationErrors.Any())
{
var errorResult = new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse
{
Body = @$"{{""message"": ""{validationErrors.Count} validation error(s) detected: {string.Join(",", validationErrors)}""}}",
Headers = new Dictionary<string, string>
{
{"Content-Type", "application/json"},
{"x-amzn-ErrorType", "ValidationException"}
},
StatusCode = 400
};
return errorResult;
}

await customAuthorizerRestExample.RestAuthorizer(authorizerValue, __context__);

return new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse
{
StatusCode = 200
};
}

private static void SetExecutionEnvironment()
{
const string envName = "AWS_EXECUTION_ENV";

var envValue = new StringBuilder();

// If there is an existing execution environment variable add the annotations package as a suffix.
if(!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName)))
{
envValue.Append($"{Environment.GetEnvironmentVariable(envName)}_");
}

envValue.Append("amazon-lambda-annotations_1.0.0.0");

Environment.SetEnvironmentVariable(envName, envValue.ToString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.0.0.0).",
"Resources": {
"HttpApiAuthorizerTest": {
"Type": "AWS::Serverless::Function",
"Metadata": {
"Tool": "Amazon.Lambda.Annotations",
"SyncedEvents": [
"RootGet"
]
},
"Properties": {
"MemorySize": 256,
"Timeout": 30,
"Policies": [
"AWSLambdaBasicExecutionRole"
],
"PackageType": "Image",
"ImageUri": ".",
"ImageConfig": {
"Command": [
"TestProject::TestServerlessApp.CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated::HttpApiAuthorizer"
]
},
"Events": {
"RootGet": {
"Type": "HttpApi",
"Properties": {
"Path": "/api/authorizer",
"Method": "GET"
}
}
}
}
}
}
}
Loading