def _set_default_authorizer(self, open_api_editor, authorizers,
                                default_authorizer, api_authorizers):
        """
        Sets the default authorizer if one is given in the template
        :param open_api_editor: editor object that contains the OpenApi definition
        :param authorizers: authorizer definitions converted from the API auth section
        :param default_authorizer: name of the default authorizer
        :param api_authorizers: API auth section authorizer defintions
        """
        if not default_authorizer:
            return

        if is_intrinsic_no_value(default_authorizer):
            return

        if is_intrinsic(default_authorizer):
            raise InvalidResourceException(
                self.logical_id,
                "Unable to set DefaultAuthorizer because intrinsic functions are not supported for this field.",
            )

        if not authorizers.get(default_authorizer):
            raise InvalidResourceException(
                self.logical_id,
                "Unable to set DefaultAuthorizer because '" +
                default_authorizer + "' was not defined in 'Authorizers'.",
            )

        for path in open_api_editor.iter_on_path():
            open_api_editor.set_path_default_authorizer(
                path,
                default_authorizer,
                authorizers=authorizers,
                api_authorizers=api_authorizers)
    def _get_type(self, policy):
        """
        Returns the type of the given policy

        :param string or dict policy: Policy data
        :return PolicyTypes: Type of the given policy. None, if type could not be inferred
        """

        # Must handle intrinsic functions. Policy could be a primitive type or an intrinsic function

        # Managed policies are of type string
        if isinstance(policy, string_types):
            return PolicyTypes.MANAGED_POLICY

        # Handle the special case for 'if' intrinsic function
        if is_intrinsic_if(policy):
            return self._get_type_from_intrinsic_if(policy)

        # Intrinsic functions are treated as managed policies by default
        if is_intrinsic(policy):
            return PolicyTypes.MANAGED_POLICY

        # Policy statement is a dictionary with the key "Statement" in it
        if isinstance(policy, dict) and "Statement" in policy:
            return PolicyTypes.POLICY_STATEMENT

        # This could be a policy template then.
        if self._is_policy_template(policy):
            return PolicyTypes.POLICY_TEMPLATE

        # Nothing matches. Don't take opinions on how to handle it. Instead just set the appropriate type.
        return PolicyTypes.UNKNOWN
    def _get_paths_to_intrinsics(self, input, path=None):
        """
        Returns all paths to dynamic values within a dictionary

        :param input: Input dictionary to find paths to dynamic values in
        :param path: Optional list to keep track of the path to the input dictionary
        :returns list: List of keys that defines the path to a dynamic value within the input dictionary
        """
        if path is None:
            path = []
        dynamic_value_paths = []
        if isinstance(input, dict):
            iterator = input.items()
        elif isinstance(input, list):
            iterator = enumerate(input)
        else:
            return dynamic_value_paths

        for key, value in sorted(iterator, key=lambda item: item[0]):
            if is_intrinsic(value) or is_dynamic_reference(value):
                dynamic_value_paths.append(path + [key])
            elif isinstance(value, (dict, list)):
                dynamic_value_paths.extend(self._get_paths_to_intrinsics(value, path + [key]))

        return dynamic_value_paths
Beispiel #4
0
    def _add_cors(self):
        """
        Add CORS configuration to the Swagger file, if necessary
        """

        INVALID_ERROR = "Invalid value for 'Cors' property"

        if not self.cors:
            return

        if self.cors and not self.definition_body:
            raise InvalidResourceException(
                self.logical_id,
                "Cors works only with inline Swagger specified in 'DefinitionBody' property."
            )

        if isinstance(self.cors, string_types) or is_intrinsic(self.cors):
            # Just set Origin property. Others will be defaults
            properties = CorsProperties(AllowOrigin=self.cors)
        elif isinstance(self.cors, dict):

            # Make sure keys in the dict are recognized
            if not all(key in CorsProperties._fields
                       for key in self.cors.keys()):
                raise InvalidResourceException(self.logical_id, INVALID_ERROR)

            properties = CorsProperties(**self.cors)

        else:
            raise InvalidResourceException(self.logical_id, INVALID_ERROR)

        if not SwaggerEditor.is_valid(self.definition_body):
            raise InvalidResourceException(
                self.logical_id,
                "Unable to add Cors configuration because "
                "'DefinitionBody' does not contain a valid Swagger definition.",
            )

        if properties.AllowCredentials is True and properties.AllowOrigin == _CORS_WILDCARD:
            raise InvalidResourceException(
                self.logical_id,
                "Unable to add Cors configuration because "
                "'AllowCredentials' can not be true when "
                "'AllowOrigin' is \"'*'\" or not set",
            )

        editor = SwaggerEditor(self.definition_body)
        for path in editor.iter_on_path():
            editor.add_cors(
                path,
                properties.AllowOrigin,
                properties.AllowHeaders,
                properties.AllowMethods,
                max_age=properties.MaxAge,
                allow_credentials=properties.AllowCredentials,
            )

        # Assign the Swagger back to template
        self.definition_body = editor.swagger
 def _replace_deployment_types(self, value, key=None):
     if isinstance(value, list):
         for i in range(len(value)):
             value[i] = self._replace_deployment_types(value[i])
         return value
     elif is_intrinsic(value):
         for (k, v) in value.items():
             value[k] = self._replace_deployment_types(v, k)
         return value
     else:
         if value in CODEDEPLOY_PREDEFINED_CONFIGURATIONS_LIST:
             if key == "Fn::Sub":  # Don't nest a "Sub" in a "Sub"
                 return ["CodeDeployDefault.Lambda${ConfigName}", {"ConfigName": value}]
             return fnSub("CodeDeployDefault.Lambda${ConfigName}", {"ConfigName": value})
         return value
