diff --git a/lib/ansible/modules/network/fortimanager/fmgr_secprof_waf.py b/lib/ansible/modules/network/fortimanager/fmgr_secprof_waf.py
new file mode 100644
index 0000000000..b42a045f1d
--- /dev/null
+++ b/lib/ansible/modules/network/fortimanager/fmgr_secprof_waf.py
@@ -0,0 +1,1630 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of`
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+#
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {'status': ['preview'],
+ 'supported_by': 'community',
+ 'metadata_version': '1.1'}
+
+DOCUMENTATION = '''
+---
+module: fmgr_secprof_waf
+version_added: "2.8"
+author:
+ - Luke Weighall (@lweighall)
+ - Andrew Welsh (@Ghilli3)
+ - Jim Huber (@p4r4n0y1ng)
+short_description: FortiManager web application firewall security profile
+description:
+ - Manage web application firewall security profiles for FGTs via FMG
+
+options:
+ adom:
+ description:
+ - The ADOM the configuration should belong to.
+ required: false
+ default: root
+
+ host:
+ description:
+ - The FortiManager's Address.
+ required: true
+
+ username:
+ description:
+ - The username associated with the account.
+ required: true
+
+ password:
+ description:
+ - The password associated with the username account.
+ required: true
+
+ mode:
+ description:
+ - Sets one of three modes for managing the object.
+ - Allows use of soft-adds instead of overwriting existing values
+ choices: ['add', 'set', 'delete', 'update']
+ required: false
+ default: add
+
+ name:
+ description:
+ - WAF Profile name.
+ required: false
+
+ external:
+ description:
+ - Disable/Enable external HTTP Inspection.
+ - choice | disable | Disable external inspection.
+ - choice | enable | Enable external inspection.
+ required: false
+ choices: ["disable", "enable"]
+
+ extended_log:
+ description:
+ - Enable/disable extended logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ comment:
+ description:
+ - Comment.
+ required: false
+
+ address_list:
+ description:
+ - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
+ - List of multiple child objects to be added. Expects a list of dictionaries.
+ - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
+ - If submitted, all other prefixed sub-parameters ARE IGNORED.
+ - This object is MUTUALLY EXCLUSIVE with its options.
+ - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
+ - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
+ required: false
+
+ address_list_blocked_address:
+ description:
+ - Blocked address.
+ required: false
+
+ address_list_blocked_log:
+ description:
+ - Enable/disable logging on blocked addresses.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ address_list_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ address_list_status:
+ description:
+ - Status.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ address_list_trusted_address:
+ description:
+ - Trusted address.
+ required: false
+
+ constraint:
+ description:
+ - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
+ - List of multiple child objects to be added. Expects a list of dictionaries.
+ - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
+ - If submitted, all other prefixed sub-parameters ARE IGNORED.
+ - This object is MUTUALLY EXCLUSIVE with its options.
+ - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
+ - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
+ required: false
+
+ constraint_content_length_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_content_length_length:
+ description:
+ - Length of HTTP content in bytes (0 to 2147483647).
+ required: false
+
+ constraint_content_length_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_content_length_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_content_length_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_address:
+ description:
+ - Host address.
+ required: false
+
+ constraint_exception_content_length:
+ description:
+ - HTTP content length in request.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_header_length:
+ description:
+ - HTTP header length in request.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_hostname:
+ description:
+ - Enable/disable hostname check.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_line_length:
+ description:
+ - HTTP line length in request.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_malformed:
+ description:
+ - Enable/disable malformed HTTP request check.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_max_cookie:
+ description:
+ - Maximum number of cookies in HTTP request.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_max_header_line:
+ description:
+ - Maximum number of HTTP header line.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_max_range_segment:
+ description:
+ - Maximum number of range segments in HTTP range line.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_max_url_param:
+ description:
+ - Maximum number of parameters in URL.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_method:
+ description:
+ - Enable/disable HTTP method check.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_param_length:
+ description:
+ - Maximum length of parameter in URL, HTTP POST request or HTTP body.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_pattern:
+ description:
+ - URL pattern.
+ required: false
+
+ constraint_exception_regex:
+ description:
+ - Enable/disable regular expression based pattern match.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_url_param_length:
+ description:
+ - Maximum length of parameter in URL.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_exception_version:
+ description:
+ - Enable/disable HTTP version check.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_header_length_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_header_length_length:
+ description:
+ - Length of HTTP header in bytes (0 to 2147483647).
+ required: false
+
+ constraint_header_length_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_header_length_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_header_length_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_hostname_action:
+ description:
+ - Action for a hostname constraint.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_hostname_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_hostname_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_hostname_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_line_length_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_line_length_length:
+ description:
+ - Length of HTTP line in bytes (0 to 2147483647).
+ required: false
+
+ constraint_line_length_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_line_length_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_line_length_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_malformed_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_malformed_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_malformed_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_malformed_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_cookie_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_max_cookie_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_cookie_max_cookie:
+ description:
+ - Maximum number of cookies in HTTP request (0 to 2147483647).
+ required: false
+
+ constraint_max_cookie_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_max_cookie_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_header_line_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_max_header_line_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_header_line_max_header_line:
+ description:
+ - Maximum number HTTP header lines (0 to 2147483647).
+ required: false
+
+ constraint_max_header_line_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_max_header_line_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_range_segment_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_max_range_segment_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_range_segment_max_range_segment:
+ description:
+ - Maximum number of range segments in HTTP range line (0 to 2147483647).
+ required: false
+
+ constraint_max_range_segment_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_max_range_segment_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_url_param_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_max_url_param_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_max_url_param_max_url_param:
+ description:
+ - Maximum number of parameters in URL (0 to 2147483647).
+ required: false
+
+ constraint_max_url_param_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_max_url_param_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_method_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_method_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_method_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_method_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_param_length_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_param_length_length:
+ description:
+ - Maximum length of parameter in URL, HTTP POST request or HTTP body in bytes (0 to 2147483647).
+ required: false
+
+ constraint_param_length_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_param_length_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_param_length_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_url_param_length_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_url_param_length_length:
+ description:
+ - Maximum length of URL parameter in bytes (0 to 2147483647).
+ required: false
+
+ constraint_url_param_length_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_url_param_length_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_url_param_length_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_version_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ required: false
+ choices: ["allow", "block"]
+
+ constraint_version_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ constraint_version_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ constraint_version_status:
+ description:
+ - Enable/disable the constraint.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ method:
+ description:
+ - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
+ - List of multiple child objects to be added. Expects a list of dictionaries.
+ - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
+ - If submitted, all other prefixed sub-parameters ARE IGNORED.
+ - This object is MUTUALLY EXCLUSIVE with its options.
+ - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
+ - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
+ required: false
+
+ method_default_allowed_methods:
+ description:
+ - Methods.
+ - FLAG Based Options. Specify multiple in list form.
+ - flag | delete | HTTP DELETE method.
+ - flag | get | HTTP GET method.
+ - flag | head | HTTP HEAD method.
+ - flag | options | HTTP OPTIONS method.
+ - flag | post | HTTP POST method.
+ - flag | put | HTTP PUT method.
+ - flag | trace | HTTP TRACE method.
+ - flag | others | Other HTTP methods.
+ - flag | connect | HTTP CONNECT method.
+ required: false
+ choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"]
+
+ method_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ method_severity:
+ description:
+ - Severity.
+ - choice | low | low severity
+ - choice | medium | medium severity
+ - choice | high | High severity
+ required: false
+ choices: ["low", "medium", "high"]
+
+ method_status:
+ description:
+ - Status.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ method_method_policy_address:
+ description:
+ - Host address.
+ required: false
+
+ method_method_policy_allowed_methods:
+ description:
+ - Allowed Methods.
+ - FLAG Based Options. Specify multiple in list form.
+ - flag | delete | HTTP DELETE method.
+ - flag | get | HTTP GET method.
+ - flag | head | HTTP HEAD method.
+ - flag | options | HTTP OPTIONS method.
+ - flag | post | HTTP POST method.
+ - flag | put | HTTP PUT method.
+ - flag | trace | HTTP TRACE method.
+ - flag | others | Other HTTP methods.
+ - flag | connect | HTTP CONNECT method.
+ required: false
+ choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"]
+
+ method_method_policy_pattern:
+ description:
+ - URL pattern.
+ required: false
+
+ method_method_policy_regex:
+ description:
+ - Enable/disable regular expression based pattern match.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ signature:
+ description:
+ - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
+ - List of multiple child objects to be added. Expects a list of dictionaries.
+ - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
+ - If submitted, all other prefixed sub-parameters ARE IGNORED.
+ - This object is MUTUALLY EXCLUSIVE with its options.
+ - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
+ - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
+ required: false
+
+ signature_credit_card_detection_threshold:
+ description:
+ - The minimum number of Credit cards to detect violation.
+ required: false
+
+ signature_disabled_signature:
+ description:
+ - Disabled signatures
+ required: false
+
+ signature_disabled_sub_class:
+ description:
+ - Disabled signature subclasses.
+ required: false
+
+ signature_custom_signature_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ - choice | erase | Erase credit card numbers.
+ required: false
+ choices: ["allow", "block", "erase"]
+
+ signature_custom_signature_case_sensitivity:
+ description:
+ - Case sensitivity in pattern.
+ - choice | disable | Case insensitive in pattern.
+ - choice | enable | Case sensitive in pattern.
+ required: false
+ choices: ["disable", "enable"]
+
+ signature_custom_signature_direction:
+ description:
+ - Traffic direction.
+ - choice | request | Match HTTP request.
+ - choice | response | Match HTTP response.
+ required: false
+ choices: ["request", "response"]
+
+ signature_custom_signature_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ signature_custom_signature_name:
+ description:
+ - Signature name.
+ required: false
+
+ signature_custom_signature_pattern:
+ description:
+ - Match pattern.
+ required: false
+
+ signature_custom_signature_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ signature_custom_signature_status:
+ description:
+ - Status.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ signature_custom_signature_target:
+ description:
+ - Match HTTP target.
+ - FLAG Based Options. Specify multiple in list form.
+ - flag | arg | HTTP arguments.
+ - flag | arg-name | Names of HTTP arguments.
+ - flag | req-body | HTTP request body.
+ - flag | req-cookie | HTTP request cookies.
+ - flag | req-cookie-name | HTTP request cookie names.
+ - flag | req-filename | HTTP request file name.
+ - flag | req-header | HTTP request headers.
+ - flag | req-header-name | HTTP request header names.
+ - flag | req-raw-uri | Raw URI of HTTP request.
+ - flag | req-uri | URI of HTTP request.
+ - flag | resp-body | HTTP response body.
+ - flag | resp-hdr | HTTP response headers.
+ - flag | resp-status | HTTP response status.
+ required: false
+ choices: ["arg","arg-name","req-body","req-cookie","req-cookie-name","req-filename","req-header","req-header-name",
+ "req-raw-uri","req-uri","resp-body","resp-hdr","resp-status"]
+
+ signature_main_class_action:
+ description:
+ - Action.
+ - choice | allow | Allow.
+ - choice | block | Block.
+ - choice | erase | Erase credit card numbers.
+ required: false
+ choices: ["allow", "block", "erase"]
+
+ signature_main_class_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ signature_main_class_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ signature_main_class_status:
+ description:
+ - Status.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ url_access:
+ description:
+ - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
+ - List of multiple child objects to be added. Expects a list of dictionaries.
+ - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
+ - If submitted, all other prefixed sub-parameters ARE IGNORED.
+ - This object is MUTUALLY EXCLUSIVE with its options.
+ - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
+ - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
+ required: false
+
+ url_access_action:
+ description:
+ - Action.
+ - choice | bypass | Allow the HTTP request, also bypass further WAF scanning.
+ - choice | permit | Allow the HTTP request, and continue further WAF scanning.
+ - choice | block | Block HTTP request.
+ required: false
+ choices: ["bypass", "permit", "block"]
+
+ url_access_address:
+ description:
+ - Host address.
+ required: false
+
+ url_access_log:
+ description:
+ - Enable/disable logging.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ url_access_severity:
+ description:
+ - Severity.
+ - choice | low | Low severity.
+ - choice | medium | Medium severity.
+ - choice | high | High severity.
+ required: false
+ choices: ["low", "medium", "high"]
+
+ url_access_access_pattern_negate:
+ description:
+ - Enable/disable match negation.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ url_access_access_pattern_pattern:
+ description:
+ - URL pattern.
+ required: false
+
+ url_access_access_pattern_regex:
+ description:
+ - Enable/disable regular expression based pattern match.
+ - choice | disable | Disable setting.
+ - choice | enable | Enable setting.
+ required: false
+ choices: ["disable", "enable"]
+
+ url_access_access_pattern_srcaddr:
+ description:
+ - Source address.
+ required: false
+
+'''
+
+EXAMPLES = '''
+ - name: DELETE Profile
+ fmgr_secprof_waf:
+ host: "{{inventory_hostname}}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ name: "Ansible_WAF_Profile"
+ comment: "Created by Ansible Module TEST"
+ mode: "delete"
+
+ - name: CREATE Profile
+ fmgr_secprof_waf:
+ host: "{{inventory_hostname}}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ name: "Ansible_WAF_Profile"
+ comment: "Created by Ansible Module TEST"
+ mode: "set"
+'''
+
+RETURN = """
+api_result:
+ description: full API response, includes status code and message
+ returned: always
+ type: string
+"""
+
+from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.network.fortimanager.fortimanager import AnsibleFortiManager
+
+# check for pyFMG lib
+try:
+ from pyFMG.fortimgr import FortiManager
+
+ HAS_PYFMGR = True
+except ImportError:
+ HAS_PYFMGR = False
+
+
+###############
+# START METHODS
+###############
+
+
+def fmgr_waf_profile_addsetdelete(fmg, paramgram):
+
+ mode = paramgram["mode"]
+ adom = paramgram["adom"]
+ # INIT A BASIC OBJECTS
+ response = (-100000, {"msg": "Illegal or malformed paramgram discovered. System Exception"})
+ url = ""
+ datagram = {}
+
+ # EVAL THE MODE PARAMETER FOR SET OR ADD
+ if mode in ['set', 'add', 'update']:
+ url = '/pm/config/adom/{adom}/obj/waf/profile'.format(adom=adom)
+ datagram = fmgr_del_none(fmgr_prepare_dict(paramgram))
+
+ # EVAL THE MODE PARAMETER FOR DELETE
+ elif mode == "delete":
+ # SET THE CORRECT URL FOR DELETE
+ url = '/pm/config/adom/{adom}/obj/waf/profile/{name}'.format(adom=adom, name=paramgram["name"])
+ datagram = {}
+
+ # IF MODE = SET -- USE THE 'SET' API CALL MODE
+ if mode == "set":
+ response = fmg.set(url, datagram)
+ # IF MODE = UPDATE -- USER THE 'UPDATE' API CALL MODE
+ elif mode == "update":
+ response = fmg.update(url, datagram)
+ # IF MODE = ADD -- USE THE 'ADD' API CALL MODE
+ elif mode == "add":
+ response = fmg.add(url, datagram)
+ # IF MODE = DELETE -- USE THE DELETE URL AND API CALL MODE
+ elif mode == "delete":
+ response = fmg.delete(url, datagram)
+
+ return response
+
+
+# ADDITIONAL COMMON FUNCTIONS
+# FUNCTION/METHOD FOR LOGGING OUT AND ANALYZING ERROR CODES
+def fmgr_logout(fmg, module, msg="NULL", results=(), good_codes=(0,), logout_on_fail=True, logout_on_success=False):
+ """
+ THIS METHOD CONTROLS THE LOGOUT AND ERROR REPORTING AFTER AN METHOD OR FUNCTION RUNS
+ """
+ # pydevd.settrace('10.0.0.122', port=54654, stdoutToServer=True, stderrToServer=True)
+ # VALIDATION ERROR (NO RESULTS, JUST AN EXIT)
+ if msg != "NULL" and len(results) == 0:
+ try:
+ fmg.logout()
+ except BaseException:
+ pass
+ module.fail_json(msg=msg)
+
+ # SUBMISSION ERROR
+ if len(results) > 0:
+ if msg == "NULL":
+ try:
+ msg = results[1]['status']['message']
+ except BaseException:
+ msg = "No status message returned from pyFMG. Possible that this was a GET with a tuple result."
+
+ if results[0] not in good_codes:
+ if logout_on_fail:
+ fmg.logout()
+ module.fail_json(msg=msg, **results[1])
+ else:
+ return msg
+ else:
+ if logout_on_success:
+ fmg.logout()
+ module.exit_json(msg="API Called worked, but logout handler has been asked to logout on success",
+ **results[1])
+ else:
+ return msg
+
+
+# FUNCTION/METHOD FOR CONVERTING CIDR TO A NETMASK
+# DID NOT USE IP ADDRESS MODULE TO KEEP INCLUDES TO A MINIMUM
+def fmgr_cidr_to_netmask(cidr):
+ cidr = int(cidr)
+ mask = (0xffffffff >> (32 - cidr)) << (32 - cidr)
+ return (str((0xff000000 & mask) >> 24) + '.' +
+ str((0x00ff0000 & mask) >> 16) + '.' +
+ str((0x0000ff00 & mask) >> 8) + '.' +
+ str((0x000000ff & mask)))
+
+
+# utility function: removing keys wih value of None, nothing in playbook for that key
+def fmgr_del_none(obj):
+ if isinstance(obj, dict):
+ return type(obj)((fmgr_del_none(k), fmgr_del_none(v))
+ for k, v in obj.items() if k is not None and (v is not None and not fmgr_is_empty_dict(v)))
+ else:
+ return obj
+
+
+# utility function: remove keys that are need for the logic but the FMG API won't accept them
+def fmgr_prepare_dict(obj):
+ list_of_elems = ["mode", "adom", "host", "username", "password"]
+ if isinstance(obj, dict):
+ obj = dict((key, fmgr_prepare_dict(value)) for (key, value) in obj.items() if key not in list_of_elems)
+ return obj
+
+
+def fmgr_is_empty_dict(obj):
+ return_val = False
+ if isinstance(obj, dict):
+ if len(obj) > 0:
+ for k, v in obj.items():
+ if isinstance(v, dict):
+ if len(v) == 0:
+ return_val = True
+ elif len(v) > 0:
+ for k1, v1 in v.items():
+ if v1 is None:
+ return_val = True
+ elif v1 is not None:
+ return_val = False
+ return return_val
+ elif v is None:
+ return_val = True
+ elif v is not None:
+ return_val = False
+ return return_val
+ elif len(obj) == 0:
+ return_val = True
+
+ return return_val
+
+
+def fmgr_split_comma_strings_into_lists(obj):
+ if isinstance(obj, dict):
+ if len(obj) > 0:
+ for k, v in obj.items():
+ if isinstance(v, str):
+ new_list = list()
+ if "," in v:
+ new_items = v.split(",")
+ for item in new_items:
+ new_list.append(item.strip())
+ obj[k] = new_list
+
+ return obj
+
+
+#############
+# END METHODS
+#############
+
+
+def main():
+ argument_spec = dict(
+ adom=dict(type="str", default="root"),
+ host=dict(required=True, type="str"),
+ password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True, required=True),
+ username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True, required=True),
+ mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
+
+ name=dict(required=False, type="str"),
+ external=dict(required=False, type="str", choices=["disable", "enable"]),
+ extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ comment=dict(required=False, type="str"),
+ address_list=dict(required=False, type="list"),
+ address_list_blocked_address=dict(required=False, type="str"),
+ address_list_blocked_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ address_list_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ address_list_status=dict(required=False, type="str", choices=["disable", "enable"]),
+ address_list_trusted_address=dict(required=False, type="str"),
+ constraint=dict(required=False, type="list"),
+
+ constraint_content_length_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_content_length_length=dict(required=False, type="int"),
+ constraint_content_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_content_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_content_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_exception_address=dict(required=False, type="str"),
+ constraint_exception_content_length=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_header_length=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_hostname=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_line_length=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_malformed=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_max_cookie=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_max_header_line=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_max_range_segment=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_max_url_param=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_method=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_pattern=dict(required=False, type="str"),
+ constraint_exception_regex=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_url_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_exception_version=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_header_length_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_header_length_length=dict(required=False, type="int"),
+ constraint_header_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_header_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_header_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_hostname_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_hostname_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_hostname_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_hostname_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_line_length_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_line_length_length=dict(required=False, type="int"),
+ constraint_line_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_line_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_line_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_malformed_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_malformed_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_malformed_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_malformed_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_max_cookie_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_max_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_max_cookie_max_cookie=dict(required=False, type="int"),
+ constraint_max_cookie_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_max_cookie_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_max_header_line_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_max_header_line_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_max_header_line_max_header_line=dict(required=False, type="int"),
+ constraint_max_header_line_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_max_header_line_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_max_range_segment_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_max_range_segment_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_max_range_segment_max_range_segment=dict(required=False, type="int"),
+ constraint_max_range_segment_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_max_range_segment_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_max_url_param_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_max_url_param_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_max_url_param_max_url_param=dict(required=False, type="int"),
+ constraint_max_url_param_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_max_url_param_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_method_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_method_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_method_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_param_length_length=dict(required=False, type="int"),
+ constraint_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_url_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_url_param_length_length=dict(required=False, type="int"),
+ constraint_url_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_url_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_url_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ constraint_version_action=dict(required=False, type="str", choices=["allow", "block"]),
+ constraint_version_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ constraint_version_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ constraint_version_status=dict(required=False, type="str", choices=["disable", "enable"]),
+ method=dict(required=False, type="list"),
+ method_default_allowed_methods=dict(required=False, type="str", choices=["delete",
+ "get",
+ "head",
+ "options",
+ "post",
+ "put",
+ "trace",
+ "others",
+ "connect"]),
+ method_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ method_status=dict(required=False, type="str", choices=["disable", "enable"]),
+
+ method_method_policy_address=dict(required=False, type="str"),
+ method_method_policy_allowed_methods=dict(required=False, type="str", choices=["delete",
+ "get",
+ "head",
+ "options",
+ "post",
+ "put",
+ "trace",
+ "others",
+ "connect"]),
+ method_method_policy_pattern=dict(required=False, type="str"),
+ method_method_policy_regex=dict(required=False, type="str", choices=["disable", "enable"]),
+ signature=dict(required=False, type="list"),
+ signature_credit_card_detection_threshold=dict(required=False, type="int"),
+ signature_disabled_signature=dict(required=False, type="str"),
+ signature_disabled_sub_class=dict(required=False, type="str"),
+
+ signature_custom_signature_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
+ signature_custom_signature_case_sensitivity=dict(required=False, type="str", choices=["disable", "enable"]),
+ signature_custom_signature_direction=dict(required=False, type="str", choices=["request", "response"]),
+ signature_custom_signature_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ signature_custom_signature_name=dict(required=False, type="str"),
+ signature_custom_signature_pattern=dict(required=False, type="str"),
+ signature_custom_signature_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ signature_custom_signature_status=dict(required=False, type="str", choices=["disable", "enable"]),
+ signature_custom_signature_target=dict(required=False, type="str", choices=["arg",
+ "arg-name",
+ "req-body",
+ "req-cookie",
+ "req-cookie-name",
+ "req-filename",
+ "req-header",
+ "req-header-name",
+ "req-raw-uri",
+ "req-uri",
+ "resp-body",
+ "resp-hdr",
+ "resp-status"]),
+
+ signature_main_class_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
+ signature_main_class_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ signature_main_class_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+ signature_main_class_status=dict(required=False, type="str", choices=["disable", "enable"]),
+ url_access=dict(required=False, type="list"),
+ url_access_action=dict(required=False, type="str", choices=["bypass", "permit", "block"]),
+ url_access_address=dict(required=False, type="str"),
+ url_access_log=dict(required=False, type="str", choices=["disable", "enable"]),
+ url_access_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
+
+ url_access_access_pattern_negate=dict(required=False, type="str", choices=["disable", "enable"]),
+ url_access_access_pattern_pattern=dict(required=False, type="str"),
+ url_access_access_pattern_regex=dict(required=False, type="str", choices=["disable", "enable"]),
+ url_access_access_pattern_srcaddr=dict(required=False, type="str"),
+
+ )
+
+ module = AnsibleModule(argument_spec, supports_check_mode=False)
+
+ # MODULE PARAMGRAM
+ paramgram = {
+ "mode": module.params["mode"],
+ "adom": module.params["adom"],
+ "name": module.params["name"],
+ "external": module.params["external"],
+ "extended-log": module.params["extended_log"],
+ "comment": module.params["comment"],
+ "address-list": {
+ "blocked-address": module.params["address_list_blocked_address"],
+ "blocked-log": module.params["address_list_blocked_log"],
+ "severity": module.params["address_list_severity"],
+ "status": module.params["address_list_status"],
+ "trusted-address": module.params["address_list_trusted_address"],
+ },
+ "constraint": {
+ "content-length": {
+ "action": module.params["constraint_content_length_action"],
+ "length": module.params["constraint_content_length_length"],
+ "log": module.params["constraint_content_length_log"],
+ "severity": module.params["constraint_content_length_severity"],
+ "status": module.params["constraint_content_length_status"],
+ },
+ "exception": {
+ "address": module.params["constraint_exception_address"],
+ "content-length": module.params["constraint_exception_content_length"],
+ "header-length": module.params["constraint_exception_header_length"],
+ "hostname": module.params["constraint_exception_hostname"],
+ "line-length": module.params["constraint_exception_line_length"],
+ "malformed": module.params["constraint_exception_malformed"],
+ "max-cookie": module.params["constraint_exception_max_cookie"],
+ "max-header-line": module.params["constraint_exception_max_header_line"],
+ "max-range-segment": module.params["constraint_exception_max_range_segment"],
+ "max-url-param": module.params["constraint_exception_max_url_param"],
+ "method": module.params["constraint_exception_method"],
+ "param-length": module.params["constraint_exception_param_length"],
+ "pattern": module.params["constraint_exception_pattern"],
+ "regex": module.params["constraint_exception_regex"],
+ "url-param-length": module.params["constraint_exception_url_param_length"],
+ "version": module.params["constraint_exception_version"],
+ },
+ "header-length": {
+ "action": module.params["constraint_header_length_action"],
+ "length": module.params["constraint_header_length_length"],
+ "log": module.params["constraint_header_length_log"],
+ "severity": module.params["constraint_header_length_severity"],
+ "status": module.params["constraint_header_length_status"],
+ },
+ "hostname": {
+ "action": module.params["constraint_hostname_action"],
+ "log": module.params["constraint_hostname_log"],
+ "severity": module.params["constraint_hostname_severity"],
+ "status": module.params["constraint_hostname_status"],
+ },
+ "line-length": {
+ "action": module.params["constraint_line_length_action"],
+ "length": module.params["constraint_line_length_length"],
+ "log": module.params["constraint_line_length_log"],
+ "severity": module.params["constraint_line_length_severity"],
+ "status": module.params["constraint_line_length_status"],
+ },
+ "malformed": {
+ "action": module.params["constraint_malformed_action"],
+ "log": module.params["constraint_malformed_log"],
+ "severity": module.params["constraint_malformed_severity"],
+ "status": module.params["constraint_malformed_status"],
+ },
+ "max-cookie": {
+ "action": module.params["constraint_max_cookie_action"],
+ "log": module.params["constraint_max_cookie_log"],
+ "max-cookie": module.params["constraint_max_cookie_max_cookie"],
+ "severity": module.params["constraint_max_cookie_severity"],
+ "status": module.params["constraint_max_cookie_status"],
+ },
+ "max-header-line": {
+ "action": module.params["constraint_max_header_line_action"],
+ "log": module.params["constraint_max_header_line_log"],
+ "max-header-line": module.params["constraint_max_header_line_max_header_line"],
+ "severity": module.params["constraint_max_header_line_severity"],
+ "status": module.params["constraint_max_header_line_status"],
+ },
+ "max-range-segment": {
+ "action": module.params["constraint_max_range_segment_action"],
+ "log": module.params["constraint_max_range_segment_log"],
+ "max-range-segment": module.params["constraint_max_range_segment_max_range_segment"],
+ "severity": module.params["constraint_max_range_segment_severity"],
+ "status": module.params["constraint_max_range_segment_status"],
+ },
+ "max-url-param": {
+ "action": module.params["constraint_max_url_param_action"],
+ "log": module.params["constraint_max_url_param_log"],
+ "max-url-param": module.params["constraint_max_url_param_max_url_param"],
+ "severity": module.params["constraint_max_url_param_severity"],
+ "status": module.params["constraint_max_url_param_status"],
+ },
+ "method": {
+ "action": module.params["constraint_method_action"],
+ "log": module.params["constraint_method_log"],
+ "severity": module.params["constraint_method_severity"],
+ "status": module.params["constraint_method_status"],
+ },
+ "param-length": {
+ "action": module.params["constraint_param_length_action"],
+ "length": module.params["constraint_param_length_length"],
+ "log": module.params["constraint_param_length_log"],
+ "severity": module.params["constraint_param_length_severity"],
+ "status": module.params["constraint_param_length_status"],
+ },
+ "url-param-length": {
+ "action": module.params["constraint_url_param_length_action"],
+ "length": module.params["constraint_url_param_length_length"],
+ "log": module.params["constraint_url_param_length_log"],
+ "severity": module.params["constraint_url_param_length_severity"],
+ "status": module.params["constraint_url_param_length_status"],
+ },
+ "version": {
+ "action": module.params["constraint_version_action"],
+ "log": module.params["constraint_version_log"],
+ "severity": module.params["constraint_version_severity"],
+ "status": module.params["constraint_version_status"],
+ },
+ },
+ "method": {
+ "default-allowed-methods": module.params["method_default_allowed_methods"],
+ "log": module.params["method_log"],
+ "severity": module.params["method_severity"],
+ "status": module.params["method_status"],
+ "method-policy": {
+ "address": module.params["method_method_policy_address"],
+ "allowed-methods": module.params["method_method_policy_allowed_methods"],
+ "pattern": module.params["method_method_policy_pattern"],
+ "regex": module.params["method_method_policy_regex"],
+ },
+ },
+ "signature": {
+ "credit-card-detection-threshold": module.params["signature_credit_card_detection_threshold"],
+ "disabled-signature": module.params["signature_disabled_signature"],
+ "disabled-sub-class": module.params["signature_disabled_sub_class"],
+ "custom-signature": {
+ "action": module.params["signature_custom_signature_action"],
+ "case-sensitivity": module.params["signature_custom_signature_case_sensitivity"],
+ "direction": module.params["signature_custom_signature_direction"],
+ "log": module.params["signature_custom_signature_log"],
+ "name": module.params["signature_custom_signature_name"],
+ "pattern": module.params["signature_custom_signature_pattern"],
+ "severity": module.params["signature_custom_signature_severity"],
+ "status": module.params["signature_custom_signature_status"],
+ "target": module.params["signature_custom_signature_target"],
+ },
+ "main-class": {
+ "action": module.params["signature_main_class_action"],
+ "log": module.params["signature_main_class_log"],
+ "severity": module.params["signature_main_class_severity"],
+ "status": module.params["signature_main_class_status"],
+ },
+ },
+ "url-access": {
+ "action": module.params["url_access_action"],
+ "address": module.params["url_access_address"],
+ "log": module.params["url_access_log"],
+ "severity": module.params["url_access_severity"],
+ "access-pattern": {
+ "negate": module.params["url_access_access_pattern_negate"],
+ "pattern": module.params["url_access_access_pattern_pattern"],
+ "regex": module.params["url_access_access_pattern_regex"],
+ "srcaddr": module.params["url_access_access_pattern_srcaddr"],
+ }
+ }
+ }
+
+ list_overrides = ['address-list', 'constraint', 'method', 'signature', 'url-access']
+ for list_variable in list_overrides:
+ override_data = list()
+ try:
+ override_data = module.params[list_variable]
+ except BaseException:
+ pass
+ try:
+ if override_data:
+ del paramgram[list_variable]
+ paramgram[list_variable] = override_data
+ except BaseException:
+ pass
+
+ # CHECK IF THE HOST/USERNAME/PW EXISTS, AND IF IT DOES, LOGIN.
+ host = module.params["host"]
+ password = module.params["password"]
+ username = module.params["username"]
+ if host is None or username is None or password is None:
+ module.fail_json(msg="Host and username and password are required")
+
+ # CHECK IF LOGIN FAILED
+ fmg = AnsibleFortiManager(module, module.params["host"], module.params["username"], module.params["password"])
+
+ response = fmg.login()
+ if response[1]['status']['code'] != 0:
+ module.fail_json(msg="Connection to FortiManager Failed")
+
+ results = fmgr_waf_profile_addsetdelete(fmg, paramgram)
+ if results[0] != 0:
+ fmgr_logout(fmg, module, results=results, good_codes=[0])
+
+ fmg.logout()
+
+ if results is not None:
+ return module.exit_json(**results[1])
+ else:
+ return module.exit_json(msg="No results were returned from the API call.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/units/modules/network/fortimanager/fixtures/test_fmgr_secprof_waf.json b/test/units/modules/network/fortimanager/fixtures/test_fmgr_secprof_waf.json
new file mode 100644
index 0000000000..1fa90d75a5
--- /dev/null
+++ b/test/units/modules/network/fortimanager/fixtures/test_fmgr_secprof_waf.json
@@ -0,0 +1,360 @@
+{
+ "fmgr_waf_profile_addsetdelete": [
+ {
+ "paramgram_used": {
+ "comment": "Created by Ansible Module TEST",
+ "name": "Ansible_WAF_Profile",
+ "adom": "root",
+ "address-list": {
+ "blocked-address": null,
+ "status": null,
+ "severity": null,
+ "blocked-log": null,
+ "trusted-address": null
+ },
+ "constraint": {
+ "header-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "content-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "max-cookie": {
+ "action": null,
+ "status": null,
+ "max-cookie": null,
+ "log": null,
+ "severity": null
+ },
+ "url-param-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "hostname": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "line-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "exception": {
+ "regex": null,
+ "header-length": null,
+ "content-length": null,
+ "max-cookie": null,
+ "pattern": null,
+ "hostname": null,
+ "line-length": null,
+ "max-range-segment": null,
+ "url-param-length": null,
+ "version": null,
+ "param-length": null,
+ "malformed": null,
+ "address": null,
+ "max-url-param": null,
+ "max-header-line": null,
+ "method": null
+ },
+ "max-range-segment": {
+ "action": null,
+ "status": null,
+ "max-range-segment": null,
+ "severity": null,
+ "log": null
+ },
+ "version": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "param-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "malformed": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "max-url-param": {
+ "action": null,
+ "status": null,
+ "max-url-param": null,
+ "log": null,
+ "severity": null
+ },
+ "max-header-line": {
+ "action": null,
+ "status": null,
+ "max-header-line": null,
+ "log": null,
+ "severity": null
+ },
+ "method": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ }
+ },
+ "extended-log": null,
+ "url-access": {
+ "action": null,
+ "address": null,
+ "severity": null,
+ "access-pattern": {
+ "negate": null,
+ "pattern": null,
+ "srcaddr": null,
+ "regex": null
+ },
+ "log": null
+ },
+ "external": null,
+ "signature": {
+ "custom-signature": {
+ "status": null,
+ "direction": null,
+ "target": null,
+ "severity": null,
+ "case-sensitivity": null,
+ "name": null,
+ "pattern": null,
+ "action": null,
+ "log": null
+ },
+ "credit-card-detection-threshold": null,
+ "main-class": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "disabled-signature": null,
+ "disabled-sub-class": null
+ },
+ "method": {
+ "status": null,
+ "severity": null,
+ "default-allowed-methods": null,
+ "log": null,
+ "method-policy": {
+ "regex": null,
+ "pattern": null,
+ "allowed-methods": null,
+ "address": null
+ }
+ },
+ "mode": "delete"
+ },
+ "raw_response": {
+ "status": {
+ "message": "OK",
+ "code": 0
+ },
+ "url": "/pm/config/adom/root/obj/waf/profile/Ansible_WAF_Profile"
+ },
+ "post_method": "delete"
+ },
+ {
+ "raw_response": {
+ "status": {
+ "message": "OK",
+ "code": 0
+ },
+ "url": "/pm/config/adom/root/obj/waf/profile"
+ },
+ "paramgram_used": {
+ "comment": "Created by Ansible Module TEST",
+ "adom": "root",
+ "address-list": {
+ "blocked-address": null,
+ "status": null,
+ "severity": null,
+ "blocked-log": null,
+ "trusted-address": null
+ },
+ "extended-log": null,
+ "url-access": {
+ "action": null,
+ "severity": null,
+ "log": null,
+ "access-pattern": {
+ "negate": null,
+ "pattern": null,
+ "srcaddr": null,
+ "regex": null
+ },
+ "address": null
+ },
+ "external": null,
+ "name": "Ansible_WAF_Profile",
+ "constraint": {
+ "content-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "max-cookie": {
+ "action": null,
+ "status": null,
+ "max-cookie": null,
+ "log": null,
+ "severity": null
+ },
+ "line-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "max-range-segment": {
+ "action": null,
+ "severity": null,
+ "status": null,
+ "log": null,
+ "max-range-segment": null
+ },
+ "param-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "malformed": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "max-url-param": {
+ "action": null,
+ "status": null,
+ "max-url-param": null,
+ "log": null,
+ "severity": null
+ },
+ "header-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "exception": {
+ "regex": null,
+ "header-length": null,
+ "content-length": null,
+ "max-cookie": null,
+ "pattern": null,
+ "hostname": null,
+ "line-length": null,
+ "max-range-segment": null,
+ "url-param-length": null,
+ "version": null,
+ "param-length": null,
+ "malformed": null,
+ "address": null,
+ "max-url-param": null,
+ "max-header-line": null,
+ "method": null
+ },
+ "hostname": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "url-param-length": {
+ "action": null,
+ "status": null,
+ "length": null,
+ "log": null,
+ "severity": null
+ },
+ "version": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "max-header-line": {
+ "action": null,
+ "status": null,
+ "max-header-line": null,
+ "log": null,
+ "severity": null
+ },
+ "method": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ }
+ },
+ "mode": "set",
+ "signature": {
+ "custom-signature": {
+ "status": null,
+ "direction": null,
+ "log": null,
+ "severity": null,
+ "target": null,
+ "action": null,
+ "pattern": null,
+ "case-sensitivity": null,
+ "name": null
+ },
+ "credit-card-detection-threshold": null,
+ "main-class": {
+ "action": null,
+ "status": null,
+ "log": null,
+ "severity": null
+ },
+ "disabled-signature": null,
+ "disabled-sub-class": null
+ },
+ "method": {
+ "status": null,
+ "default-allowed-methods": null,
+ "method-policy": {
+ "regex": null,
+ "pattern": null,
+ "allowed-methods": null,
+ "address": null
+ },
+ "log": null,
+ "severity": null
+ }
+ },
+ "post_method": "set"
+ }
+ ]
+}
diff --git a/test/units/modules/network/fortimanager/test_fmgr_secprof_waf.py b/test/units/modules/network/fortimanager/test_fmgr_secprof_waf.py
new file mode 100644
index 0000000000..e1f0b35625
--- /dev/null
+++ b/test/units/modules/network/fortimanager/test_fmgr_secprof_waf.py
@@ -0,0 +1,131 @@
+# Copyright 2018 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+from pyFMG.fortimgr import FortiManager
+import pytest
+
+try:
+ from ansible.modules.network.fortimanager import fmgr_secprof_waf
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+fmg_instance = FortiManager("1.1.1.1", "admin", "")
+
+
+def load_fixtures():
+ fixture_path = os.path.join(
+ os.path.dirname(__file__),
+ 'fixtures') + "/{filename}.json".format(
+ filename=os.path.splitext(
+ os.path.basename(__file__))[0])
+ try:
+ with open(fixture_path, "r") as fixture_file:
+ fixture_data = json.load(fixture_file)
+ except IOError:
+ return []
+ return [fixture_data]
+
+
+@pytest.fixture(scope="function", params=load_fixtures())
+def fixture_data(request):
+ func_name = request.function.__name__.replace("test_", "")
+ return request.param.get(func_name, None)
+
+
+def test_fmgr_waf_profile_addsetdelete(fixture_data, mocker):
+ mocker.patch("pyFMG.fortimgr.FortiManager._post_request", side_effect=fixture_data)
+ # Fixture sets used:###########################
+
+ ##################################################
+ # comment: Created by Ansible Module TEST
+ # name: Ansible_WAF_Profile
+ # adom: root
+ # address-list: {'blocked-address': None, 'status': None, 'severity': None, 'blocked-log': None,
+ # 'trusted-address': None}
+ # constraint: {'header-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'content-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'max-cookie': {'action': None, 'status': None, 'max-cookie': None, 'log': None, 'severity': None},
+ # 'url-param-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'hostname': {'action': None, 'status': None, 'log': None, 'severity': None},
+ # 'line-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'exception': {'regex': None, 'header-length': None, 'content-length': None, 'max-cookie': None, 'pattern': None,
+ # 'hostname': None, 'line-length': None, 'max-range-segment': None, 'url-param-length': None, 'version': None,
+ # 'param-length': None, 'malformed': None, 'address': None, 'max-url-param': None, 'max-header-line': None,
+ # 'method': None}, 'max-range-segment': {'action': None, 'status': None, 'max-range-segment': None,
+ # 'severity': None, 'log': None}, 'version': {'action': None, 'status': None, 'log': None, 'severity': None},
+ # 'param-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'malformed': {'action': None, 'status': None, 'log': None, 'severity': None}, 'max-url-param': {'action': None,
+ # 'status': None, 'max-url-param': None, 'log': None, 'severity': None}, 'max-header-line': {'action': None,
+ # 'status': None, 'max-header-line': None, 'log': None, 'severity': None}, 'method': {'action': None,
+ # 'status': None, 'log': None, 'severity': None}}
+ # extended-log: None
+ # url-access: {'action': None, 'address': None, 'severity': None, 'access-pattern': {'negate': None,
+ # 'pattern': None, 'srcaddr': None, 'regex': None}, 'log': None}
+ # external: None
+ # signature: {'custom-signature': {'status': None, 'direction': None, 'target': None, 'severity': None,
+ # 'case-sensitivity': None, 'name': None, 'pattern': None, 'action': None, 'log': None},
+ # 'credit-card-detection-threshold': None, 'main-class': {'action': None, 'status': None, 'log': None,
+ # 'severity': None}, 'disabled-signature': None, 'disabled-sub-class': None}
+ # method: {'status': None, 'severity': None, 'default-allowed-methods': None, 'log': None,
+ # 'method-policy': {'regex': None, 'pattern': None, 'allowed-methods': None, 'address': None}}
+ # mode: delete
+ ##################################################
+ ##################################################
+ # comment: Created by Ansible Module TEST
+ # adom: root
+ # address-list: {'blocked-address': None, 'status': None, 'severity': None, 'blocked-log': None,
+ # 'trusted-address': None}
+ # extended-log: None
+ # url-access: {'action': None, 'severity': None, 'log': None, 'access-pattern': {'negate': None, 'pattern': None,
+ # 'srcaddr': None, 'regex': None}, 'address': None}
+ # external: None
+ # name: Ansible_WAF_Profile
+ # constraint: {'content-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'max-cookie': {'action': None, 'status': None, 'max-cookie': None, 'log': None, 'severity': None},
+ # 'line-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'max-range-segment': {'action': None, 'severity': None, 'status': None, 'log': None, 'max-range-segment': None},
+ # 'param-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'malformed': {'action': None, 'status': None, 'log': None, 'severity': None}, 'max-url-param': {'action': None,
+ # 'status': None, 'max-url-param': None, 'log': None, 'severity': None}, 'header-length': {'action': None,
+ # 'status': None, 'length': None, 'log': None, 'severity': None}, 'exception': {'regex': None,
+ # 'header-length': None, 'content-length': None, 'max-cookie': None, 'pattern': None, 'hostname': None,
+ # 'line-length': None, 'max-range-segment': None, 'url-param-length': None, 'version': None, 'param-length': None,
+ # 'malformed': None, 'address': None, 'max-url-param': None, 'max-header-line': None, 'method': None},
+ # 'hostname': {'action': None, 'status': None, 'log': None, 'severity': None},
+ # 'url-param-length': {'action': None, 'status': None, 'length': None, 'log': None, 'severity': None},
+ # 'version': {'action': None, 'status': None, 'log': None, 'severity': None}, 'max-header-line': {'action': None,
+ # 'status': None, 'max-header-line': None, 'log': None, 'severity': None}, 'method': {'action': None,
+ # 'status': None, 'log': None, 'severity': None}}
+ # mode: set
+ # signature: {'custom-signature': {'status': None, 'direction': None, 'log': None, 'severity': None, 'target': None,
+ # 'action': None, 'pattern': None, 'case-sensitivity': None, 'name': None},
+ # 'credit-card-detection-threshold': None, 'main-class': {'action': None, 'status': None, 'log': None,
+ # 'severity': None}, 'disabled-signature': None, 'disabled-sub-class': None}
+ # method: {'status': None, 'default-allowed-methods': None, 'method-policy': {'regex': None, 'pattern': None,
+ # 'allowed-methods': None, 'address': None}, 'log': None, 'severity': None}
+ ##################################################
+
+ # Test using fixture 1 #
+ output = fmgr_secprof_waf.fmgr_waf_profile_addsetdelete(fmg_instance, fixture_data[0]['paramgram_used'])
+ assert output['raw_response']['status']['code'] == 0
+ # Test using fixture 2 #
+ output = fmgr_secprof_waf.fmgr_waf_profile_addsetdelete(fmg_instance, fixture_data[1]['paramgram_used'])
+ assert output['raw_response']['status']['code'] == 0