diff --git a/Libraries/Amazon.Lambda.Annotations.slnf b/Libraries/Amazon.Lambda.Annotations.slnf index 377a01b7e..ecb4e01ee 100644 --- a/Libraries/Amazon.Lambda.Annotations.slnf +++ b/Libraries/Amazon.Lambda.Annotations.slnf @@ -11,9 +11,12 @@ "src\\Amazon.Lambda.Serialization.SystemTextJson\\Amazon.Lambda.Serialization.SystemTextJson.csproj", "test\\Amazon.Lambda.Annotations.SourceGenerators.Tests\\Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj", "test\\TestExecutableServerlessApp\\TestExecutableServerlessApp.csproj", + "test\\IntegrationTests.Helpers\\IntegrationTests.Helpers.csproj", + "test\\TestCustomAuthorizerApp\\TestCustomAuthorizerApp.csproj", + "test\\TestCustomAuthorizerApp.IntegrationTests\\TestCustomAuthorizerApp.IntegrationTests.csproj", "test\\TestServerlessApp.IntegrationTests\\TestServerlessApp.IntegrationTests.csproj", "test\\TestServerlessApp.NET8\\TestServerlessApp.NET8.csproj", "test\\TestServerlessApp\\TestServerlessApp.csproj" ] } -} \ No newline at end of file +} diff --git a/Libraries/Libraries.sln b/Libraries/Libraries.sln index 03e0b7c79..f3214606a 100644 --- a/Libraries/Libraries.sln +++ b/Libraries/Libraries.sln @@ -145,260 +145,802 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.DynamoDBEvent EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.Lambda.AspNetCoreServer.Hosting.Tests", "test\Amazon.Lambda.AspNetCoreServer.Hosting.Tests\Amazon.Lambda.AspNetCoreServer.Hosting.Tests.csproj", "{D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests.Helpers", "test\IntegrationTests.Helpers\IntegrationTests.Helpers.csproj", "{8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCustomAuthorizerApp.IntegrationTests", "test\TestCustomAuthorizerApp.IntegrationTests\TestCustomAuthorizerApp.IntegrationTests.csproj", "{8EEDD576-7FC4-4FAC-A5A2-F58562753A53}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCustomAuthorizerApp", "test\TestCustomAuthorizerApp\TestCustomAuthorizerApp.csproj", "{3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Debug|x64.ActiveCfg = Debug|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Debug|x64.Build.0 = Debug|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Debug|x86.ActiveCfg = Debug|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Debug|x86.Build.0 = Debug|Any CPU {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Release|Any CPU.ActiveCfg = Release|Any CPU {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Release|Any CPU.Build.0 = Release|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Release|x64.ActiveCfg = Release|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Release|x64.Build.0 = Release|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Release|x86.ActiveCfg = Release|Any CPU + {51F5E824-CAE2-4EF4-9131-13256BFD28B6}.Release|x86.Build.0 = Release|Any CPU {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Debug|x64.ActiveCfg = Debug|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Debug|x64.Build.0 = Debug|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Debug|x86.ActiveCfg = Debug|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Debug|x86.Build.0 = Debug|Any CPU {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Release|Any CPU.ActiveCfg = Release|Any CPU {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Release|Any CPU.Build.0 = Release|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Release|x64.ActiveCfg = Release|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Release|x64.Build.0 = Release|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Release|x86.ActiveCfg = Release|Any CPU + {201AC4EB-48D8-4E4A-A336-BB16DD630A19}.Release|x86.Build.0 = Release|Any CPU {C148726C-9555-4347-89B4-B9A514EBB02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C148726C-9555-4347-89B4-B9A514EBB02C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Debug|x64.ActiveCfg = Debug|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Debug|x64.Build.0 = Debug|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Debug|x86.ActiveCfg = Debug|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Debug|x86.Build.0 = Debug|Any CPU {C148726C-9555-4347-89B4-B9A514EBB02C}.Release|Any CPU.ActiveCfg = Release|Any CPU {C148726C-9555-4347-89B4-B9A514EBB02C}.Release|Any CPU.Build.0 = Release|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Release|x64.ActiveCfg = Release|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Release|x64.Build.0 = Release|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Release|x86.ActiveCfg = Release|Any CPU + {C148726C-9555-4347-89B4-B9A514EBB02C}.Release|x86.Build.0 = Release|Any CPU {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Debug|x64.ActiveCfg = Debug|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Debug|x64.Build.0 = Debug|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Debug|x86.ActiveCfg = Debug|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Debug|x86.Build.0 = Debug|Any CPU {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Release|Any CPU.ActiveCfg = Release|Any CPU {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Release|Any CPU.Build.0 = Release|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Release|x64.ActiveCfg = Release|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Release|x64.Build.0 = Release|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Release|x86.ActiveCfg = Release|Any CPU + {13A0F4C9-69EC-4B8E-A00F-7BAE23CC16E7}.Release|x86.Build.0 = Release|Any CPU {25813AAC-F0B3-4591-AA99-67983394623B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25813AAC-F0B3-4591-AA99-67983394623B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Debug|x64.ActiveCfg = Debug|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Debug|x64.Build.0 = Debug|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Debug|x86.ActiveCfg = Debug|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Debug|x86.Build.0 = Debug|Any CPU {25813AAC-F0B3-4591-AA99-67983394623B}.Release|Any CPU.ActiveCfg = Release|Any CPU {25813AAC-F0B3-4591-AA99-67983394623B}.Release|Any CPU.Build.0 = Release|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Release|x64.ActiveCfg = Release|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Release|x64.Build.0 = Release|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Release|x86.ActiveCfg = Release|Any CPU + {25813AAC-F0B3-4591-AA99-67983394623B}.Release|x86.Build.0 = Release|Any CPU {480D89E0-4334-4903-82CD-1B8ADF09D019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {480D89E0-4334-4903-82CD-1B8ADF09D019}.Debug|Any CPU.Build.0 = Debug|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Debug|x64.ActiveCfg = Debug|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Debug|x64.Build.0 = Debug|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Debug|x86.ActiveCfg = Debug|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Debug|x86.Build.0 = Debug|Any CPU {480D89E0-4334-4903-82CD-1B8ADF09D019}.Release|Any CPU.ActiveCfg = Release|Any CPU {480D89E0-4334-4903-82CD-1B8ADF09D019}.Release|Any CPU.Build.0 = Release|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Release|x64.ActiveCfg = Release|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Release|x64.Build.0 = Release|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Release|x86.ActiveCfg = Release|Any CPU + {480D89E0-4334-4903-82CD-1B8ADF09D019}.Release|x86.Build.0 = Release|Any CPU {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Debug|x64.ActiveCfg = Debug|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Debug|x64.Build.0 = Debug|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Debug|x86.ActiveCfg = Debug|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Debug|x86.Build.0 = Debug|Any CPU {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Release|Any CPU.ActiveCfg = Release|Any CPU {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Release|Any CPU.Build.0 = Release|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Release|x64.ActiveCfg = Release|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Release|x64.Build.0 = Release|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Release|x86.ActiveCfg = Release|Any CPU + {105B1BBB-4114-4D86-812E-EFFBB6E47CE5}.Release|x86.Build.0 = Release|Any CPU {690F1C8C-A702-472D-9B72-7280F41D4B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {690F1C8C-A702-472D-9B72-7280F41D4B47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Debug|x64.ActiveCfg = Debug|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Debug|x64.Build.0 = Debug|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Debug|x86.ActiveCfg = Debug|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Debug|x86.Build.0 = Debug|Any CPU {690F1C8C-A702-472D-9B72-7280F41D4B47}.Release|Any CPU.ActiveCfg = Release|Any CPU {690F1C8C-A702-472D-9B72-7280F41D4B47}.Release|Any CPU.Build.0 = Release|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Release|x64.ActiveCfg = Release|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Release|x64.Build.0 = Release|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Release|x86.ActiveCfg = Release|Any CPU + {690F1C8C-A702-472D-9B72-7280F41D4B47}.Release|x86.Build.0 = Release|Any CPU {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Debug|x64.ActiveCfg = Debug|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Debug|x64.Build.0 = Debug|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Debug|x86.ActiveCfg = Debug|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Debug|x86.Build.0 = Debug|Any CPU {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Release|Any CPU.Build.0 = Release|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Release|x64.ActiveCfg = Release|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Release|x64.Build.0 = Release|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Release|x86.ActiveCfg = Release|Any CPU + {6BF4EC9F-FB9E-4898-81F7-B392BF83D2B0}.Release|x86.Build.0 = Release|Any CPU {CB170908-F770-4554-A974-9653562F1042}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB170908-F770-4554-A974-9653562F1042}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Debug|x64.Build.0 = Debug|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Debug|x86.ActiveCfg = Debug|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Debug|x86.Build.0 = Debug|Any CPU {CB170908-F770-4554-A974-9653562F1042}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB170908-F770-4554-A974-9653562F1042}.Release|Any CPU.Build.0 = Release|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Release|x64.ActiveCfg = Release|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Release|x64.Build.0 = Release|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Release|x86.ActiveCfg = Release|Any CPU + {CB170908-F770-4554-A974-9653562F1042}.Release|x86.Build.0 = Release|Any CPU {3ED92849-4103-4AEF-B406-FF856C134C4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3ED92849-4103-4AEF-B406-FF856C134C4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Debug|x64.ActiveCfg = Debug|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Debug|x64.Build.0 = Debug|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Debug|x86.ActiveCfg = Debug|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Debug|x86.Build.0 = Debug|Any CPU {3ED92849-4103-4AEF-B406-FF856C134C4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {3ED92849-4103-4AEF-B406-FF856C134C4B}.Release|Any CPU.Build.0 = Release|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Release|x64.ActiveCfg = Release|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Release|x64.Build.0 = Release|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Release|x86.ActiveCfg = Release|Any CPU + {3ED92849-4103-4AEF-B406-FF856C134C4B}.Release|x86.Build.0 = Release|Any CPU {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Debug|x64.Build.0 = Debug|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Debug|x86.Build.0 = Debug|Any CPU {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Release|Any CPU.Build.0 = Release|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Release|x64.ActiveCfg = Release|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Release|x64.Build.0 = Release|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Release|x86.ActiveCfg = Release|Any CPU + {D4B8939E-9684-4237-861C-2288EB5DD4E8}.Release|x86.Build.0 = Release|Any CPU {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Debug|x64.ActiveCfg = Debug|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Debug|x64.Build.0 = Debug|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Debug|x86.ActiveCfg = Debug|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Debug|x86.Build.0 = Debug|Any CPU {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Release|Any CPU.ActiveCfg = Release|Any CPU {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Release|Any CPU.Build.0 = Release|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Release|x64.ActiveCfg = Release|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Release|x64.Build.0 = Release|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Release|x86.ActiveCfg = Release|Any CPU + {D05BF033-DA2C-463C-BB98-64D28E1A4A75}.Release|x86.Build.0 = Release|Any CPU {0083B713-6399-479D-AA06-58D3E87F167D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0083B713-6399-479D-AA06-58D3E87F167D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Debug|x64.ActiveCfg = Debug|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Debug|x64.Build.0 = Debug|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Debug|x86.ActiveCfg = Debug|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Debug|x86.Build.0 = Debug|Any CPU {0083B713-6399-479D-AA06-58D3E87F167D}.Release|Any CPU.ActiveCfg = Release|Any CPU {0083B713-6399-479D-AA06-58D3E87F167D}.Release|Any CPU.Build.0 = Release|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Release|x64.ActiveCfg = Release|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Release|x64.Build.0 = Release|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Release|x86.ActiveCfg = Release|Any CPU + {0083B713-6399-479D-AA06-58D3E87F167D}.Release|x86.Build.0 = Release|Any CPU {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Debug|x64.ActiveCfg = Debug|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Debug|x64.Build.0 = Debug|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Debug|x86.Build.0 = Debug|Any CPU {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Release|Any CPU.ActiveCfg = Release|Any CPU {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Release|Any CPU.Build.0 = Release|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Release|x64.ActiveCfg = Release|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Release|x64.Build.0 = Release|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Release|x86.ActiveCfg = Release|Any CPU + {5B48AEA8-5702-45A8-9D89-CEB986E6DBC1}.Release|x86.Build.0 = Release|Any CPU {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Debug|x64.ActiveCfg = Debug|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Debug|x64.Build.0 = Debug|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Debug|x86.ActiveCfg = Debug|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Debug|x86.Build.0 = Debug|Any CPU {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Release|Any CPU.ActiveCfg = Release|Any CPU {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Release|Any CPU.Build.0 = Release|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Release|x64.ActiveCfg = Release|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Release|x64.Build.0 = Release|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Release|x86.ActiveCfg = Release|Any CPU + {101ABE51-390D-41DF-A70B-2BD3B08B2CC7}.Release|x86.Build.0 = Release|Any CPU {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Debug|x64.ActiveCfg = Debug|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Debug|x64.Build.0 = Debug|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Debug|x86.ActiveCfg = Debug|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Debug|x86.Build.0 = Debug|Any CPU {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Release|Any CPU.ActiveCfg = Release|Any CPU {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Release|Any CPU.Build.0 = Release|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Release|x64.ActiveCfg = Release|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Release|x64.Build.0 = Release|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Release|x86.ActiveCfg = Release|Any CPU + {A612EC01-6595-4EA6-B0EF-FF00E4FB331D}.Release|x86.Build.0 = Release|Any CPU {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Debug|x64.ActiveCfg = Debug|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Debug|x64.Build.0 = Debug|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Debug|x86.ActiveCfg = Debug|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Debug|x86.Build.0 = Debug|Any CPU {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Release|Any CPU.ActiveCfg = Release|Any CPU {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Release|Any CPU.Build.0 = Release|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Release|x64.ActiveCfg = Release|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Release|x64.Build.0 = Release|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Release|x86.ActiveCfg = Release|Any CPU + {11A53C8D-A49B-4477-BFD9-E00C77D1291C}.Release|x86.Build.0 = Release|Any CPU {A6348510-7948-46B1-A2C4-396B8C55440C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A6348510-7948-46B1-A2C4-396B8C55440C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Debug|x64.ActiveCfg = Debug|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Debug|x64.Build.0 = Debug|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Debug|x86.ActiveCfg = Debug|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Debug|x86.Build.0 = Debug|Any CPU {A6348510-7948-46B1-A2C4-396B8C55440C}.Release|Any CPU.ActiveCfg = Release|Any CPU {A6348510-7948-46B1-A2C4-396B8C55440C}.Release|Any CPU.Build.0 = Release|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Release|x64.ActiveCfg = Release|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Release|x64.Build.0 = Release|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Release|x86.ActiveCfg = Release|Any CPU + {A6348510-7948-46B1-A2C4-396B8C55440C}.Release|x86.Build.0 = Release|Any CPU {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Debug|x64.ActiveCfg = Debug|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Debug|x64.Build.0 = Debug|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Debug|x86.ActiveCfg = Debug|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Debug|x86.Build.0 = Debug|Any CPU {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Release|Any CPU.Build.0 = Release|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Release|x64.ActiveCfg = Release|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Release|x64.Build.0 = Release|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Release|x86.ActiveCfg = Release|Any CPU + {F93EFEFF-FD1F-48F1-A0F1-BBE87205129E}.Release|x86.Build.0 = Release|Any CPU {E104E093-3562-4F07-B138-821A428DE267}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E104E093-3562-4F07-B138-821A428DE267}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Debug|x64.ActiveCfg = Debug|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Debug|x64.Build.0 = Debug|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Debug|x86.ActiveCfg = Debug|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Debug|x86.Build.0 = Debug|Any CPU {E104E093-3562-4F07-B138-821A428DE267}.Release|Any CPU.ActiveCfg = Release|Any CPU {E104E093-3562-4F07-B138-821A428DE267}.Release|Any CPU.Build.0 = Release|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Release|x64.ActiveCfg = Release|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Release|x64.Build.0 = Release|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Release|x86.ActiveCfg = Release|Any CPU + {E104E093-3562-4F07-B138-821A428DE267}.Release|x86.Build.0 = Release|Any CPU {32827626-2128-49A0-A2A9-2F5076AADDAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {32827626-2128-49A0-A2A9-2F5076AADDAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Debug|x64.ActiveCfg = Debug|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Debug|x64.Build.0 = Debug|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Debug|x86.ActiveCfg = Debug|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Debug|x86.Build.0 = Debug|Any CPU {32827626-2128-49A0-A2A9-2F5076AADDAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {32827626-2128-49A0-A2A9-2F5076AADDAD}.Release|Any CPU.Build.0 = Release|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Release|x64.ActiveCfg = Release|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Release|x64.Build.0 = Release|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Release|x86.ActiveCfg = Release|Any CPU + {32827626-2128-49A0-A2A9-2F5076AADDAD}.Release|x86.Build.0 = Release|Any CPU {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Debug|x64.ActiveCfg = Debug|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Debug|x64.Build.0 = Debug|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Debug|x86.ActiveCfg = Debug|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Debug|x86.Build.0 = Debug|Any CPU {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Release|Any CPU.ActiveCfg = Release|Any CPU {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Release|Any CPU.Build.0 = Release|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Release|x64.ActiveCfg = Release|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Release|x64.Build.0 = Release|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Release|x86.ActiveCfg = Release|Any CPU + {EAC0F95B-B43A-49EB-A6DF-D0353DAD4593}.Release|x86.Build.0 = Release|Any CPU {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Debug|x64.ActiveCfg = Debug|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Debug|x64.Build.0 = Debug|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Debug|x86.ActiveCfg = Debug|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Debug|x86.Build.0 = Debug|Any CPU {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Release|Any CPU.Build.0 = Release|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Release|x64.ActiveCfg = Release|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Release|x64.Build.0 = Release|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Release|x86.ActiveCfg = Release|Any CPU + {8C9EA16D-6055-421B-ABE7-1B0E35259DFC}.Release|x86.Build.0 = Release|Any CPU {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Debug|x64.Build.0 = Debug|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Debug|x86.ActiveCfg = Debug|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Debug|x86.Build.0 = Debug|Any CPU {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Release|Any CPU.Build.0 = Release|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Release|x64.ActiveCfg = Release|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Release|x64.Build.0 = Release|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Release|x86.ActiveCfg = Release|Any CPU + {CB38FA21-5814-4573-94C7-3672D61BC8B8}.Release|x86.Build.0 = Release|Any CPU {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Debug|x64.ActiveCfg = Debug|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Debug|x64.Build.0 = Debug|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Debug|x86.ActiveCfg = Debug|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Debug|x86.Build.0 = Debug|Any CPU {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Release|Any CPU.Build.0 = Release|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Release|x64.ActiveCfg = Release|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Release|x64.Build.0 = Release|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Release|x86.ActiveCfg = Release|Any CPU + {2810A66B-3A03-4889-A4D0-0E8838474A4A}.Release|x86.Build.0 = Release|Any CPU {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Debug|x64.ActiveCfg = Debug|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Debug|x64.Build.0 = Debug|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Debug|x86.ActiveCfg = Debug|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Debug|x86.Build.0 = Debug|Any CPU {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Release|Any CPU.Build.0 = Release|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Release|x64.ActiveCfg = Release|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Release|x64.Build.0 = Release|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Release|x86.ActiveCfg = Release|Any CPU + {74BFF877-D276-43BF-AC3A-E65BF26E4E2F}.Release|x86.Build.0 = Release|Any CPU {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Debug|x64.ActiveCfg = Debug|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Debug|x64.Build.0 = Debug|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Debug|x86.ActiveCfg = Debug|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Debug|x86.Build.0 = Debug|Any CPU {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Release|Any CPU.ActiveCfg = Release|Any CPU {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Release|Any CPU.Build.0 = Release|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Release|x64.ActiveCfg = Release|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Release|x64.Build.0 = Release|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Release|x86.ActiveCfg = Release|Any CPU + {51CAD9E3-B5AE-4787-915E-7FA096CF783F}.Release|x86.Build.0 = Release|Any CPU {997B1047-4361-4E6D-9850-F130EC188141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {997B1047-4361-4E6D-9850-F130EC188141}.Debug|Any CPU.Build.0 = Debug|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Debug|x64.ActiveCfg = Debug|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Debug|x64.Build.0 = Debug|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Debug|x86.ActiveCfg = Debug|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Debug|x86.Build.0 = Debug|Any CPU {997B1047-4361-4E6D-9850-F130EC188141}.Release|Any CPU.ActiveCfg = Release|Any CPU {997B1047-4361-4E6D-9850-F130EC188141}.Release|Any CPU.Build.0 = Release|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Release|x64.ActiveCfg = Release|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Release|x64.Build.0 = Release|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Release|x86.ActiveCfg = Release|Any CPU + {997B1047-4361-4E6D-9850-F130EC188141}.Release|x86.Build.0 = Release|Any CPU {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|x64.ActiveCfg = Debug|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|x64.Build.0 = Debug|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|x86.ActiveCfg = Debug|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|x86.Build.0 = Debug|Any CPU {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|Any CPU.Build.0 = Release|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|x64.ActiveCfg = Release|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|x64.Build.0 = Release|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|x86.ActiveCfg = Release|Any CPU + {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|x86.Build.0 = Release|Any CPU {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|x64.ActiveCfg = Debug|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|x64.Build.0 = Debug|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|x86.Build.0 = Debug|Any CPU {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|Any CPU.Build.0 = Release|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|x64.ActiveCfg = Release|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|x64.Build.0 = Release|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|x86.ActiveCfg = Release|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|x86.Build.0 = Release|Any CPU {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Debug|x64.ActiveCfg = Debug|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Debug|x64.Build.0 = Debug|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Debug|x86.ActiveCfg = Debug|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Debug|x86.Build.0 = Debug|Any CPU {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Release|Any CPU.Build.0 = Release|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Release|x64.ActiveCfg = Release|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Release|x64.Build.0 = Release|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Release|x86.ActiveCfg = Release|Any CPU + {0E743512-2FE4-40AD-935A-17B40ACF82C1}.Release|x86.Build.0 = Release|Any CPU {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Debug|x64.ActiveCfg = Debug|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Debug|x64.Build.0 = Debug|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Debug|x86.ActiveCfg = Debug|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Debug|x86.Build.0 = Debug|Any CPU {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Release|Any CPU.Build.0 = Release|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Release|x64.ActiveCfg = Release|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Release|x64.Build.0 = Release|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Release|x86.ActiveCfg = Release|Any CPU + {0046EAB1-FA73-4D7A-A7CD-936E943F775E}.Release|x86.Build.0 = Release|Any CPU {61934DD2-CFBB-48E1-947C-75E8F736734C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {61934DD2-CFBB-48E1-947C-75E8F736734C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Debug|x64.ActiveCfg = Debug|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Debug|x64.Build.0 = Debug|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Debug|x86.ActiveCfg = Debug|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Debug|x86.Build.0 = Debug|Any CPU {61934DD2-CFBB-48E1-947C-75E8F736734C}.Release|Any CPU.ActiveCfg = Release|Any CPU {61934DD2-CFBB-48E1-947C-75E8F736734C}.Release|Any CPU.Build.0 = Release|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Release|x64.ActiveCfg = Release|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Release|x64.Build.0 = Release|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Release|x86.ActiveCfg = Release|Any CPU + {61934DD2-CFBB-48E1-947C-75E8F736734C}.Release|x86.Build.0 = Release|Any CPU {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Debug|x64.ActiveCfg = Debug|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Debug|x64.Build.0 = Debug|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Debug|x86.ActiveCfg = Debug|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Debug|x86.Build.0 = Debug|Any CPU {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Release|Any CPU.ActiveCfg = Release|Any CPU {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Release|Any CPU.Build.0 = Release|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Release|x64.ActiveCfg = Release|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Release|x64.Build.0 = Release|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Release|x86.ActiveCfg = Release|Any CPU + {39FD7632-73D0-4BB3-AE99-DC7B8B251E29}.Release|x86.Build.0 = Release|Any CPU {10E47FE4-8620-4933-A14D-E33F25CA557A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {10E47FE4-8620-4933-A14D-E33F25CA557A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Debug|x64.ActiveCfg = Debug|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Debug|x64.Build.0 = Debug|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Debug|x86.ActiveCfg = Debug|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Debug|x86.Build.0 = Debug|Any CPU {10E47FE4-8620-4933-A14D-E33F25CA557A}.Release|Any CPU.ActiveCfg = Release|Any CPU {10E47FE4-8620-4933-A14D-E33F25CA557A}.Release|Any CPU.Build.0 = Release|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Release|x64.ActiveCfg = Release|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Release|x64.Build.0 = Release|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Release|x86.ActiveCfg = Release|Any CPU + {10E47FE4-8620-4933-A14D-E33F25CA557A}.Release|x86.Build.0 = Release|Any CPU {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Debug|x64.ActiveCfg = Debug|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Debug|x64.Build.0 = Debug|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Debug|x86.ActiveCfg = Debug|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Debug|x86.Build.0 = Debug|Any CPU {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Release|Any CPU.Build.0 = Release|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Release|x64.ActiveCfg = Release|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Release|x64.Build.0 = Release|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Release|x86.ActiveCfg = Release|Any CPU + {AA6BA0B8-D61E-49E7-BC1B-19410E25F005}.Release|x86.Build.0 = Release|Any CPU {44E9D925-B61D-4234-97B7-61424C963BA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {44E9D925-B61D-4234-97B7-61424C963BA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Debug|x64.ActiveCfg = Debug|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Debug|x64.Build.0 = Debug|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Debug|x86.ActiveCfg = Debug|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Debug|x86.Build.0 = Debug|Any CPU {44E9D925-B61D-4234-97B7-61424C963BA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {44E9D925-B61D-4234-97B7-61424C963BA6}.Release|Any CPU.Build.0 = Release|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Release|x64.ActiveCfg = Release|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Release|x64.Build.0 = Release|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Release|x86.ActiveCfg = Release|Any CPU + {44E9D925-B61D-4234-97B7-61424C963BA6}.Release|x86.Build.0 = Release|Any CPU {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Debug|x64.Build.0 = Debug|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Debug|x86.ActiveCfg = Debug|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Debug|x86.Build.0 = Debug|Any CPU {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Release|Any CPU.Build.0 = Release|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Release|x64.ActiveCfg = Release|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Release|x64.Build.0 = Release|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Release|x86.ActiveCfg = Release|Any CPU + {E88231E0-B249-49AE-B764-DB6C9615F6CA}.Release|x86.Build.0 = Release|Any CPU {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Debug|x64.ActiveCfg = Debug|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Debug|x64.Build.0 = Debug|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Debug|x86.ActiveCfg = Debug|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Debug|x86.Build.0 = Debug|Any CPU {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Release|Any CPU.ActiveCfg = Release|Any CPU {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Release|Any CPU.Build.0 = Release|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Release|x64.ActiveCfg = Release|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Release|x64.Build.0 = Release|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Release|x86.ActiveCfg = Release|Any CPU + {9736E38B-B67F-42BD-882E-CE9C8AEE1BC4}.Release|x86.Build.0 = Release|Any CPU {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Debug|x64.Build.0 = Debug|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Debug|x86.Build.0 = Debug|Any CPU {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Release|Any CPU.Build.0 = Release|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Release|x64.ActiveCfg = Release|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Release|x64.Build.0 = Release|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Release|x86.ActiveCfg = Release|Any CPU + {3D322CAB-0DDD-4C84-B3ED-0862F244AF5C}.Release|x86.Build.0 = Release|Any CPU {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Debug|x64.ActiveCfg = Debug|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Debug|x64.Build.0 = Debug|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Debug|x86.ActiveCfg = Debug|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Debug|x86.Build.0 = Debug|Any CPU {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Release|Any CPU.ActiveCfg = Release|Any CPU {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Release|Any CPU.Build.0 = Release|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Release|x64.ActiveCfg = Release|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Release|x64.Build.0 = Release|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Release|x86.ActiveCfg = Release|Any CPU + {D76F2C74-3D7F-4DB3-BA1A-F2EA14749253}.Release|x86.Build.0 = Release|Any CPU {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Debug|x64.ActiveCfg = Debug|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Debug|x64.Build.0 = Debug|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Debug|x86.ActiveCfg = Debug|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Debug|x86.Build.0 = Debug|Any CPU {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Release|Any CPU.Build.0 = Release|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Release|x64.ActiveCfg = Release|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Release|x64.Build.0 = Release|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Release|x86.ActiveCfg = Release|Any CPU + {ADA9AF37-A8C1-47E6-BBBD-5C7E49C26C0E}.Release|x86.Build.0 = Release|Any CPU {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Debug|x64.Build.0 = Debug|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Debug|x86.Build.0 = Debug|Any CPU {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Release|Any CPU.Build.0 = Release|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Release|x64.ActiveCfg = Release|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Release|x64.Build.0 = Release|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Release|x86.ActiveCfg = Release|Any CPU + {3C617909-D61F-4AA8-B11C-4C9ECC865D75}.Release|x86.Build.0 = Release|Any CPU {2D956162-04BE-402E-9487-AE785AA14DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2D956162-04BE-402E-9487-AE785AA14DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Debug|x64.ActiveCfg = Debug|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Debug|x64.Build.0 = Debug|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Debug|x86.ActiveCfg = Debug|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Debug|x86.Build.0 = Debug|Any CPU {2D956162-04BE-402E-9487-AE785AA14DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU {2D956162-04BE-402E-9487-AE785AA14DE4}.Release|Any CPU.Build.0 = Release|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Release|x64.ActiveCfg = Release|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Release|x64.Build.0 = Release|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Release|x86.ActiveCfg = Release|Any CPU + {2D956162-04BE-402E-9487-AE785AA14DE4}.Release|x86.Build.0 = Release|Any CPU {02908C6F-FBDF-4949-B039-0F4632265B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {02908C6F-FBDF-4949-B039-0F4632265B90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Debug|x64.ActiveCfg = Debug|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Debug|x64.Build.0 = Debug|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Debug|x86.ActiveCfg = Debug|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Debug|x86.Build.0 = Debug|Any CPU {02908C6F-FBDF-4949-B039-0F4632265B90}.Release|Any CPU.ActiveCfg = Release|Any CPU {02908C6F-FBDF-4949-B039-0F4632265B90}.Release|Any CPU.Build.0 = Release|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Release|x64.ActiveCfg = Release|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Release|x64.Build.0 = Release|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Release|x86.ActiveCfg = Release|Any CPU + {02908C6F-FBDF-4949-B039-0F4632265B90}.Release|x86.Build.0 = Release|Any CPU {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Debug|x64.ActiveCfg = Debug|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Debug|x64.Build.0 = Debug|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Debug|x86.ActiveCfg = Debug|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Debug|x86.Build.0 = Debug|Any CPU {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Release|Any CPU.Build.0 = Release|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Release|x64.ActiveCfg = Release|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Release|x64.Build.0 = Release|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Release|x86.ActiveCfg = Release|Any CPU + {2FFBE745-B7D5-4E44-B76D-88A0C2402FEB}.Release|x86.Build.0 = Release|Any CPU {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Debug|x64.ActiveCfg = Debug|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Debug|x64.Build.0 = Debug|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Debug|x86.Build.0 = Debug|Any CPU {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Release|Any CPU.Build.0 = Release|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Release|x64.ActiveCfg = Release|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Release|x64.Build.0 = Release|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Release|x86.ActiveCfg = Release|Any CPU + {C1BB30D2-3237-4CFC-BA93-627471148EC2}.Release|x86.Build.0 = Release|Any CPU {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Debug|x64.ActiveCfg = Debug|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Debug|x64.Build.0 = Debug|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Debug|x86.ActiveCfg = Debug|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Debug|x86.Build.0 = Debug|Any CPU {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Release|Any CPU.ActiveCfg = Release|Any CPU {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Release|Any CPU.Build.0 = Release|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Release|x64.ActiveCfg = Release|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Release|x64.Build.0 = Release|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Release|x86.ActiveCfg = Release|Any CPU + {982A26C7-A5D1-4783-A7F8-F2B28AA2459E}.Release|x86.Build.0 = Release|Any CPU {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Debug|x64.ActiveCfg = Debug|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Debug|x64.Build.0 = Debug|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Debug|x86.ActiveCfg = Debug|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Debug|x86.Build.0 = Debug|Any CPU {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Release|Any CPU.ActiveCfg = Release|Any CPU {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Release|Any CPU.Build.0 = Release|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Release|x64.ActiveCfg = Release|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Release|x64.Build.0 = Release|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Release|x86.ActiveCfg = Release|Any CPU + {8AB1CBD7-2D08-492F-9C09-3E754364046C}.Release|x86.Build.0 = Release|Any CPU {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Debug|x64.ActiveCfg = Debug|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Debug|x64.Build.0 = Debug|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Debug|x86.ActiveCfg = Debug|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Debug|x86.Build.0 = Debug|Any CPU {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Release|Any CPU.ActiveCfg = Release|Any CPU {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Release|Any CPU.Build.0 = Release|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Release|x64.ActiveCfg = Release|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Release|x64.Build.0 = Release|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Release|x86.ActiveCfg = Release|Any CPU + {BF85932E-2DFF-41CD-8090-A672468B8FBB}.Release|x86.Build.0 = Release|Any CPU {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Debug|x64.Build.0 = Debug|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Debug|x86.Build.0 = Debug|Any CPU {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Release|Any CPU.Build.0 = Release|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Release|x64.ActiveCfg = Release|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Release|x64.Build.0 = Release|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Release|x86.ActiveCfg = Release|Any CPU + {3C6AABF5-0372-41E0-874F-DF18ECCC7FB6}.Release|x86.Build.0 = Release|Any CPU {0BD83939-458C-4EF5-8663-7098AD1200F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0BD83939-458C-4EF5-8663-7098AD1200F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Debug|x64.ActiveCfg = Debug|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Debug|x64.Build.0 = Debug|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Debug|x86.ActiveCfg = Debug|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Debug|x86.Build.0 = Debug|Any CPU {0BD83939-458C-4EF5-8663-7098AD1200F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {0BD83939-458C-4EF5-8663-7098AD1200F2}.Release|Any CPU.Build.0 = Release|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Release|x64.ActiveCfg = Release|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Release|x64.Build.0 = Release|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Release|x86.ActiveCfg = Release|Any CPU + {0BD83939-458C-4EF5-8663-7098AD1200F2}.Release|x86.Build.0 = Release|Any CPU {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Debug|x64.ActiveCfg = Debug|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Debug|x64.Build.0 = Debug|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Debug|x86.ActiveCfg = Debug|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Debug|x86.Build.0 = Debug|Any CPU {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Release|Any CPU.Build.0 = Release|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Release|x64.ActiveCfg = Release|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Release|x64.Build.0 = Release|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Release|x86.ActiveCfg = Release|Any CPU + {DD378063-C54A-44C7-9A6F-32A6A1AE94B3}.Release|x86.Build.0 = Release|Any CPU {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Debug|x64.ActiveCfg = Debug|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Debug|x64.Build.0 = Debug|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Debug|x86.ActiveCfg = Debug|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Debug|x86.Build.0 = Debug|Any CPU {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Release|Any CPU.Build.0 = Release|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Release|x64.ActiveCfg = Release|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Release|x64.Build.0 = Release|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Release|x86.ActiveCfg = Release|Any CPU + {7300983D-8FCE-42EA-9B9E-B1C5347D15D8}.Release|x86.Build.0 = Release|Any CPU {7261A438-8C1D-47AD-98B0-7678F72E4382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7261A438-8C1D-47AD-98B0-7678F72E4382}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Debug|x64.ActiveCfg = Debug|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Debug|x64.Build.0 = Debug|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Debug|x86.ActiveCfg = Debug|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Debug|x86.Build.0 = Debug|Any CPU {7261A438-8C1D-47AD-98B0-7678F72E4382}.Release|Any CPU.ActiveCfg = Release|Any CPU {7261A438-8C1D-47AD-98B0-7678F72E4382}.Release|Any CPU.Build.0 = Release|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Release|x64.ActiveCfg = Release|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Release|x64.Build.0 = Release|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Release|x86.ActiveCfg = Release|Any CPU + {7261A438-8C1D-47AD-98B0-7678F72E4382}.Release|x86.Build.0 = Release|Any CPU {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Debug|x64.ActiveCfg = Debug|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Debug|x64.Build.0 = Debug|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Debug|x86.ActiveCfg = Debug|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Debug|x86.Build.0 = Debug|Any CPU {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Release|Any CPU.ActiveCfg = Release|Any CPU {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Release|Any CPU.Build.0 = Release|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Release|x64.ActiveCfg = Release|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Release|x64.Build.0 = Release|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Release|x86.ActiveCfg = Release|Any CPU + {A699E183-D0D4-4F26-A0A7-88DA5607F455}.Release|x86.Build.0 = Release|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|x64.ActiveCfg = Debug|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|x64.Build.0 = Debug|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|x86.ActiveCfg = Debug|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|x86.Build.0 = Debug|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|Any CPU.Build.0 = Release|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|x64.ActiveCfg = Release|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|x64.Build.0 = Release|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|x86.ActiveCfg = Release|Any CPU + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|x86.Build.0 = Release|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|x64.ActiveCfg = Debug|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|x64.Build.0 = Debug|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|x86.ActiveCfg = Debug|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|x86.Build.0 = Debug|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|Any CPU.Build.0 = Release|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|x64.ActiveCfg = Release|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|x64.Build.0 = Release|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|x86.ActiveCfg = Release|Any CPU + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|x86.Build.0 = Release|Any CPU {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Debug|x64.ActiveCfg = Debug|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Debug|x64.Build.0 = Debug|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Debug|x86.ActiveCfg = Debug|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Debug|x86.Build.0 = Debug|Any CPU {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Release|Any CPU.ActiveCfg = Release|Any CPU {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Release|Any CPU.Build.0 = Release|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Release|x64.ActiveCfg = Release|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Release|x64.Build.0 = Release|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Release|x86.ActiveCfg = Release|Any CPU + {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC}.Release|x86.Build.0 = Release|Any CPU {074DB940-82BA-47D4-B888-C213D4220A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {074DB940-82BA-47D4-B888-C213D4220A82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Debug|x64.ActiveCfg = Debug|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Debug|x64.Build.0 = Debug|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Debug|x86.ActiveCfg = Debug|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Debug|x86.Build.0 = Debug|Any CPU {074DB940-82BA-47D4-B888-C213D4220A82}.Release|Any CPU.ActiveCfg = Release|Any CPU {074DB940-82BA-47D4-B888-C213D4220A82}.Release|Any CPU.Build.0 = Release|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Release|x64.ActiveCfg = Release|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Release|x64.Build.0 = Release|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Release|x86.ActiveCfg = Release|Any CPU + {074DB940-82BA-47D4-B888-C213D4220A82}.Release|x86.Build.0 = Release|Any CPU {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Debug|x64.ActiveCfg = Debug|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Debug|x64.Build.0 = Debug|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Debug|x86.ActiveCfg = Debug|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Debug|x86.Build.0 = Debug|Any CPU {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Release|Any CPU.ActiveCfg = Release|Any CPU {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Release|Any CPU.Build.0 = Release|Any CPU - {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198}.Release|Any CPU.Build.0 = Release|Any CPU - {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9}.Release|Any CPU.Build.0 = Release|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Release|x64.ActiveCfg = Release|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Release|x64.Build.0 = Release|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Release|x86.ActiveCfg = Release|Any CPU + {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526}.Release|x86.Build.0 = Release|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Debug|x64.ActiveCfg = Debug|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Debug|x64.Build.0 = Debug|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Debug|x86.ActiveCfg = Debug|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Debug|x86.Build.0 = Debug|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Release|Any CPU.Build.0 = Release|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Release|x64.ActiveCfg = Release|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Release|x64.Build.0 = Release|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Release|x86.ActiveCfg = Release|Any CPU + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D}.Release|x86.Build.0 = Release|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Debug|x64.ActiveCfg = Debug|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Debug|x64.Build.0 = Debug|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Debug|x86.ActiveCfg = Debug|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Debug|x86.Build.0 = Debug|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Release|Any CPU.Build.0 = Release|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Release|x64.ActiveCfg = Release|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Release|x64.Build.0 = Release|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Release|x86.ActiveCfg = Release|Any CPU + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53}.Release|x86.Build.0 = Release|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Debug|x64.ActiveCfg = Debug|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Debug|x64.Build.0 = Debug|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Debug|x86.ActiveCfg = Debug|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Debug|x86.Build.0 = Debug|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Release|Any CPU.Build.0 = Release|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Release|x64.ActiveCfg = Release|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Release|x64.Build.0 = Release|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Release|x86.ActiveCfg = Release|Any CPU + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -465,11 +1007,14 @@ Global {7300983D-8FCE-42EA-9B9E-B1C5347D15D8} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} {7261A438-8C1D-47AD-98B0-7678F72E4382} = {AAB54E74-20B1-42ED-BC3D-CE9F7BC7FD12} {A699E183-D0D4-4F26-A0A7-88DA5607F455} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} + {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198} = {AAB54E74-20B1-42ED-BC3D-CE9F7BC7FD12} + {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} {3400F4E9-BA12-4D3D-9BA1-2798AA8D0AFC} = {AAB54E74-20B1-42ED-BC3D-CE9F7BC7FD12} {074DB940-82BA-47D4-B888-C213D4220A82} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} {D61CBB71-17AB-4EC2-8C6A-70E9D7C60526} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} - {99F39E49-1FD0-4EF5-BF4B-8F2473FB8198} = {AAB54E74-20B1-42ED-BC3D-CE9F7BC7FD12} - {1FB22337-5D88-4CE7-ADFF-FFD89204F0E9} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} + {8D03BDF3-7078-4B46-A3F1-C73BE6D6CE0D} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} + {8EEDD576-7FC4-4FAC-A5A2-F58562753A53} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} + {3BFA4B73-BA61-4578-833B-C5B3A16EDA9E} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {503678A4-B8D1-4486-8915-405A3E9CF0EB} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/AttributeModelBuilder.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/AttributeModelBuilder.cs index fe18ca208..1a62078f3 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/AttributeModelBuilder.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/AttributeModelBuilder.cs @@ -54,6 +54,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 + { + 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); diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/FromCustomAuthorizerAttributeBuilder.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/FromCustomAuthorizerAttributeBuilder.cs new file mode 100644 index 000000000..d55e7836a --- /dev/null +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/Attributes/FromCustomAuthorizerAttributeBuilder.cs @@ -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; + } + } +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.cs index 754530b93..929441dfc 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version: 17.0.0.0 +// Runtime Version: 18.0.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -22,8 +22,8 @@ namespace Amazon.Lambda.Annotations.SourceGenerator.Templates /// Class to produce the template output /// - #line 1 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + #line 1 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")] public partial class APIGatewaySetupParameters : APIGatewaySetupParametersBase { #line hidden @@ -33,7 +33,7 @@ public partial class APIGatewaySetupParameters : APIGatewaySetupParametersBase public virtual string TransformText() { - #line 10 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 10 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" ParameterSignature = string.Join(", ", _model.LambdaMethod.Parameters .Select(p => @@ -77,7 +77,7 @@ public virtual string TransformText() #line hidden this.Write(" var validationErrors = new List();\r\n\r\n"); - #line 50 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 50 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } @@ -95,21 +95,21 @@ public virtual string TransformText() #line hidden this.Write(" var "); - #line 62 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 62 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = scope.ServiceProvider.GetRequiredService<"); - #line 62 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 62 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(">();\r\n"); - #line 63 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 63 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } else if (parameter.Attributes.Any(att => att.Type.FullName == TypeFullNames.FromQueryAttribute)) @@ -127,21 +127,21 @@ public virtual string TransformText() #line hidden this.Write(" var "); - #line 75 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 75 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = default("); - #line 75 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 75 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(");\r\n"); - #line 76 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 76 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" if (parameter.Type.IsEnumerable && parameter.Type.IsGenericType) @@ -175,42 +175,42 @@ public virtual string TransformText() #line hidden this.Write(" if (__request__."); - #line 104 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 104 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(queryStringParameters)); #line default #line hidden this.Write("?.ContainsKey(\""); - #line 104 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 104 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default #line hidden this.Write("\") == true)\r\n {\r\n "); - #line 106 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 106 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = __request__."); - #line 106 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 106 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(queryStringParameters)); #line default #line hidden this.Write("[\""); - #line 106 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 106 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default #line hidden this.Write("\"]"); - #line 106 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 106 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(commaSplit)); #line default @@ -218,14 +218,14 @@ public virtual string TransformText() this.Write("\r\n .Select(q =>\r\n {\r\n " + " try\r\n {\r\n return ("); - #line 111 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 111 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(typeArgument.FullName)); #line default #line hidden this.Write(")Convert.ChangeType(q, typeof("); - #line 111 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 111 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(typeArgument.FullNameWithoutAnnotations)); #line default @@ -236,7 +236,7 @@ public virtual string TransformText() { validationErrors.Add($""Value {q} at '"); - #line 115 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 115 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default @@ -245,7 +245,7 @@ public virtual string TransformText() "n default;\r\n }\r\n })\r\n " + " .ToList();\r\n }\r\n\r\n"); - #line 122 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 122 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } else @@ -257,14 +257,14 @@ public virtual string TransformText() #line hidden this.Write(" if (__request__."); - #line 128 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 128 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(queryStringParameters)); #line default #line hidden this.Write("?.ContainsKey(\""); - #line 128 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 128 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default @@ -272,35 +272,35 @@ public virtual string TransformText() this.Write("\") == true)\r\n {\r\n try\r\n {\r\n " + " "); - #line 132 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 132 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = ("); - #line 132 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 132 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(")Convert.ChangeType(__request__."); - #line 132 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 132 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(queryStringParameters)); #line default #line hidden this.Write("[\""); - #line 132 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 132 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default #line hidden this.Write("\"], typeof("); - #line 132 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 132 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullNameWithoutAnnotations)); #line default @@ -310,21 +310,21 @@ public virtual string TransformText() "eption)\r\n {\r\n validationErrors.Add($\"Value {__" + "request__."); - #line 136 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 136 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(queryStringParameters)); #line default #line hidden this.Write("[\""); - #line 136 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 136 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default #line hidden this.Write("\"]} at \'"); - #line 136 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 136 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameterKey)); #line default @@ -332,7 +332,7 @@ public virtual string TransformText() this.Write("\' failed to satisfy constraint: {e.Message}\");\r\n }\r\n }\r" + "\n\r\n"); - #line 140 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 140 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } @@ -354,21 +354,21 @@ public virtual string TransformText() #line hidden this.Write(" var "); - #line 156 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 156 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = default("); - #line 156 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 156 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(");\r\n"); - #line 157 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 157 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" if (parameter.Type.IsEnumerable && parameter.Type.IsGenericType) @@ -402,14 +402,14 @@ public virtual string TransformText() #line hidden this.Write(" if (__request__."); - #line 185 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 185 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headers)); #line default #line hidden this.Write("?.Any(x => string.Equals(x.Key, \""); - #line 185 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 185 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default @@ -417,28 +417,28 @@ public virtual string TransformText() this.Write("\", StringComparison.OrdinalIgnoreCase)) == true)\r\n {\r\n " + ""); - #line 187 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 187 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = __request__."); - #line 187 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 187 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headers)); #line default #line hidden this.Write(".First(x => string.Equals(x.Key, \""); - #line 187 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 187 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default #line hidden this.Write("\", StringComparison.OrdinalIgnoreCase)).Value"); - #line 187 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 187 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(commaSplit)); #line default @@ -446,14 +446,14 @@ public virtual string TransformText() this.Write("\r\n .Select(q =>\r\n {\r\n " + " try\r\n {\r\n return ("); - #line 192 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 192 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(typeArgument.FullName)); #line default #line hidden this.Write(")Convert.ChangeType(q, typeof("); - #line 192 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 192 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(typeArgument.FullNameWithoutAnnotations)); #line default @@ -464,7 +464,7 @@ public virtual string TransformText() { validationErrors.Add($""Value {q} at '"); - #line 196 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 196 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default @@ -473,7 +473,7 @@ public virtual string TransformText() "n default;\r\n }\r\n })\r\n " + " .ToList();\r\n }\r\n\r\n"); - #line 203 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 203 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } else @@ -485,14 +485,14 @@ public virtual string TransformText() #line hidden this.Write(" if (__request__."); - #line 209 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 209 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headers)); #line default #line hidden this.Write("?.Any(x => string.Equals(x.Key, \""); - #line 209 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 209 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default @@ -500,35 +500,35 @@ public virtual string TransformText() this.Write("\", StringComparison.OrdinalIgnoreCase)) == true)\r\n {\r\n " + "try\r\n {\r\n "); - #line 213 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 213 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = ("); - #line 213 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 213 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(")Convert.ChangeType(__request__."); - #line 213 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 213 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headers)); #line default #line hidden this.Write(".First(x => string.Equals(x.Key, \""); - #line 213 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 213 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default #line hidden this.Write("\", StringComparison.OrdinalIgnoreCase)).Value, typeof("); - #line 213 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 213 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullNameWithoutAnnotations)); #line default @@ -538,21 +538,21 @@ public virtual string TransformText() "eption)\r\n {\r\n validationErrors.Add($\"Value {__" + "request__."); - #line 217 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 217 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headers)); #line default #line hidden this.Write(".First(x => string.Equals(x.Key, \""); - #line 217 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 217 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default #line hidden this.Write("\", StringComparison.OrdinalIgnoreCase)).Value} at \'"); - #line 217 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 217 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(headerKey)); #line default @@ -560,7 +560,7 @@ public virtual string TransformText() this.Write("\' failed to satisfy constraint: {e.Message}\");\r\n }\r\n }\r" + "\n\r\n"); - #line 221 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 221 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } } @@ -575,14 +575,14 @@ public virtual string TransformText() #line hidden this.Write(" var "); - #line 230 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 230 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = __request__.Body;\r\n\r\n"); - #line 232 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 232 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } else @@ -593,14 +593,14 @@ public virtual string TransformText() #line hidden this.Write(" var "); - #line 237 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 237 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = default("); - #line 237 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 237 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default @@ -609,14 +609,14 @@ public virtual string TransformText() " var byteArray = Encoding.UTF8.GetBytes(__request__.Body);\r\n " + " var stream = new MemoryStream(byteArray);\r\n "); - #line 243 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 243 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = serializer.Deserialize<"); - #line 243 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 243 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default @@ -625,7 +625,372 @@ public virtual string TransformText() " validationErrors.Add($\"Value {__request__.Body} at \'body\' failed to sa" + "tisfy constraint: {e.Message}\");\r\n }\r\n\r\n"); - #line 250 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 250 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + } + else if (parameter.Attributes.Any(att => att.Type.FullName == TypeFullNames.FromCustomAuthorizerAttribute)) + { + var fromAuthorizerAttribute = parameter.Attributes?.FirstOrDefault(att => att.Type.FullName == TypeFullNames.FromCustomAuthorizerAttribute) as AttributeModel; + + // Use parameter name as key, if Name has not specified explicitly in the attribute definition. + var authKey = fromAuthorizerAttribute?.Data?.Name ?? parameter.Name; + // REST API and HTTP API v1 both use APIGatewayProxyRequest where RequestContext.Authorizer is a dictionary. + // Only HTTP API v2 uses APIGatewayHttpApiV2ProxyRequest with RequestContext.Authorizer.Lambda as the dictionary. + if(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1) + { + + + #line default + #line hidden + this.Write(" var "); + + #line 264 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write(" = default("); + + #line 264 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); + + #line default + #line hidden + this.Write(");\r\n if (__request__.RequestContext?.Authorizer == null || __request__" + + ".RequestContext?.Authorizer.ContainsKey(\""); + + #line 265 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(authKey)); + + #line default + #line hidden + this.Write("\") == false)\r\n {\r\n var __unauthorized__ = new "); + + #line 267 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse")); + + #line default + #line hidden + this.Write(@" + { + Headers = new Dictionary + { + {""Content-Type"", ""application/json""}, + {""x-amzn-ErrorType"", ""AccessDeniedException""} + }, + StatusCode = 401 + }; +"); + + #line 276 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + if(_model.LambdaMethod.ReturnsIHttpResults) + { + + + #line default + #line hidden + this.Write(@" var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +"); + + #line 284 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + else + { + + + #line default + #line hidden + this.Write(" return __unauthorized__;\r\n"); + + #line 290 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + + + #line default + #line hidden + this.Write(" }\r\n \r\n try\r\n {\r\n var " + + "__authValue_"); + + #line 297 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write("__ = __request__.RequestContext.Authorizer[\""); + + #line 297 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(authKey)); + + #line default + #line hidden + this.Write("\"];\r\n "); + + #line 298 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write(" = ("); + + #line 298 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); + + #line default + #line hidden + this.Write(")Convert.ChangeType(__authValue_"); + + #line 298 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write("__?.ToString(), typeof("); + + #line 298 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullNameWithoutAnnotations)); + + #line default + #line hidden + this.Write("));\r\n }\r\n catch (Exception e) when (e is InvalidCastExcepti" + + "on || e is FormatException || e is OverflowException || e is ArgumentException)\r" + + "\n {\r\n var __unauthorized__ = new "); + + #line 302 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse")); + + #line default + #line hidden + this.Write(@" + { + Headers = new Dictionary + { + {""Content-Type"", ""application/json""}, + {""x-amzn-ErrorType"", ""AccessDeniedException""} + }, + StatusCode = 401 + }; +"); + + #line 311 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + if(_model.LambdaMethod.ReturnsIHttpResults) + { + + + #line default + #line hidden + this.Write(@" var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +"); + + #line 319 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + else + { + + + #line default + #line hidden + this.Write(" return __unauthorized__;\r\n"); + + #line 325 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + + + #line default + #line hidden + this.Write(" }\r\n\r\n"); + + #line 330 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + else + { + + + #line default + #line hidden + this.Write(" var "); + + #line 335 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write(" = default("); + + #line 335 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); + + #line default + #line hidden + this.Write(");\r\n if (__request__.RequestContext?.Authorizer?.Lambda == null || __r" + + "equest__.RequestContext?.Authorizer?.Lambda.ContainsKey(\""); + + #line 336 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(authKey)); + + #line default + #line hidden + this.Write("\") == false)\r\n {\r\n var __unauthorized__ = new "); + + #line 338 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse")); + + #line default + #line hidden + this.Write(@" + { + Headers = new Dictionary + { + {""Content-Type"", ""application/json""}, + {""x-amzn-ErrorType"", ""AccessDeniedException""} + }, + StatusCode = 401 + }; +"); + + #line 347 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + if(_model.LambdaMethod.ReturnsIHttpResults) + { + + + #line default + #line hidden + this.Write(@" var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +"); + + #line 355 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + else + { + + + #line default + #line hidden + this.Write(" return __unauthorized__;\r\n"); + + #line 361 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + + + #line default + #line hidden + this.Write(" }\r\n \r\n try\r\n {\r\n var " + + "__authValue_"); + + #line 368 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write("__ = __request__.RequestContext.Authorizer.Lambda[\""); + + #line 368 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(authKey)); + + #line default + #line hidden + this.Write("\"];\r\n "); + + #line 369 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write(" = ("); + + #line 369 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); + + #line default + #line hidden + this.Write(")Convert.ChangeType(__authValue_"); + + #line 369 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); + + #line default + #line hidden + this.Write("__?.ToString(), typeof("); + + #line 369 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullNameWithoutAnnotations)); + + #line default + #line hidden + this.Write("));\r\n }\r\n catch (Exception e) when (e is InvalidCastExcepti" + + "on || e is FormatException || e is OverflowException || e is ArgumentException)\r" + + "\n {\r\n var __unauthorized__ = new "); + + #line 373 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse")); + + #line default + #line hidden + this.Write(@" + { + Headers = new Dictionary + { + {""Content-Type"", ""application/json""}, + {""x-amzn-ErrorType"", ""AccessDeniedException""} + }, + StatusCode = 401 + }; +"); + + #line 382 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + if(_model.LambdaMethod.ReturnsIHttpResults) + { + + + #line default + #line hidden + this.Write(@" var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +"); + + #line 390 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + else + { + + + #line default + #line hidden + this.Write(" return __unauthorized__;\r\n"); + + #line 396 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + + } + + + #line default + #line hidden + this.Write(" }\r\n\r\n"); + + #line 401 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } } @@ -641,21 +1006,21 @@ public virtual string TransformText() #line hidden this.Write(" var "); - #line 260 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 411 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = default("); - #line 260 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 411 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(");\r\n if (__request__.PathParameters?.ContainsKey(\""); - #line 261 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 412 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(routeKey)); #line default @@ -663,28 +1028,28 @@ public virtual string TransformText() this.Write("\") == true)\r\n {\r\n try\r\n {\r\n " + " "); - #line 265 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 416 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); #line default #line hidden this.Write(" = ("); - #line 265 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 416 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullName)); #line default #line hidden this.Write(")Convert.ChangeType(__request__.PathParameters[\""); - #line 265 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 416 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(routeKey)); #line default #line hidden this.Write("\"], typeof("); - #line 265 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 416 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type.FullNameWithoutAnnotations)); #line default @@ -695,14 +1060,14 @@ public virtual string TransformText() { validationErrors.Add($""Value {__request__.PathParameters["""); - #line 269 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 420 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(routeKey)); #line default #line hidden this.Write("\"]} at \'"); - #line 269 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 420 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(routeKey)); #line default @@ -710,7 +1075,7 @@ public virtual string TransformText() this.Write("\' failed to satisfy constraint: {e.Message}\");\r\n }\r\n }\r" + "\n\r\n"); - #line 273 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 424 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } else @@ -729,7 +1094,7 @@ public virtual string TransformText() " if (validationErrors.Any())\r\n {\r\n var errorResult" + " = new "); - #line 287 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 438 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" this.Write(this.ToStringHelper.ToStringWithCulture(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse")); #line default @@ -746,7 +1111,7 @@ public virtual string TransformText() }; "); - #line 297 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 448 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" if(_model.LambdaMethod.ReturnsIHttpResults) { @@ -758,7 +1123,7 @@ public virtual string TransformText() "serializer.Serialize(errorResult, errorStream);\r\n errorStream.Pos" + "ition = 0;\r\n return errorStream;\r\n"); - #line 305 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 456 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } else @@ -769,7 +1134,7 @@ public virtual string TransformText() #line hidden this.Write(" return errorResult;\r\n"); - #line 311 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 462 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } @@ -778,7 +1143,7 @@ public virtual string TransformText() #line hidden this.Write(" }\r\n\r\n"); - #line 316 "C:\codebase\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" + #line 467 "C:\dev\repos\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\APIGatewaySetupParameters.tt" } @@ -795,7 +1160,7 @@ public virtual string TransformText() /// /// Base class for this transformation /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")] public class APIGatewaySetupParametersBase { #region Fields diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt index 34ed6eb58..c8aaa34f6 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/APIGatewaySetupParameters.tt @@ -247,6 +247,157 @@ 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; + + // Use parameter name as key, if Name has not specified explicitly in the attribute definition. + var authKey = fromAuthorizerAttribute?.Data?.Name ?? parameter.Name; + // REST API and HTTP API v1 both use APIGatewayProxyRequest where RequestContext.Authorizer is a dictionary. + // Only HTTP API v2 uses APIGatewayHttpApiV2ProxyRequest with RequestContext.Authorizer.Lambda as the dictionary. + if(restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1) + { +#> + var <#= parameter.Name #> = default(<#= parameter.Type.FullName #>); + if (__request__.RequestContext?.Authorizer == null || __request__.RequestContext?.Authorizer.ContainsKey("<#= authKey #>") == false) + { + var __unauthorized__ = new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #> + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; +<# + if(_model.LambdaMethod.ReturnsIHttpResults) + { +#> + var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +<# + } + else + { +#> + return __unauthorized__; +<# + } +#> + } + + try + { + var __authValue_<#= parameter.Name #>__ = __request__.RequestContext.Authorizer["<#= authKey #>"]; + <#= parameter.Name #> = (<#= parameter.Type.FullName #>)Convert.ChangeType(__authValue_<#= parameter.Name #>__?.ToString(), typeof(<#= parameter.Type.FullNameWithoutAnnotations #>)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #> + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; +<# + if(_model.LambdaMethod.ReturnsIHttpResults) + { +#> + var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +<# + } + else + { +#> + return __unauthorized__; +<# + } +#> + } + +<# + } + else + { +#> + var <#= parameter.Name #> = default(<#= parameter.Type.FullName #>); + if (__request__.RequestContext?.Authorizer?.Lambda == null || __request__.RequestContext?.Authorizer?.Lambda.ContainsKey("<#= authKey #>") == false) + { + var __unauthorized__ = new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #> + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; +<# + if(_model.LambdaMethod.ReturnsIHttpResults) + { +#> + var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +<# + } + else + { +#> + return __unauthorized__; +<# + } +#> + } + + try + { + var __authValue_<#= parameter.Name #>__ = __request__.RequestContext.Authorizer.Lambda["<#= authKey #>"]; + <#= parameter.Name #> = (<#= parameter.Type.FullName #>)Convert.ChangeType(__authValue_<#= parameter.Name #>__?.ToString(), typeof(<#= parameter.Type.FullNameWithoutAnnotations #>)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new <#= restApiAttribute != null || httpApiAttribute?.Data.Version == Amazon.Lambda.Annotations.APIGateway.HttpApiVersion.V1 ? "Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse" : "Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse" #> + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; +<# + if(_model.LambdaMethod.ReturnsIHttpResults) + { +#> + var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; +<# + } + else + { +#> + return __unauthorized__; +<# + } +#> + } + <# } } @@ -315,4 +466,4 @@ <# } -#> \ No newline at end of file +#> diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/TypeFullNames.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/TypeFullNames.cs index 53a0cc610..a91cfaefa 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/TypeFullNames.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/TypeFullNames.cs @@ -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 SQSEvent = "Amazon.Lambda.SQSEvents.SQSEvent"; public const string SQSBatchResponse = "Amazon.Lambda.SQSEvents.SQSBatchResponse"; diff --git a/Libraries/src/Amazon.Lambda.Annotations/APIGateway/FromCustomAuthorizerAttribute.cs b/Libraries/src/Amazon.Lambda.Annotations/APIGateway/FromCustomAuthorizerAttribute.cs new file mode 100644 index 000000000..4bdc173e6 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.Annotations/APIGateway/FromCustomAuthorizerAttribute.cs @@ -0,0 +1,19 @@ +using System; + +namespace Amazon.Lambda.Annotations.APIGateway +{ + /// + /// Maps this parameter to a custom authorizer item + /// + /// + /// Will try to get the specified key from Custom Authorizer values + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class FromCustomAuthorizerAttribute : Attribute, INamedAttribute + { + /// + /// Key of the value + /// + public string Name { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.Annotations/README.md b/Libraries/src/Amazon.Lambda.Annotations/README.md index 62996f5fb..93c0ac46b 100644 --- a/Libraries/src/Amazon.Lambda.Annotations/README.md +++ b/Libraries/src/Amazon.Lambda.Annotations/README.md @@ -894,6 +894,22 @@ parameter to the `LambdaFunction` must be the event object and the event source * Map method parameter to HTTP request body. If parameter is a complex type then request body will be assumed to be JSON and deserialized into the type. * FromServices * Map method parameter to registered service in IServiceProvider +* FromCustomAuthorizer + * Map method parameter to a custom authorizer context value. Use the `Name` property to specify the key in the authorizer context if it differs from the parameter name. Returns HTTP 401 Unauthorized if the key is not found or type conversion fails. + +Example using `FromCustomAuthorizer` to access values set by a custom Lambda authorizer: +```csharp +[LambdaFunction] +[HttpApi(LambdaHttpMethod.Get, "/api/protected")] +public async Task ProtectedEndpoint( + [FromCustomAuthorizer(Name = "userId")] string userId, + [FromCustomAuthorizer(Name = "tenantId")] int tenantId, + ILambdaContext context) +{ + context.Logger.LogLine($"User {userId} from tenant {tenantId}"); + // userId and tenantId are automatically extracted from the custom authorizer context +} +``` ### Customizing responses for API Gateway Lambda functions @@ -940,4 +956,4 @@ The content type is determined using the following rules. ## Project References -If API Gateway event attributes, such as `RestAPI` or `HttpAPI`, are being used then a package reference to `Amazon.Lambda.APIGatewayEvents` must be added to the project, otherwise the project will not compile. We do not include it by default in order to keep the `Amazon.Lambda.Annotations` library lightweight. +If API Gateway event attributes, such as `RestAPI` or `HttpAPI`, are being used then a package reference to `Amazon.Lambda.APIGatewayEvents` must be added to the project, otherwise the project will not compile. We do not include it by default in order to keep the `Amazon.Lambda.Annotations` library lightweight. diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj index 3682b71a9..9b80950f6 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj @@ -168,6 +168,9 @@ + + + diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/AuthNameFallback_GetUserId_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/AuthNameFallback_GetUserId_Generated.g.cs new file mode 100644 index 000000000..92fde1712 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/AuthNameFallback_GetUserId_Generated.g.cs @@ -0,0 +1,115 @@ +// + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class AuthNameFallback_GetUserId_Generated + { + private readonly AuthNameFallback authNameFallback; + private readonly Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer serializer; + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public AuthNameFallback_GetUserId_Generated() + { + SetExecutionEnvironment(); + authNameFallback = new AuthNameFallback(); + serializer = new Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer(); + } + + /// + /// The generated Lambda function handler for + /// + /// The API Gateway request object that will be processed by the Lambda function handler. + /// The ILambdaContext that provides methods for logging and describing the Lambda environment. + /// Result of the Lambda function execution + public async System.Threading.Tasks.Task GetUserId(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__) + { + var validationErrors = new List(); + + var userId = default(string); + if (__request__.RequestContext?.Authorizer?.Lambda == null || __request__.RequestContext?.Authorizer?.Lambda.ContainsKey("userId") == false) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + try + { + var __authValue_userId__ = __request__.RequestContext.Authorizer.Lambda["userId"]; + userId = (string)Convert.ChangeType(__authValue_userId__?.ToString(), typeof(string)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + // 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 + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "ValidationException"} + }, + StatusCode = 400 + }; + return errorResult; + } + + await authNameFallback.GetUserId(userId, __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("lib/amazon-lambda-annotations#{ANNOTATIONS_ASSEMBLY_VERSION}"); + + Environment.SetEnvironmentVariable(envName, envValue.ToString()); + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs new file mode 100644 index 000000000..eabd0d661 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs @@ -0,0 +1,115 @@ +// + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated + { + private readonly CustomAuthorizerHttpApiExample customAuthorizerHttpApiExample; + private readonly Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer serializer; + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated() + { + SetExecutionEnvironment(); + customAuthorizerHttpApiExample = new CustomAuthorizerHttpApiExample(); + serializer = new Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer(); + } + + /// + /// The generated Lambda function handler for + /// + /// The API Gateway request object that will be processed by the Lambda function handler. + /// The ILambdaContext that provides methods for logging and describing the Lambda environment. + /// Result of the Lambda function execution + public async System.Threading.Tasks.Task HttpApiAuthorizer(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__) + { + var validationErrors = new List(); + + var authorizerValue = default(string); + if (__request__.RequestContext?.Authorizer?.Lambda == null || __request__.RequestContext?.Authorizer?.Lambda.ContainsKey("authKey") == false) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + try + { + var __authValue_authorizerValue__ = __request__.RequestContext.Authorizer.Lambda["authKey"]; + authorizerValue = (string)Convert.ChangeType(__authValue_authorizerValue__?.ToString(), typeof(string)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + // 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 + { + {"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("lib/amazon-lambda-annotations#{ANNOTATIONS_ASSEMBLY_VERSION}"); + + Environment.SetEnvironmentVariable(envName, envValue.ToString()); + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated.g.cs new file mode 100644 index 000000000..51360d0c8 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated.g.cs @@ -0,0 +1,115 @@ +// + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated + { + private readonly CustomAuthorizerHttpApiV1Example customAuthorizerHttpApiV1Example; + private readonly Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer serializer; + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated() + { + SetExecutionEnvironment(); + customAuthorizerHttpApiV1Example = new CustomAuthorizerHttpApiV1Example(); + serializer = new Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer(); + } + + /// + /// The generated Lambda function handler for + /// + /// The API Gateway request object that will be processed by the Lambda function handler. + /// The ILambdaContext that provides methods for logging and describing the Lambda environment. + /// Result of the Lambda function execution + public async System.Threading.Tasks.Task HttpApiV1Authorizer(Amazon.Lambda.APIGatewayEvents.APIGatewayProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__) + { + var validationErrors = new List(); + + var authorizerValue = default(string); + if (__request__.RequestContext?.Authorizer == null || __request__.RequestContext?.Authorizer.ContainsKey("authKey") == false) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + try + { + var __authValue_authorizerValue__ = __request__.RequestContext.Authorizer["authKey"]; + authorizerValue = (string)Convert.ChangeType(__authValue_authorizerValue__?.ToString(), typeof(string)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + // 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 + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "ValidationException"} + }, + StatusCode = 400 + }; + return errorResult; + } + + await customAuthorizerHttpApiV1Example.HttpApiV1Authorizer(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("lib/amazon-lambda-annotations#{ANNOTATIONS_ASSEMBLY_VERSION}"); + + Environment.SetEnvironmentVariable(envName, envValue.ToString()); + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerRestExample_RestAuthorizer_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerRestExample_RestAuthorizer_Generated.g.cs new file mode 100644 index 000000000..ad90db5e7 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerRestExample_RestAuthorizer_Generated.g.cs @@ -0,0 +1,115 @@ +// + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerRestExample_RestAuthorizer_Generated + { + private readonly CustomAuthorizerRestExample customAuthorizerRestExample; + private readonly Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer serializer; + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public CustomAuthorizerRestExample_RestAuthorizer_Generated() + { + SetExecutionEnvironment(); + customAuthorizerRestExample = new CustomAuthorizerRestExample(); + serializer = new Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer(); + } + + /// + /// The generated Lambda function handler for + /// + /// The API Gateway request object that will be processed by the Lambda function handler. + /// The ILambdaContext that provides methods for logging and describing the Lambda environment. + /// Result of the Lambda function execution + public async System.Threading.Tasks.Task RestAuthorizer(Amazon.Lambda.APIGatewayEvents.APIGatewayProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__) + { + var validationErrors = new List(); + + var authorizerValue = default(string); + if (__request__.RequestContext?.Authorizer == null || __request__.RequestContext?.Authorizer.ContainsKey("theAuthKey") == false) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + try + { + var __authValue_authorizerValue__ = __request__.RequestContext.Authorizer["theAuthKey"]; + authorizerValue = (string)Convert.ChangeType(__authValue_authorizerValue__?.ToString(), typeof(string)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + return __unauthorized__; + } + + // 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 + { + {"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("lib/amazon-lambda-annotations#{ANNOTATIONS_ASSEMBLY_VERSION}"); + + Environment.SetEnvironmentVariable(envName, envValue.ToString()); + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs new file mode 100644 index 000000000..5ef262f9c --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs @@ -0,0 +1,125 @@ +// + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Amazon.Lambda.Core; +using Amazon.Lambda.Annotations.APIGateway; + +namespace TestServerlessApp +{ + public class CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated + { + private readonly CustomAuthorizerWithIHttpResultsExample customAuthorizerWithIHttpResultsExample; + private readonly Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer serializer; + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated() + { + SetExecutionEnvironment(); + customAuthorizerWithIHttpResultsExample = new CustomAuthorizerWithIHttpResultsExample(); + serializer = new Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer(); + } + + /// + /// The generated Lambda function handler for + /// + /// The API Gateway request object that will be processed by the Lambda function handler. + /// The ILambdaContext that provides methods for logging and describing the Lambda environment. + /// Result of the Lambda function execution + public System.IO.Stream AuthorizerWithIHttpResults(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest __request__, Amazon.Lambda.Core.ILambdaContext __context__) + { + var validationErrors = new List(); + + var userId = default(string); + if (__request__.RequestContext?.Authorizer?.Lambda == null || __request__.RequestContext?.Authorizer?.Lambda.ContainsKey("userId") == false) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; + } + + try + { + var __authValue_userId__ = __request__.RequestContext.Authorizer.Lambda["userId"]; + userId = (string)Convert.ChangeType(__authValue_userId__?.ToString(), typeof(string)); + } + catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException) + { + var __unauthorized__ = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "AccessDeniedException"} + }, + StatusCode = 401 + }; + var __unauthorizedStream__ = new System.IO.MemoryStream(); + serializer.Serialize(__unauthorized__, __unauthorizedStream__); + __unauthorizedStream__.Position = 0; + return __unauthorizedStream__; + } + + // 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 + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "ValidationException"} + }, + StatusCode = 400 + }; + var errorStream = new System.IO.MemoryStream(); + serializer.Serialize(errorResult, errorStream); + errorStream.Position = 0; + return errorStream; + } + + var httpResults = customAuthorizerWithIHttpResultsExample.AuthorizerWithIHttpResults(userId, __context__); + HttpResultSerializationOptions.ProtocolFormat serializationFormat = HttpResultSerializationOptions.ProtocolFormat.HttpApi; + HttpResultSerializationOptions.ProtocolVersion serializationVersion = HttpResultSerializationOptions.ProtocolVersion.V2; + var serializationOptions = new HttpResultSerializationOptions { Format = serializationFormat, Version = serializationVersion, Serializer = serializer }; + var response = httpResults.Serialize(serializationOptions); + return response; + } + + 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("lib/amazon-lambda-annotations#{ANNOTATIONS_ASSEMBLY_VERSION}"); + + Environment.SetEnvironmentVariable(envName, envValue.ToString()); + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerHttpApi.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerHttpApi.template new file mode 100644 index 000000000..d60ca56e9 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerHttpApi.template @@ -0,0 +1,45 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v{ANNOTATIONS_ASSEMBLY_VERSION}).", + "Resources": { + "HttpApiAuthorizerTest": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } + }, + "Properties": { + "MemorySize": 512, + "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" + } + } + } + } + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerHttpApiV1.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerHttpApiV1.template new file mode 100644 index 000000000..5c0b12b9b --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerHttpApiV1.template @@ -0,0 +1,47 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v{ANNOTATIONS_ASSEMBLY_VERSION}).", + "Resources": { + "HttpApiV1AuthorizerTest": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method", + "PayloadFormatVersion" + ] + } + }, + "Properties": { + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Image", + "ImageUri": ".", + "ImageConfig": { + "Command": [ + "TestProject::TestServerlessApp.CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated::HttpApiV1Authorizer" + ] + }, + "Events": { + "RootGet": { + "Type": "HttpApi", + "Properties": { + "Path": "/api/authorizer-v1", + "Method": "GET", + "PayloadFormatVersion": "1.0" + } + } + } + } + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerParameterNameFallback.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerParameterNameFallback.template new file mode 100644 index 000000000..a30e2f0e1 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerParameterNameFallback.template @@ -0,0 +1,42 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v{ANNOTATIONS_ASSEMBLY_VERSION}).", + "Resources": { + "AuthNameFallbackTest": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } + }, + "Properties": { + "Runtime": "dotnet6", + "CodeUri": ".", + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Zip", + "Handler": "TestProject::TestServerlessApp.AuthNameFallback_GetUserId_Generated::GetUserId", + "Events": { + "RootGet": { + "Type": "HttpApi", + "Properties": { + "Path": "/api/authorizer-fallback", + "Method": "GET" + } + } + } + } + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerRest.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerRest.template new file mode 100644 index 000000000..9bbd4081c --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerRest.template @@ -0,0 +1,45 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v{ANNOTATIONS_ASSEMBLY_VERSION}).", + "Resources": { + "RestAuthorizerTest": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } + }, + "Properties": { + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Image", + "ImageUri": ".", + "ImageConfig": { + "Command": [ + "TestProject::TestServerlessApp.CustomAuthorizerRestExample_RestAuthorizer_Generated::RestAuthorizer" + ] + }, + "Events": { + "RootGet": { + "Type": "Api", + "Properties": { + "Path": "/rest/authorizer", + "Method": "GET" + } + } + } + } + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerWithIHttpResults.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerWithIHttpResults.template new file mode 100644 index 000000000..680d3ebc9 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/authorizerWithIHttpResults.template @@ -0,0 +1,45 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v{ANNOTATIONS_ASSEMBLY_VERSION}).", + "Resources": { + "TestServerlessAppCustomAuthorizerWithIHttpResultsExampleAuthorizerWithIHttpResultsGenerated": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } + }, + "Properties": { + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Image", + "ImageUri": ".", + "ImageConfig": { + "Command": [ + "TestProject::TestServerlessApp.CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated::AuthorizerWithIHttpResults" + ] + }, + "Events": { + "RootGet": { + "Type": "HttpApi", + "Properties": { + "Path": "/authorizerihttpresults", + "Method": "GET" + } + } + } + } + } + } +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs index 8258d884c..d7ce982f2 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs @@ -1400,6 +1400,206 @@ public async Task HostBuilder() }.RunAsync(); } + [Fact] + public async Task CustomAuthorizerRestTest() + { + var expectedTemplateContent = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "authorizerRest.template")); + var expectedRestAuthorizerGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "CustomAuthorizerRestExample_RestAuthorizer_Generated.g.cs")); + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + (Path.Combine("TestServerlessApp", "CustomAuthorizerRestExample.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "CustomAuthorizerRestExample.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "RestApiAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "RestApiAttribute.cs"))), + (Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"))), + }, + GeneratedSources = + { + ( + typeof(SourceGenerator.Generator), + "CustomAuthorizerRestExample_RestAuthorizer_Generated.g.cs", + SourceText.From(expectedRestAuthorizerGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256) + ) + }, + ExpectedDiagnostics = + { + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("CustomAuthorizerRestExample_RestAuthorizer_Generated.g.cs", expectedRestAuthorizerGenerated), + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestServerlessApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplateContent) + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60 + } + }.RunAsync(); + + var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template")); + Assert.Equal(expectedTemplateContent, actualTemplateContent); + } + + [Fact] + public async Task CustomAuthorizerHttpApiTest() + { + var expectedTemplateContent = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "authorizerHttpApi.template")); + var expectedRestAuthorizerGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs")); + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + (Path.Combine("TestServerlessApp", "CustomAuthorizerHttpApiExample.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "CustomAuthorizerHttpApiExample.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"))), + (Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"))), + }, + GeneratedSources = + { + ( + typeof(SourceGenerator.Generator), + "CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs", + SourceText.From(expectedRestAuthorizerGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256) + ) + }, + ExpectedDiagnostics = + { + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("CustomAuthorizerHttpApiExample_HttpApiAuthorizer_Generated.g.cs", expectedRestAuthorizerGenerated), + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestServerlessApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplateContent) + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60 + } + }.RunAsync(); + + var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template")); + Assert.Equal(expectedTemplateContent, actualTemplateContent); + } + + /// + /// Tests that [FromCustomAuthorizer] without Name property uses the parameter name as the key. + /// This exercises the fallback behavior: authKey = Name ?? parameter.Name + /// + [Fact] + public async Task CustomAuthorizerAttributeParameterNameFallbackTest() + { + var expectedTemplateContent = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "authorizerParameterNameFallback.template")); + var expectedAuthorizerGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "AuthNameFallback_GetUserId_Generated.g.cs")); + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + (Path.Combine("TestServerlessApp", "AuthNameFallback.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "AuthNameFallback.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "FromCustomAuthorizerAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "FromCustomAuthorizerAttribute.cs"))), + (Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"))), + }, + GeneratedSources = + { + ( + typeof(SourceGenerator.Generator), + "AuthNameFallback_GetUserId_Generated.g.cs", + SourceText.From(expectedAuthorizerGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256) + ) + }, + ExpectedDiagnostics = + { + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("AuthNameFallback_GetUserId_Generated.g.cs", expectedAuthorizerGenerated), + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestServerlessApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplateContent) + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60 + } + }.RunAsync(); + + var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template")); + Assert.Equal(expectedTemplateContent, actualTemplateContent); + } + + [Fact] + public async Task CustomAuthorizerHttpApiV1Test() + { + var expectedTemplateContent = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "authorizerHttpApiV1.template")); + var expectedHttpApiV1AuthorizerGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated.g.cs")); + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + (Path.Combine("TestServerlessApp", "CustomAuthorizerHttpApiV1Example.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "CustomAuthorizerHttpApiV1Example.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"))), + (Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"))), + }, + GeneratedSources = + { + ( + typeof(SourceGenerator.Generator), + "CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated.g.cs", + SourceText.From(expectedHttpApiV1AuthorizerGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256) + ) + }, + ExpectedDiagnostics = + { + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("CustomAuthorizerHttpApiV1Example_HttpApiV1Authorizer_Generated.g.cs", expectedHttpApiV1AuthorizerGenerated), + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestServerlessApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplateContent) + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60 + } + }.RunAsync(); + + var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template")); + Assert.Equal(expectedTemplateContent, actualTemplateContent); + } + + [Fact] + public async Task CustomAuthorizerWithIHttpResultsTest() + { + var expectedTemplateContent = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "authorizerWithIHttpResults.template")); + var expectedAuthorizerGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs")); + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + (Path.Combine("TestServerlessApp", "CustomAuthorizerWithIHttpResultsExample.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "CustomAuthorizerWithIHttpResultsExample.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "LambdaStartupAttribute.cs"))), + (Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"), File.ReadAllText(Path.Combine("Amazon.Lambda.Annotations", "APIGateway", "HttpApiAttribute.cs"))), + (Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"), File.ReadAllText(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"))), + }, + GeneratedSources = + { + ( + typeof(SourceGenerator.Generator), + "CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs", + SourceText.From(expectedAuthorizerGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256) + ) + }, + ExpectedDiagnostics = + { + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("CustomAuthorizerWithIHttpResultsExample_AuthorizerWithIHttpResults_Generated.g.cs", expectedAuthorizerGenerated), + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestServerlessApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplateContent) + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60 + } + }.RunAsync(); + + var actualTemplateContent = File.ReadAllText(Path.Combine("TestServerlessApp", "serverless.template")); + Assert.Equal(expectedTemplateContent, actualTemplateContent); + } + public void Dispose() { File.Delete(Path.Combine("TestServerlessApp", "serverless.template")); diff --git a/Libraries/test/IntegrationTests.Helpers/CloudFormationHelper.cs b/Libraries/test/IntegrationTests.Helpers/CloudFormationHelper.cs new file mode 100644 index 000000000..11e943b75 --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/CloudFormationHelper.cs @@ -0,0 +1,75 @@ +using System.Linq; +using System.Threading.Tasks; +using Amazon.CloudFormation; +using Amazon.CloudFormation.Model; + +namespace IntegrationTests.Helpers +{ + public class CloudFormationHelper + { + private readonly IAmazonCloudFormation _cloudFormationClient; + + public CloudFormationHelper(IAmazonCloudFormation cloudFormationClient) + { + _cloudFormationClient = cloudFormationClient; + } + + public async Task GetStackStatusAsync(string stackName) + { + var stack = await GetStackAsync(stackName); + return stack?.StackStatus; + } + + public async Task IsDeletedAsync(string stackName) + { + var attemptCount = 0; + const int maxAttempts = 5; + + while (attemptCount < maxAttempts) + { + attemptCount += 1; + if (!await StackExistsAsync(stackName)) + return true; + await Task.Delay(StaticHelpers.GetWaitTime(attemptCount)); + } + return false; + } + + public async Task DeleteStackAsync(string stackName) + { + if (!await StackExistsAsync(stackName)) + return; + + await _cloudFormationClient.DeleteStackAsync(new DeleteStackRequest { StackName = stackName }); + } + + public async Task GetOutputValueAsync(string stackName, string outputKey) + { + var stack = await GetStackAsync(stackName); + return stack?.Outputs.FirstOrDefault(x => string.Equals(x.OutputKey, outputKey))?.OutputValue; + } + + private async Task GetStackAsync(string stackName) + { + if (!await StackExistsAsync(stackName)) + return null; + + var response = await _cloudFormationClient.DescribeStacksAsync(new DescribeStacksRequest { StackName = stackName }); + return response.Stacks.Count == 0 ? null : response.Stacks[0]; + } + + private async Task StackExistsAsync(string stackName) + { + try + { + await _cloudFormationClient.DescribeStacksAsync(new DescribeStacksRequest { StackName = stackName }); + } + catch (AmazonCloudFormationException exception) when (exception.ErrorCode.Equals("ValidationError") && exception.Message.Equals($"Stack with id {stackName} does not exist")) + { + return false; + } + + return true; + } + } +} diff --git a/Libraries/test/IntegrationTests.Helpers/CloudWatchHelper.cs b/Libraries/test/IntegrationTests.Helpers/CloudWatchHelper.cs new file mode 100644 index 000000000..a89cf7bb7 --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/CloudWatchHelper.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Amazon.CloudWatchLogs; +using Amazon.CloudWatchLogs.Model; + +namespace IntegrationTests.Helpers +{ + public class CloudWatchHelper + { + private readonly IAmazonCloudWatchLogs _cloudWatchlogsClient; + + public CloudWatchHelper(IAmazonCloudWatchLogs cloudWatchlogsClient) + { + _cloudWatchlogsClient = cloudWatchlogsClient; + } + + public string GetLogGroupName(string lambdaFunctionName) => $"/aws/lambda/{lambdaFunctionName}"; + + public async Task MessageExistsInRecentLogEventsAsync(string message, string logGroupName, string logGroupNamePrefix) + { + var attemptCount = 0; + const int maxAttempts = 5; + + while (attemptCount < maxAttempts) + { + attemptCount += 1; + var recentLogEvents = await GetRecentLogEventsAsync(logGroupName, logGroupNamePrefix); + if (recentLogEvents.Any(x => x.Message.Contains(message))) + return true; + await Task.Delay(StaticHelpers.GetWaitTime(attemptCount)); + } + + return false; + } + + private async Task> GetRecentLogEventsAsync(string logGroupName, string logGroupNamePrefix) + { + var latestLogStreamName = await GetLatestLogStreamNameAsync(logGroupName, logGroupNamePrefix); + var logEvents = await GetLogEventsAsync(logGroupName, latestLogStreamName); + return logEvents; + } + + private async Task GetLatestLogStreamNameAsync(string logGroupName, string logGroupNamePrefix) + { + var attemptCount = 0; + const int maxAttempts = 5; + + while (attemptCount < maxAttempts) + { + attemptCount += 1; + if (await LogGroupExistsAsync(logGroupName, logGroupNamePrefix)) + break; + await Task.Delay(StaticHelpers.GetWaitTime(attemptCount)); + } + + var response = await _cloudWatchlogsClient.DescribeLogStreamsAsync( + new DescribeLogStreamsRequest + { + LogGroupName = logGroupName, + Descending = true, + Limit = 1 + }); + + return response.LogStreams.FirstOrDefault()?.LogStreamName; + } + + private async Task> GetLogEventsAsync(string logGroupName, string? logStreamName) + { + if (string.IsNullOrEmpty(logStreamName)) + return new List(); + + var response = await _cloudWatchlogsClient.GetLogEventsAsync( + new GetLogEventsRequest + { + LogGroupName = logGroupName, + LogStreamName = logStreamName, + Limit = 10 + }); + + return response.Events; + } + + private async Task LogGroupExistsAsync(string logGroupName, string logGroupNamePrefix) + { + var response = await _cloudWatchlogsClient.DescribeLogGroupsAsync(new DescribeLogGroupsRequest { LogGroupNamePrefix = logGroupNamePrefix }); + return response.LogGroups.Any(x => string.Equals(x.LogGroupName, logGroupName)); + } + } +} diff --git a/Libraries/test/IntegrationTests.Helpers/CommandLineWrapper.cs b/Libraries/test/IntegrationTests.Helpers/CommandLineWrapper.cs new file mode 100644 index 000000000..31f705a45 --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/CommandLineWrapper.cs @@ -0,0 +1,71 @@ +#nullable enable +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntegrationTests.Helpers +{ + public static class CommandLineWrapper + { + public static async Task RunAsync(string command, string workingDirectory = "", bool redirectIo = true, CancellationToken cancelToken = default) + { + var processStartInfo = new ProcessStartInfo + { + FileName = GetSystemShell(), + Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"/c {command}" : $"-c \"{command}\"", + + RedirectStandardInput = redirectIo, + RedirectStandardOutput = redirectIo, + RedirectStandardError = redirectIo, + UseShellExecute = false, + CreateNoWindow = redirectIo, + WorkingDirectory = workingDirectory + }; + + var process = Process.Start(processStartInfo); + if (null == process) + throw new Exception("Process.Start failed to return a non-null process"); + + var sb = new StringBuilder(); + DataReceivedEventHandler callback = (object sender, DataReceivedEventArgs e) => + { + sb.AppendLine(e.Data); + Console.WriteLine(e.Data); + }; + + if (redirectIo) + { + process.OutputDataReceived += callback; + process.ErrorDataReceived += callback; + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + } + + await process.WaitForExitAsync(cancelToken); + var log = sb.ToString(); + } + + private static string GetSystemShell() + { + if (TryGetEnvironmentVariable("COMSPEC", out var comspec)) + return comspec!; + + if (TryGetEnvironmentVariable("SHELL", out var shell)) + return shell!; + + // fall back to defaults + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "cmd.exe" : "/bin/sh"; + } + + private static bool TryGetEnvironmentVariable(string variable, out string? value) + { + value = Environment.GetEnvironmentVariable(variable); + + return !string.IsNullOrEmpty(value); + } + } +} diff --git a/Libraries/test/IntegrationTests.Helpers/IntegrationTests.Helpers.csproj b/Libraries/test/IntegrationTests.Helpers/IntegrationTests.Helpers.csproj new file mode 100644 index 000000000..c1f9c663b --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/IntegrationTests.Helpers.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + disable + enable + + + + + + + + + + diff --git a/Libraries/test/IntegrationTests.Helpers/LambdaHelper.cs b/Libraries/test/IntegrationTests.Helpers/LambdaHelper.cs new file mode 100644 index 000000000..6436c7c7b --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/LambdaHelper.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Amazon.Lambda; +using Amazon.Lambda.Model; + +namespace IntegrationTests.Helpers +{ + public class LambdaHelper + { + private readonly IAmazonLambda _lambdaClient; + + public LambdaHelper(IAmazonLambda lambdaClient) + { + _lambdaClient = lambdaClient; + } + + public async Task> FilterByCloudFormationStackAsync(string stackName) + { + const string stackNameKey = "aws:cloudformation:stack-name"; + const string logicalIdKey = "aws:cloudformation:logical-id"; + var lambdaFunctions = new List(); + var paginator = _lambdaClient.Paginators.ListFunctions(new ListFunctionsRequest()); + + await foreach (var function in paginator.Functions) + { + var tags = (await _lambdaClient.ListTagsAsync(new ListTagsRequest { Resource = function.FunctionArn })).Tags; + if (tags.ContainsKey(stackNameKey) && string.Equals(tags[stackNameKey], stackName)) + { + var lambdaFunction = new LambdaFunction + { + LogicalId = tags[logicalIdKey], + Name = function.FunctionName + }; + lambdaFunctions.Add(lambdaFunction); + } + } + + return lambdaFunctions; + } + + public async Task InvokeFunctionAsync(string functionName, string? payload = null) + { + var request = new InvokeRequest { FunctionName = functionName }; + if (!string.IsNullOrEmpty(payload)) + request.Payload = payload; + return await _lambdaClient.InvokeAsync(request); + } + + public async Task ListEventSourceMappingsAsync(string functionName, string eventSourceArn) + { + return await _lambdaClient.ListEventSourceMappingsAsync(new ListEventSourceMappingsRequest + { + FunctionName = functionName, + EventSourceArn = eventSourceArn + }); + } + + public async Task WaitTillNotPending(List functions) + { + foreach (var function in functions) + { + while (true) + { + var response = await _lambdaClient.GetFunctionConfigurationAsync(new GetFunctionConfigurationRequest { FunctionName = function }); + if (response.State == State.Pending) + { + await Task.Delay(1000); + } + else + { + break; + } + } + } + } + } + + public class LambdaFunction + { + public string? LogicalId { get; set; } + public string? Name { get; set; } + } +} diff --git a/Libraries/test/IntegrationTests.Helpers/S3Helper.cs b/Libraries/test/IntegrationTests.Helpers/S3Helper.cs new file mode 100644 index 000000000..e3c09eefd --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/S3Helper.cs @@ -0,0 +1,37 @@ +using System.Linq; +using System.Threading.Tasks; +using Amazon.S3; +using Amazon.S3.Model; + +namespace IntegrationTests.Helpers +{ + public class S3Helper + { + private readonly IAmazonS3 _s3Client; + + public S3Helper(IAmazonS3 s3Client) + { + _s3Client = s3Client; + } + + public async Task DeleteBucketAsync(string bucketName) + { + if (!await BucketExistsAsync(bucketName)) + return; + + var response = await _s3Client.ListObjectsAsync(new ListObjectsRequest { BucketName = bucketName }); + foreach (var s3Object in response.S3Objects) + { + await _s3Client.DeleteObjectAsync(new DeleteObjectRequest { BucketName = bucketName, Key = s3Object.Key }); + } + + await _s3Client.DeleteBucketAsync(new DeleteBucketRequest { BucketName = bucketName }); + } + + public async Task BucketExistsAsync(string bucketName) + { + var response = await _s3Client.ListBucketsAsync(new ListBucketsRequest()); + return response.Buckets.Any(x => x.BucketName.Equals(bucketName)); + } + } +} diff --git a/Libraries/test/IntegrationTests.Helpers/StaticHelpers.cs b/Libraries/test/IntegrationTests.Helpers/StaticHelpers.cs new file mode 100644 index 000000000..29c9a9878 --- /dev/null +++ b/Libraries/test/IntegrationTests.Helpers/StaticHelpers.cs @@ -0,0 +1,13 @@ +using System; + +namespace IntegrationTests.Helpers +{ + public static class StaticHelpers + { + public static TimeSpan GetWaitTime(int attemptCount) + { + var waitTime = Math.Pow(2, attemptCount) * 5; + return TimeSpan.FromSeconds(waitTime); + } + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/DeploymentScript.ps1 b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/DeploymentScript.ps1 new file mode 100644 index 000000000..4fe9313c0 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/DeploymentScript.ps1 @@ -0,0 +1,72 @@ +$ErrorActionPreference = 'Stop' + +function Get-Architecture { + $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture + if ($arch -eq "Arm64" -or $arch -eq "Arm") { + return "arm64" + } + + if ($arch -eq "X64" -or $arch -eq "X86") { + return "x86_64" + } + + throw "Unsupported architecture: $arch" +} + +try +{ + Push-Location $PSScriptRoot + $guid = New-Guid + $suffix = $guid.ToString().Split('-') | Select-Object -First 1 + $identifier = "test-custom-authorizer-" + $suffix + cd ..\TestCustomAuthorizerApp + + $arch = Get-Architecture + + # Replace bucket name in aws-lambda-tools-defaults.json + $line = Get-Content .\aws-lambda-tools-defaults.json | Select-String s3-bucket | Select-Object -ExpandProperty Line + $content = Get-Content .\aws-lambda-tools-defaults.json + $content | ForEach-Object {$_ -replace $line, "`"s3-bucket`" : `"$identifier`","} | Set-Content .\aws-lambda-tools-defaults.json + + # Replace stack name in aws-lambda-tools-defaults.json + $line = Get-Content .\aws-lambda-tools-defaults.json | Select-String stack-name | Select-Object -ExpandProperty Line + $content = Get-Content .\aws-lambda-tools-defaults.json + $content | ForEach-Object {$_ -replace $line, "`"stack-name`" : `"$identifier`","} | Set-Content .\aws-lambda-tools-defaults.json + + # Replace function-architecture in aws-lambda-tools-defaults.json + $line = Get-Content .\aws-lambda-tools-defaults.json | Select-String function-architecture | Select-Object -ExpandProperty Line + $content = Get-Content .\aws-lambda-tools-defaults.json + $content | ForEach-Object {$_ -replace $line, "`"function-architecture`" : `"$arch`""} | Set-Content .\aws-lambda-tools-defaults.json + + # Extract region + $json = Get-Content .\aws-lambda-tools-defaults.json | Out-String | ConvertFrom-Json + $region = $json.region + + dotnet tool install -g Amazon.Lambda.Tools + Write-Host "Creating S3 Bucket $identifier" + + if(![string]::IsNullOrEmpty($region)) + { + aws s3 mb s3://$identifier --region $region + } + else + { + aws s3 mb s3://$identifier + } + + if (!$?) + { + throw "Failed to create the following bucket: $identifier" + } + dotnet restore + Write-Host "Creating CloudFormation Stack $identifier, Architecture $arch" + dotnet lambda deploy-serverless + if (!$?) + { + throw "Failed to create the following CloudFormation stack: $identifier" + } +} +finally +{ + Pop-Location +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HealthCheckTests.cs b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HealthCheckTests.cs new file mode 100644 index 000000000..2360d7305 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HealthCheckTests.cs @@ -0,0 +1,30 @@ +using System.Net; +using Xunit; + +namespace TestCustomAuthorizerApp.IntegrationTests; + +/// +/// Tests for the health check endpoint which does not require authorization. +/// +[Collection("Integration Tests")] +public class HealthCheckTests +{ + private readonly IntegrationTestContextFixture _fixture; + + public HealthCheckTests(IntegrationTestContextFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task HealthCheck_ReturnsOk_WithoutAuthorization() + { + // Arrange & Act + var response = await _fixture.HttpClient.GetAsync($"{_fixture.HttpApiUrl}/api/health"); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var content = await response.Content.ReadAsStringAsync(); + Assert.Contains("OK", content); + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HttpApiV1Tests.cs b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HttpApiV1Tests.cs new file mode 100644 index 000000000..1ae5084c8 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HttpApiV1Tests.cs @@ -0,0 +1,72 @@ +using System.Net; +using System.Net.Http.Headers; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace TestCustomAuthorizerApp.IntegrationTests; + +/// +/// Tests for HTTP API v1 (payload format 1.0) endpoints with custom authorizer. +/// HTTP API v1 uses the same request structure as REST API. +/// +[Collection("Integration Tests")] +public class HttpApiV1Tests +{ + private readonly IntegrationTestContextFixture _fixture; + + public HttpApiV1Tests(IntegrationTestContextFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task HttpApiV1UserInfo_WithValidAuth_ReturnsAuthorizerContext() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/http-v1-user-info"); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var content = await response.Content.ReadAsStringAsync(); + var json = JObject.Parse(content); + + // Verify FromCustomAuthorizer extracted the values correctly from v1 format + Assert.Equal("user-12345", json["UserId"]?.ToString()); + Assert.Equal("test@example.com", json["Email"]?.ToString()); + Assert.Equal("42", json["TenantId"]?.ToString()); + Assert.Equal("HTTP API V1", json["ApiType"]?.ToString()); + } + + [Fact] + public async Task HttpApiV1UserInfo_WithoutAuth_ReturnsUnauthorized() + { + // Arrange & Act + var response = await _fixture.HttpClient.GetAsync($"{_fixture.HttpApiUrl}/api/http-v1-user-info"); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } + + [Fact] + public async Task HttpApiV1UserInfo_WithInvalidToken_ReturnsForbidden() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/http-v1-user-info"); + // Send an invalid token - authorizer uses allow-list approach + request.Headers.TryAddWithoutValidation("Authorization", "invalid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HttpApiV2Tests.cs b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HttpApiV2Tests.cs new file mode 100644 index 000000000..4d812e02c --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/HttpApiV2Tests.cs @@ -0,0 +1,132 @@ +using System.Net; +using System.Net.Http.Headers; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace TestCustomAuthorizerApp.IntegrationTests; + +/// +/// Tests for HTTP API v2 (payload format 2.0) endpoints with custom authorizer. +/// +[Collection("Integration Tests")] +public class HttpApiV2Tests +{ + private readonly IntegrationTestContextFixture _fixture; + + public HttpApiV2Tests(IntegrationTestContextFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task ProtectedEndpoint_WithValidAuth_ReturnsSuccess() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/protected"); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var content = await response.Content.ReadAsStringAsync(); + // The endpoint returns context info - should contain the authorizer values + Assert.Contains("user-12345", content); + } + + [Fact] + public async Task ProtectedEndpoint_WithoutAuth_ReturnsUnauthorized() + { + // Arrange & Act + var response = await _fixture.HttpClient.GetAsync($"{_fixture.HttpApiUrl}/api/protected"); + + // Assert + // HTTP API with Lambda authorizer returns 401 when authorization header is missing + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } + + [Fact] + public async Task ProtectedEndpoint_WithInvalidToken_ReturnsForbidden() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/protected"); + // Send an invalid token - authorizer uses allow-list approach + request.Headers.TryAddWithoutValidation("Authorization", "invalid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } + + [Fact] + public async Task UserInfo_WithValidAuth_ReturnsAuthorizerContext() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/user-info"); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var content = await response.Content.ReadAsStringAsync(); + var json = JObject.Parse(content); + + // Verify FromCustomAuthorizer extracted the values correctly + Assert.Equal("user-12345", json["UserId"]?.ToString()); + Assert.Equal("test@example.com", json["Email"]?.ToString()); + Assert.Equal("42", json["TenantId"]?.ToString()); + } + + [Fact] + public async Task UserInfo_WithoutAuth_ReturnsUnauthorized() + { + // Arrange & Act + var response = await _fixture.HttpClient.GetAsync($"{_fixture.HttpApiUrl}/api/user-info"); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } + + [Fact] + public async Task IHttpResult_WithValidAuth_ReturnsSuccess() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.HttpApiUrl}/api/ihttpresult-user-info"); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var content = await response.Content.ReadAsStringAsync(); + var json = JObject.Parse(content); + + // Verify FromCustomAuthorizer extracted the values correctly + Assert.Equal("user-12345", json["UserId"]?.ToString()); + Assert.Equal("test@example.com", json["Email"]?.ToString()); + } + + [Fact] + public async Task IHttpResult_WithoutAuth_ReturnsUnauthorized() + { + // Arrange & Act + var response = await _fixture.HttpClient.GetAsync($"{_fixture.HttpApiUrl}/api/ihttpresult-user-info"); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/IntegrationTestContextFixture.cs b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/IntegrationTestContextFixture.cs new file mode 100644 index 000000000..f4351b4bb --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/IntegrationTestContextFixture.cs @@ -0,0 +1,109 @@ +using System.Net.Http; +using Amazon.CloudFormation; +using Amazon.CloudWatchLogs; +using Amazon.Lambda; +using Amazon.S3; +using IntegrationTests.Helpers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace TestCustomAuthorizerApp.IntegrationTests; + +public class IntegrationTestContextFixture : IAsyncLifetime +{ + private readonly CloudFormationHelper _cloudFormationHelper; + private readonly S3Helper _s3Helper; + + private string _stackName = string.Empty; + private string _bucketName = string.Empty; + + public readonly LambdaHelper LambdaHelper; + public readonly CloudWatchHelper CloudWatchHelper; + public readonly HttpClient HttpClient; + + /// + /// HTTP API base URL (no trailing slash) + /// + public string HttpApiUrl = string.Empty; + + /// + /// REST API base URL (no trailing slash) + /// + public string RestApiUrl = string.Empty; + + /// + /// List of Lambda functions deployed in this stack + /// + public List LambdaFunctions = new(); + + public IntegrationTestContextFixture() + { + _cloudFormationHelper = new CloudFormationHelper(new AmazonCloudFormationClient(Amazon.RegionEndpoint.USWest2)); + _s3Helper = new S3Helper(new AmazonS3Client(Amazon.RegionEndpoint.USWest2)); + LambdaHelper = new LambdaHelper(new AmazonLambdaClient(Amazon.RegionEndpoint.USWest2)); + CloudWatchHelper = new CloudWatchHelper(new AmazonCloudWatchLogsClient(Amazon.RegionEndpoint.USWest2)); + HttpClient = new HttpClient(); + } + + public async Task InitializeAsync() + { + var scriptPath = Path.Combine("..", "..", "..", "DeploymentScript.ps1"); + await CommandLineWrapper.RunAsync($"pwsh {scriptPath}"); + + _stackName = GetStackName(); + _bucketName = GetBucketName(); + Assert.False(string.IsNullOrEmpty(_stackName), "Stack name should not be empty"); + Assert.False(string.IsNullOrEmpty(_bucketName), "Bucket name should not be empty"); + + // Get API URLs from CloudFormation outputs + HttpApiUrl = await _cloudFormationHelper.GetOutputValueAsync(_stackName, "ApiUrl") ?? string.Empty; + RestApiUrl = await _cloudFormationHelper.GetOutputValueAsync(_stackName, "RestApiUrl") ?? string.Empty; + + LambdaFunctions = await LambdaHelper.FilterByCloudFormationStackAsync(_stackName); + + Assert.Equal(StackStatus.CREATE_COMPLETE, await _cloudFormationHelper.GetStackStatusAsync(_stackName)); + Assert.True(await _s3Helper.BucketExistsAsync(_bucketName), $"S3 bucket {_bucketName} should exist"); + + // There are 8 Lambda functions in TestCustomAuthorizerApp: + // CustomAuthorizer, RestApiAuthorizer, ProtectedEndpoint, GetUserInfo, HealthCheck, RestUserInfo, HttpApiV1UserInfo, IHttpResultUserInfo + Assert.Equal(8, LambdaFunctions.Count); + Assert.False(string.IsNullOrEmpty(HttpApiUrl), "HTTP API URL should not be empty"); + Assert.False(string.IsNullOrEmpty(RestApiUrl), "REST API URL should not be empty"); + + await LambdaHelper.WaitTillNotPending(LambdaFunctions.Where(x => x.Name != null).Select(x => x.Name!).ToList()); + + // Wait an additional 10 seconds for any other eventual consistency state to finish up. + await Task.Delay(10000); + } + + public async Task DisposeAsync() + { + await _cloudFormationHelper.DeleteStackAsync(_stackName); + Assert.True(await _cloudFormationHelper.IsDeletedAsync(_stackName), $"The stack '{_stackName}' still exists and will have to be manually deleted from the AWS console."); + + await _s3Helper.DeleteBucketAsync(_bucketName); + Assert.False(await _s3Helper.BucketExistsAsync(_bucketName), $"The bucket '{_bucketName}' still exists and will have to be manually deleted from the AWS console."); + + // Reset the aws-lambda-tools-defaults.json to original values + var filePath = Path.Combine("..", "..", "..", "..", "TestCustomAuthorizerApp", "aws-lambda-tools-defaults.json"); + var token = JObject.Parse(await File.ReadAllTextAsync(filePath)); + token["s3-bucket"] = "test-custom-authorizer-app"; + token["stack-name"] = "test-custom-authorizer"; + await File.WriteAllTextAsync(filePath, token.ToString(Formatting.Indented)); + } + + private string GetStackName() + { + var filePath = Path.Combine("..", "..", "..", "..", "TestCustomAuthorizerApp", "aws-lambda-tools-defaults.json"); + var token = JObject.Parse(File.ReadAllText(filePath))["stack-name"]; + return token?.ToObject() ?? string.Empty; + } + + private string GetBucketName() + { + var filePath = Path.Combine("..", "..", "..", "..", "TestCustomAuthorizerApp", "aws-lambda-tools-defaults.json"); + var token = JObject.Parse(File.ReadAllText(filePath))["s3-bucket"]; + return token?.ToObject() ?? string.Empty; + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/IntegrationTestContextFixtureCollection.cs b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/IntegrationTestContextFixtureCollection.cs new file mode 100644 index 000000000..f90a2401b --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/IntegrationTestContextFixtureCollection.cs @@ -0,0 +1,11 @@ +using Xunit; + +namespace TestCustomAuthorizerApp.IntegrationTests; + +[CollectionDefinition("Integration Tests")] +public class IntegrationTestContextFixtureCollection : ICollectionFixture +{ + // This class has no code, and is never created. Its purpose is simply + // to be the place to apply [CollectionDefinition] and all the + // ICollectionFixture<> interfaces. +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/RestApiTests.cs b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/RestApiTests.cs new file mode 100644 index 000000000..862fd66e6 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/RestApiTests.cs @@ -0,0 +1,72 @@ +using System.Net; +using System.Net.Http.Headers; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace TestCustomAuthorizerApp.IntegrationTests; + +/// +/// Tests for REST API (API Gateway v1) endpoints with custom authorizer. +/// REST API uses a different authorizer context structure than HTTP API v2. +/// +[Collection("Integration Tests")] +public class RestApiTests +{ + private readonly IntegrationTestContextFixture _fixture; + + public RestApiTests(IntegrationTestContextFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task RestUserInfo_WithValidAuth_ReturnsAuthorizerContext() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.RestApiUrl}/api/rest-user-info"); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var content = await response.Content.ReadAsStringAsync(); + var json = JObject.Parse(content); + + // Verify FromCustomAuthorizer extracted the values correctly from REST API format + Assert.Equal("user-12345", json["UserId"]?.ToString()); + Assert.Equal("test@example.com", json["Email"]?.ToString()); + Assert.Equal("42", json["TenantId"]?.ToString()); + Assert.Equal("REST API", json["ApiType"]?.ToString()); + } + + [Fact] + public async Task RestUserInfo_WithoutAuth_ReturnsUnauthorized() + { + // Arrange & Act + var response = await _fixture.HttpClient.GetAsync($"{_fixture.RestApiUrl}/api/rest-user-info"); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } + + [Fact] + public async Task RestUserInfo_WithInvalidToken_ReturnsForbidden() + { + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"{_fixture.RestApiUrl}/api/rest-user-info"); + // Send an invalid token - authorizer uses allow-list approach + request.Headers.TryAddWithoutValidation("Authorization", "invalid-token"); + + // Act + var response = await _fixture.HttpClient.SendAsync(request); + + // Assert + Assert.True( + response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden, + $"Expected 401 or 403 but got {response.StatusCode}"); + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/TestCustomAuthorizerApp.IntegrationTests.csproj b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/TestCustomAuthorizerApp.IntegrationTests.csproj new file mode 100644 index 000000000..9271cfe61 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp.IntegrationTests/TestCustomAuthorizerApp.IntegrationTests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + Library + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/Libraries/test/TestCustomAuthorizerApp/AuthorizerFunction.cs b/Libraries/test/TestCustomAuthorizerApp/AuthorizerFunction.cs new file mode 100644 index 000000000..eef37c162 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp/AuthorizerFunction.cs @@ -0,0 +1,157 @@ +using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Core; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace TestCustomAuthorizerApp; + +/// +/// Custom Lambda Authorizer that validates requests and returns context values. +/// This authorizer is configured for HTTP API (API Gateway V2) with simple response format. +/// +public class AuthorizerFunction +{ + // Valid tokens that will be authorized (for testing purposes) + private static readonly HashSet ValidTokens = new(StringComparer.OrdinalIgnoreCase) + { + "allow", + "Bearer allow", + "valid-token", + "Bearer valid-token" + }; + + /// + /// HTTP API Lambda Authorizer (Payload format 2.0 with simple response) + /// Returns authorized status along with custom context that can be accessed via [FromCustomAuthorizer] + /// + public APIGatewayCustomAuthorizerV2SimpleResponse HttpApiAuthorize( + APIGatewayCustomAuthorizerV2Request request, + ILambdaContext context) + { + context.Logger.LogLine($"Authorizer invoked for path: {request.RawPath}"); + if (request.Headers != null) + { + context.Logger.LogLine($"Request headers: {string.Join(", ", request.Headers.Keys)}"); + } + + // Check for Authorization header + // Note: HTTP API v2 lowercases all header names + var hasAuthHeader = request.Headers?.ContainsKey("authorization") == true; + + if (hasAuthHeader) + { + var authValue = request.Headers!["authorization"]; + context.Logger.LogLine($"Authorization header value: {authValue}"); + + // Only authorize if the token is in our allow list + if (ValidTokens.Contains(authValue)) + { + context.Logger.LogLine("Authorizing request with valid token"); + + // Return authorized with context values that will be passed to the Lambda function + // These values can be accessed using [FromCustomAuthorizer(Name = "key")] + return new APIGatewayCustomAuthorizerV2SimpleResponse + { + IsAuthorized = true, + Context = new Dictionary + { + // These values will be available via [FromCustomAuthorizer] + { "userId", "user-12345" }, + { "tenantId", "42" }, + { "userRole", "admin" }, + { "email", "test@example.com" } + } + }; + } + } + + // Deny by default - no valid token found + context.Logger.LogLine("Denying request - no valid token found"); + return new APIGatewayCustomAuthorizerV2SimpleResponse + { + IsAuthorized = false + }; + } + + /// + /// REST API Lambda Authorizer (Token-based authorizer) + /// Returns an IAM policy document along with custom context values + /// + public APIGatewayCustomAuthorizerResponse RestApiAuthorize( + APIGatewayCustomAuthorizerRequest request, + ILambdaContext context) + { + context.Logger.LogLine($"REST API Authorizer invoked"); + context.Logger.LogLine($"Authorization token: {request.AuthorizationToken}"); + context.Logger.LogLine($"Method ARN: {request.MethodArn}"); + + // Only authorize if the token is in our allow list + if (!ValidTokens.Contains(request.AuthorizationToken ?? "")) + { + context.Logger.LogLine("Denying request - no valid token found"); + return GenerateDenyPolicy("user", request.MethodArn); + } + + context.Logger.LogLine("Authorizing request with valid token"); + + // Parse the method ARN to create a policy + // Format: arn:aws:execute-api:{region}:{accountId}:{apiId}/{stage}/{method}/{resourcePath} + var arnParts = request.MethodArn.Split(':'); + var apiGatewayArnPart = arnParts[5].Split('/'); + var region = arnParts[3]; + var accountId = arnParts[4]; + var apiId = apiGatewayArnPart[0]; + var stage = apiGatewayArnPart[1]; + + // Create policy allowing all methods on this API + var resourceArn = $"arn:aws:execute-api:{region}:{accountId}:{apiId}/{stage}/*"; + + return new APIGatewayCustomAuthorizerResponse + { + PrincipalID = "user-12345", + PolicyDocument = new APIGatewayCustomAuthorizerPolicy + { + Version = "2012-10-17", + Statement = new List + { + new APIGatewayCustomAuthorizerPolicy.IAMPolicyStatement + { + Action = new HashSet { "execute-api:Invoke" }, + Effect = "Allow", + Resource = new HashSet { resourceArn } + } + } + }, + Context = new APIGatewayCustomAuthorizerContextOutput + { + // REST API context values are automatically converted to strings + ["userId"] = "user-12345", + ["tenantId"] = "42", + ["userRole"] = "admin", + ["email"] = "test@example.com" + } + }; + } + + private APIGatewayCustomAuthorizerResponse GenerateDenyPolicy(string principalId, string methodArn) + { + return new APIGatewayCustomAuthorizerResponse + { + PrincipalID = principalId, + PolicyDocument = new APIGatewayCustomAuthorizerPolicy + { + Version = "2012-10-17", + Statement = new List + { + new APIGatewayCustomAuthorizerPolicy.IAMPolicyStatement + { + Action = new HashSet { "execute-api:Invoke" }, + Effect = "Deny", + Resource = new HashSet { methodArn } + } + } + } + }; + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp/ProtectedFunction.cs b/Libraries/test/TestCustomAuthorizerApp/ProtectedFunction.cs new file mode 100644 index 000000000..f184055ec --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp/ProtectedFunction.cs @@ -0,0 +1,192 @@ +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Core; +using System.Text.Json; + +namespace TestCustomAuthorizerApp; + +/// +/// Lambda functions that demonstrate the [FromCustomAuthorizer] attribute. +/// These functions are protected by the custom authorizer and receive context values +/// that were set by the authorizer. +/// +public class ProtectedFunction +{ + /// + /// Debug endpoint to see what's in the RequestContext.Authorizer + /// + [LambdaFunction(ResourceName = "ProtectedEndpoint")] + [HttpApi(LambdaHttpMethod.Get, "/api/protected")] + public string GetProtectedData( + APIGatewayHttpApiV2ProxyRequest request, + ILambdaContext context) + { + // Debug: Log the entire authorizer context + context.Logger.LogLine("=== DEBUG: Checking RequestContext.Authorizer ==="); + + if (request.RequestContext?.Authorizer == null) + { + context.Logger.LogLine("RequestContext.Authorizer is NULL"); + return "ERROR: Authorizer context is null"; + } + + context.Logger.LogLine($"Authorizer object exists"); + + // Check the Lambda dictionary specifically + if (request.RequestContext.Authorizer.Lambda == null) + { + context.Logger.LogLine("RequestContext.Authorizer.Lambda is NULL"); + } + else + { + context.Logger.LogLine($"Lambda dictionary has {request.RequestContext.Authorizer.Lambda.Count} entries"); + foreach (var kvp in request.RequestContext.Authorizer.Lambda) + { + context.Logger.LogLine($" Lambda[\"{kvp.Key}\"] = {kvp.Value} (Type: {kvp.Value?.GetType().Name ?? "null"})"); + } + } + + // Check JWT authorizer + if (request.RequestContext.Authorizer.Jwt != null) + { + context.Logger.LogLine("JWT authorizer context found"); + } + + // Log the raw JSON for the full request context + try + { + var authorizerJson = JsonSerializer.Serialize(request.RequestContext.Authorizer); + context.Logger.LogLine($"Full Authorizer JSON: {authorizerJson}"); + } + catch (Exception ex) + { + context.Logger.LogLine($"Error serializing authorizer: {ex.Message}"); + } + + // Try to get context values if Lambda dictionary exists + if (request.RequestContext.Authorizer.Lambda != null) + { + var userId = request.RequestContext.Authorizer.Lambda.ContainsKey("userId") + ? request.RequestContext.Authorizer.Lambda["userId"]?.ToString() + : "NOT_FOUND"; + var tenantId = request.RequestContext.Authorizer.Lambda.ContainsKey("tenantId") + ? request.RequestContext.Authorizer.Lambda["tenantId"]?.ToString() + : "NOT_FOUND"; + var userRole = request.RequestContext.Authorizer.Lambda.ContainsKey("userRole") + ? request.RequestContext.Authorizer.Lambda["userRole"]?.ToString() + : "NOT_FOUND"; + + return $"Found context - userId: {userId}, tenantId: {tenantId}, userRole: {userRole}"; + } + + return "Lambda authorizer context not found in request"; + } + + /// + /// Another protected endpoint showing different usage - just getting the email. + /// + [LambdaFunction(ResourceName = "GetUserInfo")] + [HttpApi(LambdaHttpMethod.Get, "/api/user-info")] + public object GetUserInfo( + [FromCustomAuthorizer(Name = "userId")] string userId, + [FromCustomAuthorizer(Name = "email")] string email, + [FromCustomAuthorizer(Name = "tenantId")] string tenantId, + ILambdaContext context) + { + context.Logger.LogLine($"Getting user info for: {userId}"); + + // Return a JSON object with user information + return new + { + UserId = userId, + Email = email, + TenantId = tenantId, + Message = "This data came from the custom authorizer context!" + }; + } + + /// + /// Simple health check endpoint (no authorizer required for comparison) + /// + [LambdaFunction(ResourceName = "HealthCheck")] + [HttpApi(LambdaHttpMethod.Get, "/api/health")] + public string HealthCheck(ILambdaContext context) + { + context.Logger.LogLine("Health check called"); + return "OK"; + } + + /// + /// REST API endpoint demonstrating [FromCustomAuthorizer] with REST API authorizer. + /// REST API authorizers use a different context structure than HTTP API v2. + /// + [LambdaFunction(ResourceName = "RestUserInfo")] + [RestApi(LambdaHttpMethod.Get, "/api/rest-user-info")] + public object GetRestUserInfo( + [FromCustomAuthorizer(Name = "userId")] string userId, + [FromCustomAuthorizer(Name = "email")] string email, + [FromCustomAuthorizer(Name = "tenantId")] string tenantId, + ILambdaContext context) + { + context.Logger.LogLine($"[REST API] Getting user info for: {userId}"); + + // Return a JSON object with user information + return new + { + UserId = userId, + Email = email, + TenantId = tenantId, + ApiType = "REST API", + Message = "This data came from the REST API custom authorizer context!" + }; + } + + /// + /// HTTP API v1 endpoint demonstrating [FromCustomAuthorizer] with HTTP API v1 (payload format 1.0). + /// HTTP API v1 uses the same request structure as REST API (APIGatewayProxyRequest) + /// where RequestContext.Authorizer is a dictionary, not RequestContext.Authorizer.Lambda. + /// + [LambdaFunction(ResourceName = "HttpApiV1UserInfo")] + [HttpApi(LambdaHttpMethod.Get, "/api/http-v1-user-info", Version = HttpApiVersion.V1)] + public object GetHttpApiV1UserInfo( + [FromCustomAuthorizer(Name = "userId")] string userId, + [FromCustomAuthorizer(Name = "email")] string email, + [FromCustomAuthorizer(Name = "tenantId")] string tenantId, + ILambdaContext context) + { + context.Logger.LogLine($"[HTTP API V1] Getting user info for: {userId}"); + + // Return a JSON object with user information + return new + { + UserId = userId, + Email = email, + TenantId = tenantId, + ApiType = "HTTP API V1", + Message = "This data came from the HTTP API v1 custom authorizer context!" + }; + } + + /// + /// Demonstrates [FromCustomAuthorizer] with IHttpResult return type. + /// This tests that the generated handler properly serializes 401 responses + /// when authorizer context is missing (the handler returns Stream, not response object). + /// + [LambdaFunction(ResourceName = "IHttpResultUserInfo")] + [HttpApi(LambdaHttpMethod.Get, "/api/ihttpresult-user-info")] + public IHttpResult GetIHttpResult( + [FromCustomAuthorizer(Name = "userId")] string userId, + [FromCustomAuthorizer(Name = "email")] string email, + ILambdaContext context) + { + context.Logger.LogLine($"[IHttpResult] Getting user info for: {userId}"); + + return HttpResults.Ok(new + { + UserId = userId, + Email = email, + Message = "Success with IHttpResult return type!" + }); + } +} diff --git a/Libraries/test/TestCustomAuthorizerApp/README.md b/Libraries/test/TestCustomAuthorizerApp/README.md new file mode 100644 index 000000000..d79b5141b --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp/README.md @@ -0,0 +1,178 @@ +# TestCustomAuthorizerApp + +This test application demonstrates the `[FromCustomAuthorizer]` attribute functionality in AWS Lambda Annotations. + +## What This Demonstrates + +- **Custom Lambda Authorizer**: A Lambda function that authenticates requests and returns context values +- **Protected Lambda Functions**: Functions that use `[FromCustomAuthorizer]` to extract values set by the authorizer + +## Prerequisites + +1. AWS CLI configured with credentials +2. .NET 8 SDK installed +3. Amazon.Lambda.Tools installed: + ```bash + dotnet tool install -g Amazon.Lambda.Tools + ``` +4. An S3 bucket for deployment artifacts + +## Project Structure + +``` +TestCustomAuthorizerApp/ +├── AuthorizerFunction.cs # Custom Lambda authorizer +├── ProtectedFunction.cs # Functions using [FromCustomAuthorizer] +├── serverless.template # CloudFormation template with API Gateway +├── aws-lambda-tools-defaults.json +└── README.md +``` + +## How It Works + +### 1. Custom Authorizer (`AuthorizerFunction.cs`) + +The authorizer Lambda: +- Receives the API Gateway request +- Validates the request (in this demo, it always authorizes unless `Authorization: deny`) +- Returns context values that are passed to the downstream Lambda: + ```csharp + Context = new Dictionary + { + { "userId", "user-12345" }, + { "tenantId", 42 }, + { "userRole", "admin" }, + { "email", "test@example.com" } + } + ``` + +### 2. Protected Functions (`ProtectedFunction.cs`) + +The protected functions use `[FromCustomAuthorizer]` to extract these values: +```csharp +[LambdaFunction] +[HttpApi(LambdaHttpMethod.Get, "/api/protected")] +public string GetProtectedData( + [FromCustomAuthorizer(Name = "userId")] string userId, + [FromCustomAuthorizer(Name = "tenantId")] int tenantId, + [FromCustomAuthorizer(Name = "userRole")] string userRole, + ILambdaContext context) +{ + return $"Hello {userId}! You are a {userRole} in tenant {tenantId}."; +} +``` + +## Deployment + +### Step 1: Build the project + +```bash +cd Libraries/test/TestCustomAuthorizerApp +dotnet build +``` + +### Step 2: Deploy to AWS + +Replace `YOUR_S3_BUCKET` with your bucket name: + +```bash +dotnet lambda deploy-serverless --s3-bucket YOUR_S3_BUCKET +``` + +Or specify all parameters: + +```bash +dotnet lambda deploy-serverless \ + --stack-name test-custom-authorizer \ + --s3-bucket YOUR_S3_BUCKET \ + --region us-east-1 +``` + +### Step 3: Get the API URL + +After deployment, the output will show the API URL: + +``` +Outputs: + ApiUrl: https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com + ProtectedEndpointUrl: https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/protected + UserInfoUrl: https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/user-info + HealthCheckUrl: https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/health +``` + +## Testing + +### Test Health Check (No Auth Required) + +```bash +curl https://YOUR_API_URL/api/health +# Response: "OK" +``` + +### Test Protected Endpoint (With Authorization) + +```bash +curl -H "Authorization: my-token" https://YOUR_API_URL/api/protected +# Response: "Hello user-12345! You are a admin in tenant 42." +``` + +### Test User Info Endpoint + +```bash +curl -H "Authorization: any-value" https://YOUR_API_URL/api/user-info +# Response: {"userId":"user-12345","email":"test@example.com","tenantId":42,"message":"This data came from the custom authorizer context!"} +``` + +### Test Authorization Denial + +```bash +curl -H "Authorization: deny" https://YOUR_API_URL/api/protected +# Response: 403 Forbidden (authorizer denies requests with "deny" token) +``` + +### Test Missing Authorization Header + +```bash +curl https://YOUR_API_URL/api/protected +# Response: 401 Unauthorized (missing Authorization header) +``` + +## Cleanup + +To delete the deployed resources: + +```bash +dotnet lambda delete-serverless --stack-name test-custom-authorizer +``` + +Or via AWS CLI: + +```bash +aws cloudformation delete-stack --stack-name test-custom-authorizer +``` + +## Troubleshooting + +### "Handler not found" error +Make sure you built the project in Release mode: +```bash +dotnet build -c Release +``` + +### Authorizer returns 500 error +Check the authorizer Lambda logs in CloudWatch for detailed error messages. + +### 401 Unauthorized even with Authorization header +The HTTP API authorizer expects the header specified in `IdentitySource`. Make sure you're using the `Authorization` header. + +## Key Points About `[FromCustomAuthorizer]` + +1. **HTTP API vs REST API**: The authorizer context location differs: + - HTTP API: `RequestContext.Authorizer.Lambda["key"]` + - REST API: `RequestContext.Authorizer["key"]` + +2. **Automatic 401 Response**: If the specified key is not found in the authorizer context, the generated code automatically returns HTTP 401 Unauthorized. + +3. **Type Conversion**: The attribute handles type conversion (e.g., string to int for `tenantId`). + +4. **Name Property**: Use `Name = "key"` when the authorizer context key differs from your parameter name. diff --git a/Libraries/test/TestCustomAuthorizerApp/TestCustomAuthorizerApp.csproj b/Libraries/test/TestCustomAuthorizerApp/TestCustomAuthorizerApp.csproj new file mode 100644 index 000000000..a9b30addb --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp/TestCustomAuthorizerApp.csproj @@ -0,0 +1,19 @@ + + + net8.0 + enable + enable + true + Lambda + + true + + + + + + + + + + diff --git a/Libraries/test/TestCustomAuthorizerApp/aws-lambda-tools-defaults.json b/Libraries/test/TestCustomAuthorizerApp/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..a9beee417 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp/aws-lambda-tools-defaults.json @@ -0,0 +1,15 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda CLI.", + "To learn more about the Lambda CLI see: https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools" + ], + "profile": "", + "region": "us-west-2", + "configuration": "Release", + "template": "serverless.template", + "template-parameters": "", +"s3-bucket" : "test-custom-authorizer-e0ed6fc4", + "s3-prefix": "TestCustomAuthorizerApp/", +"stack-name" : "test-custom-authorizer-e0ed6fc4", +"function-architecture" : "x86_64" +} diff --git a/Libraries/test/TestCustomAuthorizerApp/serverless.template b/Libraries/test/TestCustomAuthorizerApp/serverless.template new file mode 100644 index 000000000..df4dd1c99 --- /dev/null +++ b/Libraries/test/TestCustomAuthorizerApp/serverless.template @@ -0,0 +1,553 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "Test application demonstrating FromCustomAuthorizer attribute with both HTTP API and REST API Lambda Authorizers. This template is partially managed by Amazon.Lambda.Annotations (v1.8.0.0).", + "Globals": { + "Function": { + "Runtime": "dotnet8", + "MemorySize": 512, + "Timeout": 30, + "CodeUri": "." + } + }, + "Resources": { + "CustomAuthorizer": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.AuthorizerFunction::HttpApiAuthorize", + "Description": "Lambda Authorizer that validates requests and provides custom context values", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "CustomAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "CustomAuthorizer" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessHttpApi}/authorizers/*" + } + } + }, + "ServerlessHttpApi": { + "Type": "AWS::ApiGatewayV2::Api", + "Properties": { + "Name": "TestCustomAuthorizerApi", + "ProtocolType": "HTTP", + "Description": "HTTP API with custom Lambda authorizer for testing FromCustomAuthorizer attribute" + } + }, + "HttpApiAuthorizer": { + "Type": "AWS::ApiGatewayV2::Authorizer", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "AuthorizerType": "REQUEST", + "AuthorizerUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CustomAuthorizer.Arn}/invocations" + }, + "AuthorizerPayloadFormatVersion": "2.0", + "EnableSimpleResponses": true, + "IdentitySource": [ + "$request.header.authorization" + ], + "Name": "CustomLambdaAuthorizer" + } + }, + "ProtectedEndpoint": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.ProtectedFunction_GetProtectedData_Generated::GetProtectedData", + "Description": "Protected endpoint demonstrating FromCustomAuthorizer attribute", + "PackageType": "Zip", + "CodeUri": ".", + "Runtime": "dotnet8", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "ProtectedEndpointPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "ProtectedEndpoint" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessHttpApi}/*/*/api/protected" + } + } + }, + "ProtectedEndpointIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "ProtectedEndpoint", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0" + } + }, + "ProtectedEndpointRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "RouteKey": "GET /api/protected", + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizer" + }, + "Target": { + "Fn::Sub": "integrations/${ProtectedEndpointIntegration}" + } + } + }, + "GetUserInfo": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.ProtectedFunction_GetUserInfo_Generated::GetUserInfo", + "Description": "Returns user info from custom authorizer context", + "PackageType": "Zip", + "CodeUri": ".", + "Runtime": "dotnet8", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "GetUserInfoPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "GetUserInfo" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessHttpApi}/*/*/api/user-info" + } + } + }, + "GetUserInfoIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "GetUserInfo", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0" + } + }, + "GetUserInfoRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "RouteKey": "GET /api/user-info", + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizer" + }, + "Target": { + "Fn::Sub": "integrations/${GetUserInfoIntegration}" + } + } + }, + "HealthCheck": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.ProtectedFunction_HealthCheck_Generated::HealthCheck", + "Description": "Simple health check endpoint without authorizer", + "PackageType": "Zip", + "CodeUri": ".", + "Runtime": "dotnet8", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "HealthCheckPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "HealthCheck" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessHttpApi}/*/*/api/health" + } + } + }, + "HealthCheckIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "HealthCheck", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0" + } + }, + "HealthCheckRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "RouteKey": "GET /api/health", + "Target": { + "Fn::Sub": "integrations/${HealthCheckIntegration}" + } + } + }, + "HttpApiStage": { + "Type": "AWS::ApiGatewayV2::Stage", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "StageName": "$default", + "AutoDeploy": true + } + }, + "RestApiAuthorizer": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.AuthorizerFunction::RestApiAuthorize", + "Description": "REST API Lambda Authorizer that validates requests and provides custom context values", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "TestCustomAuthorizerRestApi", + "Description": "REST API with custom Lambda authorizer for testing FromCustomAuthorizer attribute" + } + }, + "RestApiLambdaAuthorizer": { + "Type": "AWS::ApiGateway::Authorizer", + "Properties": { + "Name": "RestApiLambdaAuthorizer", + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Type": "TOKEN", + "AuthorizerUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RestApiAuthorizer.Arn}/invocations" + }, + "IdentitySource": "method.request.header.Authorization" + } + }, + "RestApiAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "RestApiAuthorizer" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessRestApi}/authorizers/*" + } + } + }, + "RestUserInfo": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.ProtectedFunction_GetRestUserInfo_Generated::GetRestUserInfo", + "Description": "REST API endpoint demonstrating FromCustomAuthorizer attribute", + "PackageType": "Zip", + "CodeUri": ".", + "Runtime": "dotnet8", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "RestUserInfoPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "RestUserInfo" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessRestApi}/*/*/*" + } + } + }, + "RestApiResource": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "ParentId": { + "Fn::GetAtt": [ + "ServerlessRestApi", + "RootResourceId" + ] + }, + "PathPart": "api" + } + }, + "RestApiUserInfoResource": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "ParentId": { + "Ref": "RestApiResource" + }, + "PathPart": "rest-user-info" + } + }, + "RestApiUserInfoMethod": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "ResourceId": { + "Ref": "RestApiUserInfoResource" + }, + "HttpMethod": "GET", + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "RestApiLambdaAuthorizer" + }, + "Integration": { + "Type": "AWS_PROXY", + "IntegrationHttpMethod": "POST", + "Uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RestUserInfo.Arn}/invocations" + } + } + } + }, + "RestApiDeployment": { + "Type": "AWS::ApiGateway::Deployment", + "DependsOn": [ + "RestApiUserInfoMethod" + ], + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + } + } + }, + "RestApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "DeploymentId": { + "Ref": "RestApiDeployment" + }, + "StageName": "Prod" + } + }, + "HttpApiV1UserInfo": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.ProtectedFunction_GetHttpApiV1UserInfo_Generated::GetHttpApiV1UserInfo", + "Description": "HTTP API v1 endpoint demonstrating FromCustomAuthorizer attribute with payload format 1.0", + "PackageType": "Zip", + "CodeUri": ".", + "Runtime": "dotnet8", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "HttpApiV1UserInfoPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "HttpApiV1UserInfo" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessHttpApi}/*/*/api/http-v1-user-info" + } + } + }, + "HttpApiV1UserInfoIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "HttpApiV1UserInfo", + "Arn" + ] + }, + "PayloadFormatVersion": "1.0" + } + }, + "HttpApiV1UserInfoRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "RouteKey": "GET /api/http-v1-user-info", + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizer" + }, + "Target": { + "Fn::Sub": "integrations/${HttpApiV1UserInfoIntegration}" + } + } + }, + "IHttpResultUserInfo": { + "Type": "AWS::Serverless::Function", + "Properties": { + "Handler": "TestCustomAuthorizerApp::TestCustomAuthorizerApp.ProtectedFunction_GetIHttpResult_Generated::GetIHttpResult", + "Description": "IHttpResult endpoint demonstrating FromCustomAuthorizer with IHttpResult return type", + "PackageType": "Zip", + "CodeUri": ".", + "Runtime": "dotnet8", + "Policies": [ + "AWSLambdaBasicExecutionRole" + ] + } + }, + "IHttpResultUserInfoPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "IHttpResultUserInfo" + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerlessHttpApi}/*/*/api/ihttpresult-user-info" + } + } + }, + "IHttpResultUserInfoIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "IHttpResultUserInfo", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0" + } + }, + "IHttpResultUserInfoRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "ServerlessHttpApi" + }, + "RouteKey": "GET /api/ihttpresult-user-info", + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizer" + }, + "Target": { + "Fn::Sub": "integrations/${IHttpResultUserInfoIntegration}" + } + } + } + }, + "Outputs": { + "ApiUrl": { + "Description": "HTTP API endpoint URL", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" + } + }, + "ProtectedEndpointUrl": { + "Description": "Protected endpoint URL (requires Authorization header)", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/api/protected" + } + }, + "UserInfoUrl": { + "Description": "User info endpoint URL (requires Authorization header)", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/api/user-info" + } + }, + "HealthCheckUrl": { + "Description": "Health check endpoint URL (no auth required)", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/api/health" + } + }, + "RestApiUrl": { + "Description": "REST API endpoint URL", + "Value": { + "Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod" + } + }, + "RestUserInfoUrl": { + "Description": "REST API User info endpoint URL (requires Authorization header)", + "Value": { + "Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/api/rest-user-info" + } + }, + "HttpApiV1UserInfoUrl": { + "Description": "HTTP API v1 User info endpoint URL (requires Authorization header, uses payload format 1.0)", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/api/http-v1-user-info" + } + }, + "IHttpResultUserInfoUrl": { + "Description": "IHttpResult User info endpoint URL (requires Authorization header, demonstrates IHttpResult return type)", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/api/ihttpresult-user-info" + } + } + } +} \ No newline at end of file diff --git a/Libraries/test/TestExecutableServerlessApp/serverless.template b/Libraries/test/TestExecutableServerlessApp/serverless.template index 740184c32..fcee0d176 100644 --- a/Libraries/test/TestExecutableServerlessApp/serverless.template +++ b/Libraries/test/TestExecutableServerlessApp/serverless.template @@ -22,6 +22,31 @@ } }, "Resources": { + "TestServerlessAppTaskExampleTaskReturnGenerated": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations" + }, + "Properties": { + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Image", + "ImageUri": ".", + "ImageConfig": { + "Command": [ + "TestExecutableServerlessApp" + ] + }, + "Environment": { + "Variables": { + "ANNOTATIONS_HANDLER": "TaskReturn" + } + } + } + }, "TestServerlessAppCustomizeResponseExamplesOkResponseWithHeaderGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { @@ -284,56 +309,6 @@ } } }, - "TestServerlessAppDynamicExampleDynamicReturnGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestExecutableServerlessApp" - ] - }, - "Environment": { - "Variables": { - "ANNOTATIONS_HANDLER": "DynamicReturn" - } - } - } - }, - "TestServerlessAppDynamicExampleDynamicInputGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestExecutableServerlessApp" - ] - }, - "Environment": { - "Variables": { - "ANNOTATIONS_HANDLER": "DynamicInput" - } - } - } - }, "GreeterSayHello": { "Type": "AWS::Serverless::Function", "Metadata": { @@ -424,7 +399,7 @@ } } }, - "TestServerlessAppIntrinsicExampleHasIntrinsicGenerated": { + "TestServerlessAppVoidExampleVoidReturnGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations" @@ -444,55 +419,34 @@ }, "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "HasIntrinsic" + "ANNOTATIONS_HANDLER": "VoidReturn" } } } }, - "TestServerlessAppNullableReferenceTypeExampleNullableHeaderHttpApiGenerated": { + "TestServerlessAppParameterlessMethodsNoParameterGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } + "Tool": "Amazon.Lambda.Annotations" }, "Properties": { + "Runtime": "provided.al2", + "CodeUri": ".", "MemorySize": 512, "Timeout": 30, "Policies": [ "AWSLambdaBasicExecutionRole" ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestExecutableServerlessApp" - ] - }, + "PackageType": "Zip", + "Handler": "TestExecutableServerlessApp", "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "NullableHeaderHttpApi" - } - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/nullableheaderhttpapi", - "Method": "GET" - } + "ANNOTATIONS_HANDLER": "NoParameter" } } } }, - "TestServerlessAppParameterlessMethodsNoParameterGenerated": { + "TestServerlessAppParameterlessMethodWithResponseNoParameterWithResponseGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations" @@ -509,12 +463,37 @@ "Handler": "TestExecutableServerlessApp", "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "NoParameter" + "ANNOTATIONS_HANDLER": "NoParameterWithResponse" } } } }, - "TestServerlessAppParameterlessMethodWithResponseNoParameterWithResponseGenerated": { + "TestServerlessAppIntrinsicExampleHasIntrinsicGenerated": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations" + }, + "Properties": { + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Image", + "ImageUri": ".", + "ImageConfig": { + "Command": [ + "TestExecutableServerlessApp" + ] + }, + "Environment": { + "Variables": { + "ANNOTATIONS_HANDLER": "HasIntrinsic" + } + } + } + }, + "ToLower": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations" @@ -531,12 +510,12 @@ "Handler": "TestExecutableServerlessApp", "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "NoParameterWithResponse" + "ANNOTATIONS_HANDLER": "ToLower" } } } }, - "TestExecutableServerlessAppSourceGenerationSerializationExampleGetPersonGenerated": { + "TestServerlessAppNullableReferenceTypeExampleNullableHeaderHttpApiGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations", @@ -565,24 +544,33 @@ }, "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "GetPerson" + "ANNOTATIONS_HANDLER": "NullableHeaderHttpApi" } }, "Events": { "RootGet": { - "Type": "Api", + "Type": "HttpApi", "Properties": { - "Path": "/", + "Path": "/nullableheaderhttpapi", "Method": "GET" } } } } }, - "ToUpper": { + "TestExecutableServerlessAppSourceGenerationSerializationExampleGetPersonGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { - "Tool": "Amazon.Lambda.Annotations" + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } }, "Properties": { "MemorySize": 512, @@ -599,34 +587,46 @@ }, "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "ToUpper" + "ANNOTATIONS_HANDLER": "GetPerson" + } + }, + "Events": { + "RootGet": { + "Type": "Api", + "Properties": { + "Path": "/", + "Method": "GET" + } } } } }, - "ToLower": { + "TestServerlessAppDynamicExampleDynamicReturnGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations" }, "Properties": { - "Runtime": "provided.al2", - "CodeUri": ".", "MemorySize": 512, "Timeout": 30, "Policies": [ "AWSLambdaBasicExecutionRole" ], - "PackageType": "Zip", - "Handler": "TestExecutableServerlessApp", + "PackageType": "Image", + "ImageUri": ".", + "ImageConfig": { + "Command": [ + "TestExecutableServerlessApp" + ] + }, "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "ToLower" + "ANNOTATIONS_HANDLER": "DynamicReturn" } } } }, - "TestServerlessAppTaskExampleTaskReturnGenerated": { + "TestServerlessAppDynamicExampleDynamicInputGenerated": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations" @@ -646,12 +646,12 @@ }, "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "TaskReturn" + "ANNOTATIONS_HANDLER": "DynamicInput" } } } }, - "TestServerlessAppVoidExampleVoidReturnGenerated": { + "ToUpper": { "Type": "AWS::Serverless::Function", "Metadata": { "Tool": "Amazon.Lambda.Annotations" @@ -671,7 +671,7 @@ }, "Environment": { "Variables": { - "ANNOTATIONS_HANDLER": "VoidReturn" + "ANNOTATIONS_HANDLER": "ToUpper" } } } diff --git a/Libraries/test/TestServerlessApp.IntegrationTests/IntegrationTestContextFixture.cs b/Libraries/test/TestServerlessApp.IntegrationTests/IntegrationTestContextFixture.cs index cbae5fd6a..c2fa5139c 100644 --- a/Libraries/test/TestServerlessApp.IntegrationTests/IntegrationTestContextFixture.cs +++ b/Libraries/test/TestServerlessApp.IntegrationTests/IntegrationTestContextFixture.cs @@ -7,9 +7,9 @@ using Amazon.CloudWatchLogs; using Amazon.Lambda; using Amazon.S3; +using IntegrationTests.Helpers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using TestServerlessApp.IntegrationTests.Helpers; using Xunit; namespace TestServerlessApp.IntegrationTests @@ -96,4 +96,4 @@ private string GetBucketName() return token.ToObject(); } } -} \ No newline at end of file +} diff --git a/Libraries/test/TestServerlessApp.IntegrationTests/TestServerlessApp.IntegrationTests.csproj b/Libraries/test/TestServerlessApp.IntegrationTests/TestServerlessApp.IntegrationTests.csproj index 13d185a5b..5f0728358 100644 --- a/Libraries/test/TestServerlessApp.IntegrationTests/TestServerlessApp.IntegrationTests.csproj +++ b/Libraries/test/TestServerlessApp.IntegrationTests/TestServerlessApp.IntegrationTests.csproj @@ -6,13 +6,10 @@ - - - - + all @@ -20,4 +17,8 @@ - \ No newline at end of file + + + + + diff --git a/Libraries/test/TestServerlessApp/AuthNameFallback.cs b/Libraries/test/TestServerlessApp/AuthNameFallback.cs new file mode 100644 index 000000000..582ea0e79 --- /dev/null +++ b/Libraries/test/TestServerlessApp/AuthNameFallback.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + /// + /// Tests the fallback behavior where [FromCustomAuthorizer] is used without the Name property, + /// so the parameter name is used as the authorizer context key instead. + /// + public class AuthNameFallback + { + /// + /// When Name is not specified on [FromCustomAuthorizer], the parameter name 'userId' + /// should be used as the key to look up in the authorizer context. + /// + [LambdaFunction(ResourceName = "AuthNameFallbackTest")] + [HttpApi(LambdaHttpMethod.Get, "/api/authorizer-fallback")] + public async Task GetUserId([FromCustomAuthorizer] string userId, ILambdaContext context) + { + context.Logger.LogLine($"User ID from authorizer: {userId}"); + await Task.CompletedTask; + } + } +} diff --git a/Libraries/test/TestServerlessApp/CustomAuthorizerHttpApiExample.cs b/Libraries/test/TestServerlessApp/CustomAuthorizerHttpApiExample.cs new file mode 100644 index 000000000..7754a189f --- /dev/null +++ b/Libraries/test/TestServerlessApp/CustomAuthorizerHttpApiExample.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerHttpApiExample + { + [LambdaFunction(ResourceName = "HttpApiAuthorizerTest", PackageType = LambdaPackageType.Image)] + [HttpApi(LambdaHttpMethod.Get, "/api/authorizer")] + public async Task HttpApiAuthorizer([FromCustomAuthorizer(Name = "authKey")] string authorizerValue, ILambdaContext context) + { + context.Logger.LogLine(authorizerValue); + await Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Libraries/test/TestServerlessApp/CustomAuthorizerHttpApiV1Example.cs b/Libraries/test/TestServerlessApp/CustomAuthorizerHttpApiV1Example.cs new file mode 100644 index 000000000..0fe70bfee --- /dev/null +++ b/Libraries/test/TestServerlessApp/CustomAuthorizerHttpApiV1Example.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerHttpApiV1Example + { + [LambdaFunction(ResourceName = "HttpApiV1AuthorizerTest", PackageType = LambdaPackageType.Image)] + [HttpApi(LambdaHttpMethod.Get, "/api/authorizer-v1", Version = HttpApiVersion.V1)] + public async Task HttpApiV1Authorizer([FromCustomAuthorizer(Name = "authKey")] string authorizerValue, ILambdaContext context) + { + context.Logger.LogLine(authorizerValue); + await Task.CompletedTask; + } + } +} diff --git a/Libraries/test/TestServerlessApp/CustomAuthorizerRestExample.cs b/Libraries/test/TestServerlessApp/CustomAuthorizerRestExample.cs new file mode 100644 index 000000000..8779fa283 --- /dev/null +++ b/Libraries/test/TestServerlessApp/CustomAuthorizerRestExample.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerRestExample + { + [LambdaFunction(ResourceName = "RestAuthorizerTest", PackageType = LambdaPackageType.Image)] + [RestApi(LambdaHttpMethod.Get, "/rest/authorizer")] + public async Task RestAuthorizer([FromCustomAuthorizer(Name = "theAuthKey")] string authorizerValue, ILambdaContext context) + { + context.Logger.LogLine(authorizerValue); + await Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Libraries/test/TestServerlessApp/CustomAuthorizerWithIHttpResultsExample.cs b/Libraries/test/TestServerlessApp/CustomAuthorizerWithIHttpResultsExample.cs new file mode 100644 index 000000000..23e9acc3f --- /dev/null +++ b/Libraries/test/TestServerlessApp/CustomAuthorizerWithIHttpResultsExample.cs @@ -0,0 +1,18 @@ +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.Core; + +namespace TestServerlessApp +{ + public class CustomAuthorizerWithIHttpResultsExample + { + [LambdaFunction(PackageType = LambdaPackageType.Image)] + [HttpApi(LambdaHttpMethod.Get, "/authorizerihttpresults")] + public IHttpResult AuthorizerWithIHttpResults( + [FromCustomAuthorizer(Name = "userId")] string userId, + ILambdaContext context) + { + return HttpResults.Ok($"Hello {userId}"); + } + } +} diff --git a/Libraries/test/TestServerlessApp/serverless.template b/Libraries/test/TestServerlessApp/serverless.template index 56bb5c15b..f07151572 100644 --- a/Libraries/test/TestServerlessApp/serverless.template +++ b/Libraries/test/TestServerlessApp/serverless.template @@ -1,973 +1,56 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Transform": "AWS::Serverless-2016-10-31", - "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.8.0.0).", - "Parameters": { - "ArchitectureTypeParameter": { - "Type": "String", - "Default": "x86_64", - "AllowedValues": [ - "x86_64", - "arm64" - ] - } - }, - "Globals": { - "Function": { - "Architectures": [ - { - "Ref": "ArchitectureTypeParameter" - } - ], - "Tags": { - "aws-tests": "TestServerlessApp", - "aws-repo": "aws-lambda-dotnet" - } - } - }, - "Resources": { - "TestQueue": { - "Type": "AWS::SQS::Queue" - }, - "TestServerlessAppComplexCalculatorAddGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootPost" - ], - "SyncedEventProperties": { - "RootPost": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.ComplexCalculator_Add_Generated::Add" - ] - }, - "Events": { - "RootPost": { - "Type": "HttpApi", - "Properties": { - "Path": "/ComplexCalculator/Add", - "Method": "POST" - } - } - } - } - }, - "TestServerlessAppComplexCalculatorSubtractGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootPost" - ], - "SyncedEventProperties": { - "RootPost": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.ComplexCalculator_Subtract_Generated::Subtract" - ] - }, - "Events": { - "RootPost": { - "Type": "HttpApi", - "Properties": { - "Path": "/ComplexCalculator/Subtract", - "Method": "POST" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesOkResponseWithHeaderGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_OkResponseWithHeader_Generated::OkResponseWithHeader" - ] - }, - "Events": { - "RootGet": { - "Type": "Api", - "Properties": { - "Path": "/okresponsewithheader/{x}", - "Method": "GET" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesOkResponseWithHeaderAsyncGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_OkResponseWithHeaderAsync_Generated::OkResponseWithHeaderAsync" - ] - }, - "Events": { - "RootGet": { - "Type": "Api", - "Properties": { - "Path": "/okresponsewithheaderasync/{x}", - "Method": "GET" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesNotFoundResponseWithHeaderV2Generated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_NotFoundResponseWithHeaderV2_Generated::NotFoundResponseWithHeaderV2" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/notfoundwithheaderv2/{x}", - "Method": "GET" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesNotFoundResponseWithHeaderV2AsyncGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_NotFoundResponseWithHeaderV2Async_Generated::NotFoundResponseWithHeaderV2Async" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/notfoundwithheaderv2async/{x}", - "Method": "GET" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesNotFoundResponseWithHeaderV1Generated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method", - "PayloadFormatVersion" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_NotFoundResponseWithHeaderV1_Generated::NotFoundResponseWithHeaderV1" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/notfoundwithheaderv1/{x}", - "Method": "GET", - "PayloadFormatVersion": "1.0" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesNotFoundResponseWithHeaderV1AsyncGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method", - "PayloadFormatVersion" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_NotFoundResponseWithHeaderV1Async_Generated::NotFoundResponseWithHeaderV1Async" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/notfoundwithheaderv1async/{x}", - "Method": "GET", - "PayloadFormatVersion": "1.0" - } - } - } - } - }, - "TestServerlessAppCustomizeResponseExamplesOkResponseWithCustomSerializerGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method", - "PayloadFormatVersion" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.CustomizeResponseExamples_OkResponseWithCustomSerializer_Generated::OkResponseWithCustomSerializer" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/okresponsewithcustomserializerasync/{firstName}/{lastName}", - "Method": "GET", - "PayloadFormatVersion": "1.0" - } - } - } - } - }, - "TestServerlessAppDynamicExampleDynamicReturnGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.DynamicExample_DynamicReturn_Generated::DynamicReturn" - ] - } - } - }, - "TestServerlessAppDynamicExampleDynamicInputGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.DynamicExample_DynamicInput_Generated::DynamicInput" - ] - } - } - }, - "TestServerlessAppFromScratchNoApiGatewayEventsReferenceToUpperGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.FromScratch.NoApiGatewayEventsReference_ToUpper_Generated::ToUpper" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/{text}", - "Method": "GET" - } - } - } - } - }, - "TestServerlessAppFromScratchNoSerializerAttributeReferenceToUpperGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.FromScratch.NoSerializerAttributeReference_ToUpper_Generated::ToUpper" - ] - } - } - }, - "GreeterSayHello": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method", - "PayloadFormatVersion" - ] - } - }, - "Properties": { - "MemorySize": 1024, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.Greeter_SayHello_Generated::SayHello" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/Greeter/SayHello", - "Method": "GET", - "PayloadFormatVersion": "1.0" - } - } - } - } - }, - "GreeterSayHelloAsync": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method", - "PayloadFormatVersion" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 50, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.Greeter_SayHelloAsync_Generated::SayHelloAsync" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/Greeter/SayHelloAsync", - "Method": "GET", - "PayloadFormatVersion": "1.0" - } - } - } - } - }, - "TestServerlessAppIntrinsicExampleHasIntrinsicGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.IntrinsicExample_HasIntrinsic_Generated::HasIntrinsic" - ] - } - } - }, - "TestServerlessAppNullableReferenceTypeExampleNullableHeaderHttpApiGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.NullableReferenceTypeExample_NullableHeaderHttpApi_Generated::NullableHeaderHttpApi" - ] - }, - "Events": { - "RootGet": { - "Type": "HttpApi", - "Properties": { - "Path": "/nullableheaderhttpapi", - "Method": "GET" - } - } - } - } - }, - "SimpleCalculatorAdd": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_Add_Generated::Add" - ] - }, - "Events": { - "RootGet": { - "Type": "Api", - "Properties": { - "Path": "/SimpleCalculator/Add", - "Method": "GET" - } - } - } - } - }, - "SimpleCalculatorSubtract": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_Subtract_Generated::Subtract" - ] - }, - "Events": { - "RootGet": { - "Type": "Api", - "Properties": { - "Path": "/SimpleCalculator/Subtract", - "Method": "GET" - } - } - } - } - }, - "SimpleCalculatorMultiply": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_Multiply_Generated::Multiply" - ] - }, - "Events": { - "RootGet": { - "Type": "Api", - "Properties": { - "Path": "/SimpleCalculator/Multiply/{x}/{y}", - "Method": "GET" - } - } - } - } - }, - "SimpleCalculatorDivideAsync": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "RootGet" - ], - "SyncedEventProperties": { - "RootGet": [ - "Path", - "Method" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_DivideAsync_Generated::DivideAsync" - ] - }, - "Events": { - "RootGet": { - "Type": "Api", - "Properties": { - "Path": "/SimpleCalculator/DivideAsync/{x}/{y}", - "Method": "GET" - } - } - } - } - }, - "PI": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_Pi_Generated::Pi" - ] - } - } - }, - "Random": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_Random_Generated::Random" - ] - } - } - }, - "Randoms": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SimpleCalculator_Randoms_Generated::Randoms" - ] - } - } - }, - "SQSMessageHandler": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations", - "SyncedEvents": [ - "TestQueueEvent" - ], - "SyncedEventProperties": { - "TestQueueEvent": [ - "Queue.Fn::GetAtt", - "BatchSize", - "FilterCriteria.Filters", - "FunctionResponseTypes", - "MaximumBatchingWindowInSeconds", - "ScalingConfig.MaximumConcurrency" - ] - } - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaSQSQueueExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.SqsMessageProcessing_HandleMessage_Generated::HandleMessage" - ] - }, - "Events": { - "TestQueueEvent": { - "Type": "SQS", - "Properties": { - "BatchSize": 50, - "FilterCriteria": { - "Filters": [ - { - "Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }" - } - ] - }, - "FunctionResponseTypes": [ - "ReportBatchItemFailures" - ], - "MaximumBatchingWindowInSeconds": 5, - "ScalingConfig": { - "MaximumConcurrency": 5 - }, - "Queue": { - "Fn::GetAtt": [ - "TestQueue", - "Arn" - ] - } - } - } - } - } - }, - "ToUpper": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.Sub1.Functions_ToUpper_Generated::ToUpper" - ] - } - } - }, - "TestServerlessAppTaskExampleTaskReturnGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.TaskExample_TaskReturn_Generated::TaskReturn" - ] - } - } - }, - "TestServerlessAppVoidExampleVoidReturnGenerated": { - "Type": "AWS::Serverless::Function", - "Metadata": { - "Tool": "Amazon.Lambda.Annotations" - }, - "Properties": { - "MemorySize": 512, - "Timeout": 30, - "Policies": [ - "AWSLambdaBasicExecutionRole" - ], - "PackageType": "Image", - "ImageUri": ".", - "ImageConfig": { - "Command": [ - "TestServerlessApp::TestServerlessApp.VoidExample_VoidReturn_Generated::VoidReturn" - ] - } - } - } - }, - "Outputs": { - "RestApiURL": { - "Description": "Rest API endpoint URL for Prod environment", - "Value": { - "Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod" - } - }, - "HttpApiURL": { - "Description": "HTTP API endpoint URL for Prod environment", - "Value": { - "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" - } - }, - "TestQueueARN": { - "Description": "ARN of the TestQueue resource", - "Value": { - "Fn::GetAtt": [ - "TestQueue", - "Arn" - ] - } - } - } +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.8.0.0).", + "Parameters": { + "ArchitectureTypeParameter": { + "Type": "String", + "Default": "x86_64", + "AllowedValues": [ + "x86_64", + "arm64" + ] + } + }, + "Globals": { + "Function": { + "Architectures": [ + { + "Ref": "ArchitectureTypeParameter" + } + ], + "Tags": { + "aws-tests": "TestServerlessApp", + "aws-repo": "aws-lambda-dotnet" + } + } + }, + "Resources": { + "TestQueue": { + "Type": "AWS::SQS::Queue" + } + }, + "Outputs": { + "RestApiURL": { + "Description": "Rest API endpoint URL for Prod environment", + "Value": { + "Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod" + } + }, + "HttpApiURL": { + "Description": "HTTP API endpoint URL for Prod environment", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" + } + }, + "TestQueueARN": { + "Description": "ARN of the TestQueue resource", + "Value": { + "Fn::GetAtt": [ + "TestQueue", + "Arn" + ] + } + } + } } \ No newline at end of file