Beispiel #6
0
    def add_cors(
        self,
        allow_origins,
        allow_headers=None,
        allow_methods=None,
        expose_headers=None,
        max_age=None,
        allow_credentials=None,
    ):
        """
        Add CORS configuration to this Api to _X_APIGW_CORS header in open api definition

        Following this guide:
        https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html
        https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-api-cors.html

        :param list/dict allowed_origins: Comma separate list of allowed origins.
            Value can also be an intrinsic function dict.
        :param list/dict allowed_headers: Comma separated list of allowed headers.
            Value can also be an intrinsic function dict.
        :param list/dict allowed_methods: Comma separated list of allowed methods.
            Value can also be an intrinsic function dict.
        :param list/dict expose_headers: Comma separated list of allowed methods.
            Value can also be an intrinsic function dict.
        :param integer/dict max_age: Maximum duration to cache the CORS Preflight request. Value is set on
            Access-Control-Max-Age header. Value can also be an intrinsic function dict.
        :param bool/None allowed_credentials: Flags whether request is allowed to contain credentials.
        """
        ALLOW_ORIGINS = "allowOrigins"
        ALLOW_HEADERS = "allowHeaders"
        ALLOW_METHODS = "allowMethods"
        EXPOSE_HEADERS = "exposeHeaders"
        MAX_AGE = "maxAge"
        ALLOW_CREDENTIALS = "allowCredentials"
        cors_headers = [
            ALLOW_ORIGINS, ALLOW_HEADERS, ALLOW_METHODS, EXPOSE_HEADERS,
            MAX_AGE, ALLOW_CREDENTIALS
        ]
        cors_configuration = self._doc.get(self._X_APIGW_CORS, dict())

        # intrinsics will not work if cors configuration is defined in open api and as a property to the HttpApi
        if allow_origins and is_intrinsic(allow_origins):
            cors_configuration_string = json.dumps(allow_origins)
            for header in cors_headers:
                # example: allowOrigins to AllowOrigins
                keyword = header[0].upper() + header[1:]
                cors_configuration_string = cors_configuration_string.replace(
                    keyword, header)
            cors_configuration_dict = json.loads(cors_configuration_string)
            cors_configuration.update(cors_configuration_dict)

        else:
            if allow_origins:
                cors_configuration[ALLOW_ORIGINS] = allow_origins
            if allow_headers:
                cors_configuration[ALLOW_HEADERS] = allow_headers
            if allow_methods:
                cors_configuration[ALLOW_METHODS] = allow_methods
            if expose_headers:
                cors_configuration[EXPOSE_HEADERS] = expose_headers
            if max_age is not None:
                cors_configuration[MAX_AGE] = max_age
            if allow_credentials is True:
                cors_configuration[ALLOW_CREDENTIALS] = allow_credentials

        self._doc[self._X_APIGW_CORS] = cors_configuration
    def _add_cors(self):
        """
        Add CORS configuration if CORSConfiguration property is set in SAM.
        Adds CORS configuration only if DefinitionBody is present and
        APIGW extension for CORS is not present in the DefinitionBody
        """

        if self.cors_configuration and not self.definition_body:
            raise InvalidResourceException(
                self.logical_id,
                "Cors works only with inline OpenApi specified in 'DefinitionBody' property."
            )

        # If cors configuration is set to true add * to the allow origins.
        # This also support referencing the value as a parameter
        if isinstance(self.cors_configuration, bool):
            # if cors config is true add Origins as "'*'"
            properties = CorsProperties(AllowOrigins=[_CORS_WILDCARD])

        elif is_intrinsic(self.cors_configuration):
            # Just set Origin property. Intrinsics will be handledOthers will be defaults
            properties = CorsProperties(AllowOrigins=self.cors_configuration)

        elif isinstance(self.cors_configuration, dict):
            # Make sure keys in the dict are recognized
            if not all(key in CorsProperties._fields
                       for key in self.cors_configuration.keys()):
                raise InvalidResourceException(
                    self.logical_id, "Invalid value for 'Cors' property.")

            properties = CorsProperties(**self.cors_configuration)

        else:
            raise InvalidResourceException(
                self.logical_id, "Invalid value for 'Cors' property.")

        if not OpenApiEditor.is_valid(self.definition_body):
            raise InvalidResourceException(
                self.logical_id,
                "Unable to add Cors configuration because "
                "'DefinitionBody' does not contain a valid "
                "OpenApi definition.",
            )

        if properties.AllowCredentials is True and properties.AllowOrigins == [
                _CORS_WILDCARD
        ]:
            raise InvalidResourceException(
                self.logical_id,
                "Unable to add Cors configuration because "
                "'AllowCredentials' can not be true when "
                "'AllowOrigin' is \"'*'\" or not set.",
            )

        editor = OpenApiEditor(self.definition_body)
        # if CORS is set in both definition_body and as a CorsConfiguration property,
        # SAM merges and overrides the cors headers in definition_body with headers of CorsConfiguration
        editor.add_cors(
            properties.AllowOrigins,
            properties.AllowHeaders,
            properties.AllowMethods,
            properties.ExposeHeaders,
            properties.MaxAge,
            properties.AllowCredentials,
        )

        # Assign the OpenApi back to template
        self.definition_body = editor.openapi
Beispiel #8
0
 def test_is_intrinsic_on_intrinsic_like_dict_input(self):
     self.assertFalse(is_intrinsic({"Ref": "foo", "key": "bar"}))
Beispiel #9
0
 def test_is_intrinsic_on_non_dict_input(self):
     self.assertFalse(is_intrinsic([1, 2, 3]))
Beispiel #10
0
 def test_is_intrinsic_on_empty_input(self):
     self.assertFalse(is_intrinsic(None))
Beispiel #11
0
    def test_is_intrinsic_must_detect_intrinsics(self, intrinsic_name):

        input = {intrinsic_name: ["some value"]}

        self.assertTrue(is_intrinsic(input))