@@ -130,6 +130,73 @@ def test_basic_function_with_url_config(self, file_name, qualifier):
130130 self .assertEqual (function_url_config ["Cors" ], cors_config )
131131 self ._assert_invoke (lambda_client , function_name , qualifier , 200 )
132132
133+ @parameterized .expand (
134+ [
135+ ("single/basic_function_with_function_url_dual_auth" , None ),
136+ ("single/basic_function_with_function_url_with_autopuplishalias_dual_auth" , "live" ),
137+ ]
138+ )
139+ @skipIf (current_region_does_not_support ([LAMBDA_URL ]), "Lambda Url is not supported in this testing region" )
140+ def test_basic_function_with_url_dual_auth (self , file_name , qualifier ):
141+ """
142+ Creates a basic lambda function with Function Url with authtype: None
143+ Verifies that 2 AWS::Lambda::Permission resources are created:
144+ - lambda:InvokeFunctionUrl
145+ - lambda:InvokeFunction with InvokedViaFunctionUrl: True
146+ """
147+ self .create_and_verify_stack (file_name )
148+
149+ # Get Lambda permissions
150+ lambda_permissions = self .get_stack_resources ("AWS::Lambda::Permission" )
151+
152+ # Verify we have exactly 2 permissions
153+ self .assertEqual (len (lambda_permissions ), 2 , "Expected exactly 2 Lambda permissions" )
154+
155+ # Check for the expected permission logical IDs
156+ invoke_function_url_permission = None
157+ invoke_permission = None
158+
159+ for permission in lambda_permissions :
160+ logical_id = permission ["LogicalResourceId" ]
161+ if "MyLambdaFunctionUrlPublicPermissions" in logical_id :
162+ invoke_function_url_permission = permission
163+ elif "MyLambdaFunctionURLInvokeAllowPublicAccess" in logical_id :
164+ invoke_permission = permission
165+
166+ # Verify both permissions exist
167+ self .assertIsNotNone (invoke_function_url_permission , "Expected MyLambdaFunctionUrlPublicPermissions to exist" )
168+ self .assertIsNotNone (invoke_permission , "Expected MyLambdaFunctionURLInvokeAllowPublicAccess to exist" )
169+
170+ # Get the function name and URL
171+ function_name = self .get_physical_id_by_type ("AWS::Lambda::Function" )
172+ lambda_client = self .client_provider .lambda_client
173+
174+ # Get the function URL configuration to verify auth type
175+ function_url_config = (
176+ lambda_client .get_function_url_config (FunctionName = function_name , Qualifier = qualifier )
177+ if qualifier
178+ else lambda_client .get_function_url_config (FunctionName = function_name )
179+ )
180+
181+ # Verify the auth type is NONE
182+ self .assertEqual (function_url_config ["AuthType" ], "NONE" , "Expected AuthType to be NONE" )
183+
184+ # Get the template to check for InvokedViaFunctionUrl property
185+ cfn_client = self .client_provider .cfn_client
186+ template = cfn_client .get_template (StackName = self .stack_name , TemplateStage = "Processed" )
187+ template_body = template ["TemplateBody" ]
188+
189+ # Check if the InvokePermission has InvokedViaFunctionUrl: True
190+ # This is a bit hacky but we don't have direct access to the resource properties
191+ # We're checking if the string representation of the template contains this property
192+ template_str = str (template_body )
193+ self .assertIn ("InvokedViaFunctionUrl" , template_str , "Expected InvokedViaFunctionUrl property in the template" )
194+
195+ # Get the function URL from stack outputs
196+ function_url = self .get_stack_output ("FunctionUrl" )["OutputValue" ]
197+ # Invoke the function URL and verify the response
198+ self ._verify_get_request (function_url , self .FUNCTION_OUTPUT )
199+
133200 @skipIf (current_region_does_not_support ([CODE_DEPLOY ]), "CodeDeploy is not supported in this testing region" )
134201 def test_function_with_deployment_preference_alarms_intrinsic_if (self ):
135202 self .create_and_verify_stack ("single/function_with_deployment_preference_alarms_intrinsic_if" )
0 commit comments