diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index 649f277c61..607c38529e 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -267,8 +267,9 @@ def _is_missing_identity_source(self, identity): query_strings = identity.get("QueryStrings") stage_variables = identity.get("StageVariables") context = identity.get("Context") + ttl = identity.get("ReauthorizeEvery") - if not headers and not query_strings and not stage_variables and not context: + if (ttl is None or int(ttl) > 0) and not headers and not query_strings and not stage_variables and not context: return True return False @@ -311,7 +312,9 @@ def generate_swagger(self): swagger[APIGATEWAY_AUTHORIZER_KEY]["authorizerCredentials"] = function_invoke_role if self._get_function_payload_type() == "REQUEST": - swagger[APIGATEWAY_AUTHORIZER_KEY]["identitySource"] = self._get_identity_source() + identity_source = self._get_identity_source() + if identity_source: + swagger[APIGATEWAY_AUTHORIZER_KEY]["identitySource"] = self._get_identity_source() # Authorizer Validation Expression is only allowed on COGNITO_USER_POOLS and LAMBDA_TOKEN is_lambda_token_authorizer = authorizer_type == "LAMBDA" and self._get_function_payload_type() == "TOKEN" diff --git a/tests/model/test_api.py b/tests/model/test_api.py index 627bda3d5c..8bc871ee7e 100644 --- a/tests/model/test_api.py +++ b/tests/model/test_api.py @@ -17,3 +17,18 @@ def test_create_authorizer_fails_with_string_authorization_scopes(self): auth = ApiGatewayAuthorizer( api_logical_id="logicalId", name="authName", authorization_scopes="invalid_scope" ) + + def test_create_authorizer_fails_with_missing_identity_values_and_not_cached(self): + with pytest.raises(InvalidResourceException): + auth = ApiGatewayAuthorizer( + api_logical_id="logicalId", + name="authName", + identity={"ReauthorizeEvery": 10}, + function_payload_type="REQUEST", + ) + + def test_create_authorizer_fails_with_empty_identity(self): + with pytest.raises(InvalidResourceException): + auth = ApiGatewayAuthorizer( + api_logical_id="logicalId", name="authName", identity={}, function_payload_type="REQUEST" + ) diff --git a/tests/translator/input/api_with_auth_all_minimum.yaml b/tests/translator/input/api_with_auth_all_minimum.yaml index f6eda0af2c..b89479219c 100644 --- a/tests/translator/input/api_with_auth_all_minimum.yaml +++ b/tests/translator/input/api_with_auth_all_minimum.yaml @@ -32,6 +32,20 @@ Resources: Identity: Headers: - Authorization1 + + MyApiWithNotCachedLambdaRequestAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: MyLambdaRequestAuth + Authorizers: + MyLambdaRequestAuth: + FunctionPayloadType: REQUEST + FunctionArn: !GetAtt MyAuthFn.Arn + Identity: + ReauthorizeEvery: 0 + MyAuthFn: Type: AWS::Serverless::Function Properties: @@ -63,6 +77,12 @@ Resources: RestApiId: !Ref MyApiWithLambdaRequestAuth Method: get Path: /lambda-request + LambdaNotCachedRequest: + Type: Api + Properties: + RestApiId: !Ref MyApiWithNotCachedLambdaRequestAuth + Method: get + Path: /not-cached-lambda-request MyUserPool: Type: AWS::Cognito::UserPool Properties: diff --git a/tests/translator/output/api_with_auth_all_minimum.json b/tests/translator/output/api_with_auth_all_minimum.json index 640d74f16a..4a4dbe937c 100644 --- a/tests/translator/output/api_with_auth_all_minimum.json +++ b/tests/translator/output/api_with_auth_all_minimum.json @@ -63,7 +63,19 @@ }, "StageName": "Prod" } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuthDeployment444f67cd7c" + }, + "RestApiId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + }, + "StageName": "Prod" + } + }, "MyApiWithLambdaTokenAuthMyLambdaTokenAuthAuthorizerPermission": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -205,7 +217,30 @@ ] } } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthMyLambdaRequestAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuthFn", + "Arn" + ] + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + } + } + ] + } + } + }, "MyFnLambdaTokenPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -236,7 +271,17 @@ "Description": "RestApi deployment id: 6e52add211cda52ae10a7cc0e0afcf4afc682f9f", "StageName": "Stage" } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthDeployment444f67cd7c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + }, + "Description": "RestApi deployment id: 444f67cd7c6475a698a0101480ba99b498325e90", + "StageName": "Stage" + } + }, "MyFnLambdaRequestPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -257,7 +302,28 @@ ] } } - }, + }, + "MyFnLambdaNotCachedRequestPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFn" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/not-cached-lambda-request", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + } + } + ] + } + } + }, "MyApiWithLambdaTokenAuth": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -468,6 +534,64 @@ } } } + }, + "MyApiWithNotCachedLambdaRequestAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/not-cached-lambda-request": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFn.Arn}/invocations" + } + }, + "security": [ + { + "MyLambdaRequestAuth": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": { + "Fn::GetAtt": [ + "MyAuthFn", + "Arn" + ] + } + } + ] + }, + "authorizerResultTtlInSeconds": 0 + }, + "x-amazon-apigateway-authtype": "custom" + } + } + } + } } } } diff --git a/tests/translator/output/aws-cn/api_with_auth_all_minimum.json b/tests/translator/output/aws-cn/api_with_auth_all_minimum.json index f568fdaa85..c072d8df8a 100644 --- a/tests/translator/output/aws-cn/api_with_auth_all_minimum.json +++ b/tests/translator/output/aws-cn/api_with_auth_all_minimum.json @@ -71,6 +71,18 @@ }, "StageName": "Prod" } + }, + "MyApiWithNotCachedLambdaRequestAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuthDeployment234e92eab4" + }, + "RestApiId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + }, + "StageName": "Prod" + } }, "MyApiWithLambdaTokenAuthMyLambdaTokenAuthAuthorizerPermission": { "Type": "AWS::Lambda::Permission", @@ -203,7 +215,30 @@ ] } } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthMyLambdaRequestAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuthFn", + "Arn" + ] + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + } + } + ] + } + } + }, "MyApiWithLambdaTokenAuthDeploymenta48b731095": { "Type": "AWS::ApiGateway::Deployment", "Properties": { @@ -213,7 +248,17 @@ "Description": "RestApi deployment id: a48b7310952ed029bd212c380e89a1bd39c74eae", "StageName": "Stage" } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthDeployment234e92eab4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + }, + "Description": "RestApi deployment id: 234e92eab4e4c590ad261ddd55775c1edcc2972f", + "StageName": "Stage" + } + }, "MyFnLambdaTokenPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -255,7 +300,28 @@ ] } } - }, + }, + "MyFnLambdaNotCachedRequestPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFn" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/not-cached-lambda-request", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + } + } + ] + } + } + }, "MyApiWithLambdaTokenAuth": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -492,6 +558,72 @@ "endpointConfigurationTypes": "REGIONAL" } } + }, + "MyApiWithNotCachedLambdaRequestAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/not-cached-lambda-request": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFn.Arn}/invocations" + } + }, + "security": [ + { + "MyLambdaRequestAuth": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": { + "Fn::GetAtt": [ + "MyAuthFn", + "Arn" + ] + } + } + ] + }, + "authorizerResultTtlInSeconds": 0 + }, + "x-amazon-apigateway-authtype": "custom" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } } } } diff --git a/tests/translator/output/aws-us-gov/api_with_auth_all_minimum.json b/tests/translator/output/aws-us-gov/api_with_auth_all_minimum.json index b108f7b430..7ab9dea6e5 100644 --- a/tests/translator/output/aws-us-gov/api_with_auth_all_minimum.json +++ b/tests/translator/output/aws-us-gov/api_with_auth_all_minimum.json @@ -71,6 +71,18 @@ }, "StageName": "Prod" } + }, + "MyApiWithNotCachedLambdaRequestAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuthDeploymentd3b8858811" + }, + "RestApiId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + }, + "StageName": "Prod" + } }, "MyApiWithLambdaTokenAuthMyLambdaTokenAuthAuthorizerPermission": { "Type": "AWS::Lambda::Permission", @@ -213,7 +225,30 @@ ] } } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthMyLambdaRequestAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Fn::GetAtt": [ + "MyAuthFn", + "Arn" + ] + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + } + } + ] + } + } + }, "MyFnLambdaTokenPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -234,7 +269,17 @@ ] } } - }, + }, + "MyApiWithNotCachedLambdaRequestAuthDeploymentd3b8858811": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + }, + "Description": "RestApi deployment id: d3b8858811d6c42be45490ba4d1ca059821cf4fd", + "StageName": "Stage" + } + }, "MyFnLambdaRequestPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -256,6 +301,27 @@ } } }, + "MyFnLambdaNotCachedRequestPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFn" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/not-cached-lambda-request", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithNotCachedLambdaRequestAuth" + } + } + ] + } + } + }, "MyApiWithLambdaTokenAuth": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -492,6 +558,72 @@ "endpointConfigurationTypes": "REGIONAL" } } + }, + "MyApiWithNotCachedLambdaRequestAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/not-cached-lambda-request": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFn.Arn}/invocations" + } + }, + "security": [ + { + "MyLambdaRequestAuth": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": { + "Fn::GetAtt": [ + "MyAuthFn", + "Arn" + ] + } + } + ] + }, + "authorizerResultTtlInSeconds": 0 + }, + "x-amazon-apigateway-authtype": "custom" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } } } }