diff --git a/samtranslator/model/api/http_api_generator.py b/samtranslator/model/api/http_api_generator.py index 2c57d86a58..6326609f49 100644 --- a/samtranslator/model/api/http_api_generator.py +++ b/samtranslator/model/api/http_api_generator.py @@ -397,34 +397,45 @@ def _construct_alias_target(self, domain): def _add_auth(self): """ - Add Auth configuration to the OAS file, if necessary + Add Auth configuration to the OAS file. In order to support the built-in AWS_IAM authorizer it is always added. """ - if not self.auth: - return - - if self.auth and not self.definition_body: + if not self.definition_body: raise InvalidResourceException( self.logical_id, "Auth works only with inline OpenApi specified in the 'DefinitionBody' property." ) - # Make sure keys in the dict are recognized - if not all(key in AuthProperties._fields for key in self.auth.keys()): - raise InvalidResourceException(self.logical_id, "Invalid value for 'Auth' property") - if not OpenApiEditor.is_valid(self.definition_body): raise InvalidResourceException( self.logical_id, "Unable to add Auth configuration because 'DefinitionBody' does not contain a valid OpenApi definition.", ) + open_api_editor = OpenApiEditor(self.definition_body) - auth_properties = AuthProperties(**self.auth) - authorizers = self._get_authorizers(auth_properties.Authorizers, auth_properties.DefaultAuthorizer) - # authorizers is guaranteed to return a value or raise an exception - open_api_editor.add_authorizers_security_definitions(authorizers) - self._set_default_authorizer( - open_api_editor, authorizers, auth_properties.DefaultAuthorizer, auth_properties.Authorizers - ) + # To remain backwards compatible add the built-in "AWS_IAM" security scheme _before_ adding the authorizers defined + # in the template so that if the template already has an authorized named "AWS_IAM" it will override the built-in one. + open_api_editor.security_schemes["AWS_IAM"] = { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4", + } + + # If auth is defined in the template validate it, set the default authorizer, and add any specified authorizers. + if self.auth: + # Make sure keys in the dict are recognized + if not all(key in AuthProperties._fields for key in self.auth.keys()): + raise InvalidResourceException(self.logical_id, "Invalid value for 'Auth' property") + + auth_properties = AuthProperties(**self.auth) + # authorizers is guaranteed to return a value or raise an exception + authorizers = self._get_authorizers(auth_properties.Authorizers, auth_properties.DefaultAuthorizer) + + open_api_editor.add_authorizers_security_definitions(authorizers) + self._set_default_authorizer( + open_api_editor, authorizers, auth_properties.DefaultAuthorizer, auth_properties.Authorizers + ) + self.definition_body = open_api_editor.openapi def _add_tags(self): @@ -468,7 +479,8 @@ def _set_default_authorizer(self, open_api_editor, authorizers, default_authoriz if not default_authorizer: return - if not authorizers.get(default_authorizer): + # The AWS_IAM authorizer is built-in and does not need to be defined in the template as an authorizer. + if not authorizers.get(default_authorizer) and default_authorizer != "AWS_IAM": raise InvalidResourceException( self.logical_id, "Unable to set DefaultAuthorizer because '" @@ -488,8 +500,10 @@ def _get_authorizers(self, authorizers_config, default_authorizer=None): :param default_authorizer: name of the default authorizer """ authorizers = {} - if not isinstance(authorizers_config, dict): + # The AWS_IAM authorizer is built-in and does not need to be defined in the template as an authorizer. + if default_authorizer == "AWS_IAM": + return authorizers raise InvalidResourceException(self.logical_id, "Authorizers must be a dictionary.") for authorizer_name, authorizer in authorizers_config.items(): diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py index d134f19402..59a46062db 100644 --- a/samtranslator/model/eventsources/push.py +++ b/samtranslator/model/eventsources/push.py @@ -1167,7 +1167,8 @@ def _add_auth_to_openapi_integration(self, api, editor): # Default auth should already be applied, so apply any other auth here or scope override to default api_authorizers = api_auth and api_auth.get("Authorizers") - if method_authorizer != "NONE" and not api_authorizers: + # "NONE" and "AWS_IAM" are placeholder authorizer values so they can be safely skipped. + if method_authorizer != "NONE" and method_authorizer != "AWS_IAM" and not api_authorizers: raise InvalidEventException( self.relative_id, "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " @@ -1176,7 +1177,11 @@ def _add_auth_to_openapi_integration(self, api, editor): ), ) - if method_authorizer != "NONE" and not api_authorizers.get(method_authorizer): + if ( + method_authorizer != "NONE" + and method_authorizer != "AWS_IAM" + and not api_authorizers.get(method_authorizer) + ): raise InvalidEventException( self.relative_id, "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " diff --git a/samtranslator/open_api/open_api.py b/samtranslator/open_api/open_api.py index b31f3b7527..5d3ee32378 100644 --- a/samtranslator/open_api/open_api.py +++ b/samtranslator/open_api/open_api.py @@ -407,7 +407,7 @@ def _set_method_authorizer(self, path, method_name, authorizer_name, authorizers security_dict = dict() security_dict[authorizer_name] = [] - if authorizer_name != "NONE": + if authorizer_name != "NONE" and authorizer_name != "AWS_IAM": method_authorization_scopes = authorizers[authorizer_name].get("AuthorizationScopes") if authorization_scopes: method_authorization_scopes = authorization_scopes