adds new module for asm dos application profiles (#61063)

This commit is contained in:
Wojciech Wypior 2019-08-22 04:50:07 +01:00 committed by Tim Rupp
parent 0210447fa7
commit 306b6b728c
3 changed files with 1863 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,276 @@
{
"kind": "tm:security:dos:profile:application:applicationstate",
"name": "test",
"fullPath": "test",
"generation": 1442,
"selfLink": "https://localhost/mgmt/tm/security/dos/profile/~Common~test/application/test?ver=13.1.1.4",
"botDefense": {
"browserLegitCaptcha": "enabled",
"browserLegitEnabled": "enabled",
"crossDomainRequests": "allow-all",
"gracePeriod": 300,
"mode": "disabled"
},
"botSignatures": {
"check": "disabled",
"categories": [
{
"name": "DOS Tool",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~DOS%20Tool?ver=13.1.1.4"
}
},
{
"name": "E-Mail Collector",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~E-Mail%20Collector?ver=13.1.1.4"
}
},
{
"name": "Exploit Tool",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Exploit%20Tool?ver=13.1.1.4"
}
},
{
"name": "Network Scanner",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Network%20Scanner?ver=13.1.1.4"
}
},
{
"name": "Search Engine",
"partition": "Common",
"action": "report",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Search%20Engine?ver=13.1.1.4"
}
},
{
"name": "Spam Bot",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Spam%20Bot?ver=13.1.1.4"
}
},
{
"name": "Spyware",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Spyware?ver=13.1.1.4"
}
},
{
"name": "Vulnerability Scanner",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Vulnerability%20Scanner?ver=13.1.1.4"
}
},
{
"name": "Web Spider",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Web%20Spider?ver=13.1.1.4"
}
},
{
"name": "Webserver Stress Tool",
"partition": "Common",
"action": "block",
"nameReference": {
"link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Webserver%20Stress%20Tool?ver=13.1.1.4"
}
}
]
},
"captchaResponse": {
"failure": {
"body": "You have entered an invalid answer for the question. Please, try again.\n<br>\n%DOSL7.captcha.image% %DOSL7.captcha.change%\n<br>\n<b>What code is in the image\\?</b>\n%DOSL7.captcha.solution%\n<br>\n%DOSL7.captcha.submit%\n<br>\n<br>\nYour support ID is: %DOSL7.captcha.support_id%.",
"type": "default"
},
"first": {
"body": "This question is for testing whether you are a human visitor and to prevent automated spam submission.\n<br>\n%DOSL7.captcha.image% %DOSL7.captcha.change%\n<br>\n<b>What code is in the image\\?</b>\n%DOSL7.captcha.solution%\n<br>\n%DOSL7.captcha.submit%\n<br>\n<br>\nYour support ID is: %DOSL7.captcha.support_id%.",
"type": "default"
}
},
"heavyUrls": {
"automaticDetection": "enabled",
"exclude": [
"/exclude.html"
],
"latencyThreshold": 1000,
"protection": "disabled",
"includeList": [
{
"name": "URL/test.htm",
"threshold": "auto",
"url": "/test.htm"
},
{
"name": "URL/testy.htm",
"threshold": "auto",
"url": "/testy.htm"
}
]
},
"mobileDetection": {
"allowAndroidRootedDevice": "false",
"allowAnyAndroidPackage": "false",
"allowAnyIosPackage": "false",
"allowEmulators": "true",
"allowJailbrokenDevices": "true",
"clientSideChallengeMode": "pass",
"enabled": "disabled",
"iosAllowedPackageNames": [
"foobarapp"
],
"androidPublishers": [
{
"name": "ca-bundle.crt",
"partition": "Common",
"nameReference": {
"link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ca-bundle.crt?ver=13.1.1.4"
}
}
]
},
"rtbhDurationSec": 300,
"rtbhEnable": "enabled",
"scrubbingDurationSec": 60,
"scrubbingEnable": "enabled",
"singlePageApplication": "enabled",
"stressBased": {
"behavioral": {
"dosDetection": "disabled",
"mitigationMode": "none",
"signatures": "disabled",
"signaturesApprovedOnly": "disabled"
},
"deEscalationPeriod": 7200,
"deviceCaptchaChallenge": "disabled",
"deviceClientSideDefense": "disabled",
"deviceMaximumAutoTps": 5000,
"deviceMaximumTps": 200,
"deviceMinimumAutoTps": 5,
"deviceMinimumTps": 40,
"deviceRateLimiting": "disabled",
"deviceRequestBlockingMode": "rate-limit",
"deviceTpsIncreaseRate": 500,
"escalationPeriod": 120,
"geoCaptchaChallenge": "disabled",
"geoClientSideDefense": "disabled",
"geoMaximumAutoTps": 20000,
"geoMinimumAutoTps": 50,
"geoMinimumShare": 10,
"geoRateLimiting": "disabled",
"geoRequestBlockingMode": "rate-limit",
"geoShareIncreaseRate": 500,
"ipCaptchaChallenge": "disabled",
"ipClientSideDefense": "disabled",
"ipMaximumAutoTps": 5000,
"ipMaximumTps": 200,
"ipMinimumAutoTps": 5,
"ipMinimumTps": 40,
"ipRateLimiting": "enabled",
"ipRequestBlockingMode": "rate-limit",
"ipTpsIncreaseRate": 500,
"mode": "off",
"siteCaptchaChallenge": "disabled",
"siteClientSideDefense": "disabled",
"siteMaximumAutoTps": 20000,
"siteMaximumTps": 10000,
"siteMinimumAutoTps": 50,
"siteMinimumTps": 2000,
"siteRateLimiting": "disabled",
"siteTpsIncreaseRate": 500,
"thresholdsMode": "manual",
"urlCaptchaChallenge": "disabled",
"urlClientSideDefense": "disabled",
"urlEnableHeavy": "enabled",
"urlMaximumAutoTps": 5000,
"urlMaximumTps": 1000,
"urlMinimumAutoTps": 50,
"urlMinimumTps": 200,
"urlRateLimiting": "enabled",
"urlTpsIncreaseRate": 500
},
"tcpDump": {
"maximumDuration": 30,
"maximumSize": 10,
"recordTraffic": "disabled",
"repetitionInterval": "120"
},
"tpsBased": {
"deEscalationPeriod": 7200,
"deviceCaptchaChallenge": "disabled",
"deviceClientSideDefense": "disabled",
"deviceMaximumAutoTps": 5000,
"deviceMaximumTps": 200,
"deviceMinimumAutoTps": 5,
"deviceMinimumTps": 40,
"deviceRateLimiting": "disabled",
"deviceRequestBlockingMode": "rate-limit",
"deviceTpsIncreaseRate": 500,
"escalationPeriod": 120,
"geoCaptchaChallenge": "disabled",
"geoClientSideDefense": "disabled",
"geoMaximumAutoTps": 20000,
"geoMinimumAutoTps": 50,
"geoMinimumShare": 10,
"geoRateLimiting": "disabled",
"geoRequestBlockingMode": "rate-limit",
"geoShareIncreaseRate": 500,
"ipCaptchaChallenge": "disabled",
"ipClientSideDefense": "disabled",
"ipMaximumAutoTps": 5000,
"ipMaximumTps": 200,
"ipMinimumAutoTps": 5,
"ipMinimumTps": 40,
"ipRateLimiting": "enabled",
"ipRequestBlockingMode": "rate-limit",
"ipTpsIncreaseRate": 500,
"mode": "off",
"siteCaptchaChallenge": "disabled",
"siteClientSideDefense": "disabled",
"siteMaximumAutoTps": 20000,
"siteMaximumTps": 10000,
"siteMinimumAutoTps": 50,
"siteMinimumTps": 2000,
"siteRateLimiting": "disabled",
"siteTpsIncreaseRate": 500,
"thresholdsMode": "manual",
"urlCaptchaChallenge": "disabled",
"urlClientSideDefense": "disabled",
"urlEnableHeavy": "enabled",
"urlMaximumAutoTps": 5000,
"urlMaximumTps": 1000,
"urlMinimumAutoTps": 50,
"urlMinimumTps": 200,
"urlRateLimiting": "enabled",
"urlTpsIncreaseRate": 500
},
"triggerIrule": "enabled",
"geolocations": [
{
"name": "Afghanistan",
"blackListed": true
},
{
"name": "Aland Islands",
"whiteListed": true
}
]
}

View file

@ -0,0 +1,279 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, F5 Networks Inc.
# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
import sys
if sys.version_info < (2, 7):
pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
from ansible.module_utils.basic import AnsibleModule
try:
from library.modules.bigip_asm_dos_application import ApiParameters
from library.modules.bigip_asm_dos_application import ModuleParameters
from library.modules.bigip_asm_dos_application import ModuleManager
from library.modules.bigip_asm_dos_application import ArgumentSpec
# In Ansible 2.8, Ansible changed import paths.
from test.units.compat import unittest
from test.units.compat.mock import Mock
from test.units.compat.mock import patch
from test.units.modules.utils import set_module_args
except ImportError:
from ansible.modules.network.f5.bigip_asm_dos_application import ApiParameters
from ansible.modules.network.f5.bigip_asm_dos_application import ModuleParameters
from ansible.modules.network.f5.bigip_asm_dos_application import ModuleManager
from ansible.modules.network.f5.bigip_asm_dos_application import ArgumentSpec
# Ansible 2.8 imports
from units.compat import unittest
from units.compat.mock import Mock
from units.compat.mock import patch
from units.modules.utils import set_module_args
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
fixture_data = {}
def load_fixture(name):
path = os.path.join(fixture_path, name)
if path in fixture_data:
return fixture_data[path]
with open(path) as f:
data = f.read()
try:
data = json.loads(data)
except Exception:
pass
fixture_data[path] = data
return data
class TestParameters(unittest.TestCase):
def test_module_parameters(self):
args = dict(
profile='dos_foo',
geolocations=dict(
blacklist=['Argentina', 'Montenegro'],
whitelist=['France', 'Belgium']
),
heavy_urls=dict(
auto_detect=True,
latency_threshold=3000,
exclude=['/exclude1.html', '/exclude2.html'],
include=[dict(url='include1.html', threshold='auto'),
dict(url='include2.html', threshold='2000')],
),
mobile_detection=dict(
enabled=True,
allow_android_rooted_device=True,
allow_any_android_package=True,
allow_any_ios_package=True,
allow_jailbroken_devices=True,
allow_emulators=True,
client_side_challenge_mode='cshui',
ios_allowed_package_names=['foo', 'bar'],
android_publishers=['cert1.crt', 'cert2.crt']
),
rtbh_duration=180,
rtbh_enable=True,
scrubbing_duration=360,
scrubbing_enable=True,
single_page_application=True,
trigger_irule=False,
partition='Common'
)
p = ModuleParameters(params=args)
assert p.profile == 'dos_foo'
assert p.geo_whitelist == ['France', 'Belgium']
assert p.geo_blacklist == ['Argentina', 'Montenegro']
assert p.auto_detect == 'enabled'
assert p.latency_threshold == 3000
assert p.hw_url_exclude == ['/exclude1.html', '/exclude2.html']
assert dict(name='URL/include1.html', threshold='auto', url='/include1.html') in p.hw_url_include
assert dict(name='URL/include2.html', threshold='2000', url='/include2.html') in p.hw_url_include
assert p.allow_android_rooted_device == 'true'
assert p.enable_mobile_detection == 'enabled'
assert p.allow_any_android_package == 'true'
assert p.allow_any_ios_package == 'true'
assert p.allow_jailbroken_devices == 'true'
assert p.allow_emulators == 'true'
assert p.client_side_challenge_mode == 'cshui'
assert p.ios_allowed_package_names == ['foo', 'bar']
assert p.android_publishers == ['/Common/cert1.crt', '/Common/cert2.crt']
assert p.rtbh_duration == 180
assert p.rtbh_enable == 'enabled'
assert p.scrubbing_duration == 360
assert p.scrubbing_enable == 'enabled'
assert p.single_page_application == 'enabled'
assert p.trigger_irule == 'disabled'
def test_api_parameters(self):
args = load_fixture('load_asm_dos.json')
p = ApiParameters(params=args)
assert p.geo_whitelist == ['Aland Islands']
assert p.geo_blacklist == ['Afghanistan']
assert p.auto_detect == 'enabled'
assert p.latency_threshold == 1000
assert p.hw_url_exclude == ['/exclude.html']
assert dict(name='URL/test.htm', threshold='auto', url='/test.htm') in p.hw_url_include
assert dict(name='URL/testy.htm', threshold='auto', url='/testy.htm') in p.hw_url_include
assert p.allow_android_rooted_device == 'false'
assert p.enable_mobile_detection == 'disabled'
assert p.allow_any_android_package == 'false'
assert p.allow_any_ios_package == 'false'
assert p.allow_jailbroken_devices == 'true'
assert p.allow_emulators == 'true'
assert p.client_side_challenge_mode == 'pass'
assert p.ios_allowed_package_names == ['foobarapp']
assert p.android_publishers == ['/Common/ca-bundle.crt']
assert p.rtbh_duration == 300
assert p.rtbh_enable == 'enabled'
assert p.scrubbing_duration == 60
assert p.scrubbing_enable == 'enabled'
assert p.single_page_application == 'enabled'
assert p.trigger_irule == 'enabled'
class TestManager(unittest.TestCase):
def setUp(self):
self.spec = ArgumentSpec()
try:
self.p1 = patch('library.modules.bigip_asm_dos_application.module_provisioned')
self.m1 = self.p1.start()
self.m1.return_value = True
except Exception:
self.p1 = patch('ansible.modules.network.f5.bigip_asm_dos_application.module_provisioned')
self.m1 = self.p1.start()
self.m1.return_value = True
def tearDown(self):
self.p1.stop()
def test_create_asm_dos_profile(self, *args):
set_module_args(dict(
profile='dos_foo',
geolocations=dict(
blacklist=['Argentina', 'Montenegro'],
whitelist=['France', 'Belgium']
),
heavy_urls=dict(
auto_detect=True,
latency_threshold=3000,
exclude=['/exclude1.html', '/exclude2.html'],
include=[dict(url='include1.html', threshold='auto'),
dict(url='include2.html', threshold='2000')]
),
mobile_detection=dict(
enabled=True,
allow_android_rooted_device=True,
allow_any_android_package=True,
allow_any_ios_package=True,
allow_jailbroken_devices=True,
allow_emulators=True,
client_side_challenge_mode='cshui',
ios_allowed_package_names=['foo', 'bar'],
android_publishers=['cert1.crt', 'cert2.crt']
),
rtbh_duration=180,
rtbh_enable=True,
scrubbing_duration=360,
scrubbing_enable=True,
single_page_application=True,
trigger_irule=False,
partition='Common',
provider=dict(
server='localhost',
password='password',
user='admin'
)
))
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
)
# Override methods in the specific type of manager
mm = ModuleManager(module=module)
mm.exists = Mock(return_value=False)
mm.create_on_device = Mock(return_value=True)
mm.version_less_than_13_1 = Mock(return_value=False)
results = mm.exec_module()
assert results['changed'] is True
assert results['geolocations'] == dict(blacklist=['Argentina', 'Montenegro'], whitelist=['France', 'Belgium'])
assert results['heavy_urls'] == dict(auto_detect='yes', latency_threshold=3000,
exclude=['/exclude1.html', '/exclude2.html'],
include=[dict(url='/include1.html', threshold='auto'),
dict(url='/include2.html', threshold='2000')]
)
assert results['mobile_detection'] == dict(enabled='yes', allow_android_rooted_device='yes',
allow_any_android_package='yes', allow_any_ios_package='yes',
allow_jailbroken_devices='yes', allow_emulators='yes',
client_side_challenge_mode='cshui',
ios_allowed_package_names=['foo', 'bar'],
android_publishers=['/Common/cert1.crt', '/Common/cert2.crt']
)
assert results['rtbh_duration'] == 180
assert results['rtbh_enable'] == 'yes'
assert results['scrubbing_duration'] == 360
assert results['scrubbing_enable'] == 'yes'
assert results['single_page_application'] == 'yes'
assert results['trigger_irule'] == 'no'
def test_update_asm_dos_profile(self, *args):
set_module_args(dict(
profile='test',
heavy_urls=dict(
latency_threshold=3000,
exclude=['/exclude1.html', '/exclude2.html'],
include=[dict(url='include1.html', threshold='auto'),
dict(url='include2.html', threshold='2000')]
),
provider=dict(
server='localhost',
password='password',
user='admin'
)
))
current = ApiParameters(params=load_fixture('load_asm_dos.json'))
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
)
# Override methods in the specific type of manager
mm = ModuleManager(module=module)
mm.exists = Mock(return_value=True)
mm.update_on_device = Mock(return_value=True)
mm.read_current_from_device = Mock(return_value=current)
mm.version_less_than_13_1 = Mock(return_value=False)
results = mm.exec_module()
assert results['changed'] is True
assert results['heavy_urls'] == dict(latency_threshold=3000, exclude=['/exclude1.html', '/exclude2.html'],
include=[dict(url='/include1.html', threshold='auto'),
dict(url='/include2.html', threshold='2000')]
)