diff --git a/README.md b/README.md
index ebbd3cb..1bf8017 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ Table of Contents
* [Custom Request Handler](#custom_request_handler)
* [Additional Activity Handler](#additional_activity_handler)
* [Px Disable Request](#px_disable_request)
+ * [Test Block Flow on Monitoring Mode](#bypass_monitor_header)
## Installation
@@ -254,3 +255,21 @@ environ['px_disable_request'] = True #The enforcer shall be disabled for that re
```
+#### Test Block Flow on Monitoring Mode
+
+Allows you to test an enforcer’s blocking flow while you are still in Monitor Mode.
+
+When the header name is set(eg. `x-px-block`) and the value is set to `1`, when there is a block response (for example from using a User-Agent header with the value of `PhantomJS/1.0`) the Monitor Mode is bypassed and full block mode is applied. If one of the conditions is missing you will stay in Monitor Mode. This is done per request.
+To stay in Monitor Mode, set the header value to `0`.
+
+The Header Name is configurable using the `bypass_monitor_header` property.
+
+**Default:** Empty
+
+```python
+config = {
+ ...
+ bypass_monitor_header: 'x-px-block',
+ ...
+}
+```
diff --git a/perimeterx/px_config.py b/perimeterx/px_config.py
index e430945..caa90ff 100644
--- a/perimeterx/px_config.py
+++ b/perimeterx/px_config.py
@@ -37,6 +37,7 @@ def __init__(self, config_dict):
self._ip_headers = config_dict.get('ip_headers', [])
self._proxy_url = config_dict.get('proxy_url', None)
self._max_buffer_len = config_dict.get('max_buffer_len', 30)
+ self._bypass_monitor_header = config_dict.get('bypass_monitor_header','')
sensitive_routes = config_dict.get('sensitive_routes', [])
if not isinstance(sensitive_routes, list):
@@ -191,6 +192,10 @@ def enrich_custom_parameters(self):
def testing_mode(self):
return self._testing_mode
+ @property
+ def bypass_monitor_header(self):
+ return self._bypass_monitor_header
+
def __instantiate_user_defined_handlers(self, config_dict):
self._custom_request_handler = self.__set_handler('custom_request_handler', config_dict)
self._get_user_ip = self.__set_handler('get_user_ip', config_dict)
diff --git a/perimeterx/px_request_verifier.py b/perimeterx/px_request_verifier.py
index 4ca19ca..6e7f01e 100644
--- a/perimeterx/px_request_verifier.py
+++ b/perimeterx/px_request_verifier.py
@@ -50,9 +50,10 @@ def handle_verification(self, ctx, request):
else:
logger.debug('Risk score is higher or equal than blocking score')
self.report_block_traffic(ctx)
+ should_bypass_monitor = config.bypass_monitor_header and ctx.headers.get(config.bypass_monitor_header) == '1';
if config.additional_activity_handler:
config.additional_activity_handler(ctx, config)
- if config.module_mode == px_constants.MODULE_MODE_BLOCKING:
+ if config.module_mode == px_constants.MODULE_MODE_BLOCKING or should_bypass_monitor:
data, headers, status = self.px_blocker.handle_blocking(ctx=ctx, config=config)
response_function = generate_blocking_response(data, headers, status)
else:
diff --git a/test/test_px_request_validator.py b/test/test_px_request_validator.py
index ac5dc33..410624c 100644
--- a/test/test_px_request_validator.py
+++ b/test/test_px_request_validator.py
@@ -71,3 +71,92 @@ def test_handle_verification_failed(self):
context.score = 100
response = self.request_handler.handle_verification(context, request)
self.assertEqual(response.status, '403 Forbidden')
+
+ def test_handle_monitor(self):
+ config = PxConfig({'app_id': 'PXfake_app_id',
+ 'auth_token': '',
+ 'module_mode': px_constants.MODULE_MODE_MONITORING
+ });
+ request_handler = PxRequestVerifier(config)
+ builder = EnvironBuilder(headers=self.headers, path='/')
+ env = builder.get_environ()
+ request = Request(env)
+ context = PxContext(request, request_handler.config)
+ context.score = 100
+ response = request_handler.handle_verification(context, request)
+ self.assertEqual(response, True)
+
+ def test_bypass_monitor_header_enabled(self):
+ config = PxConfig({'app_id': 'PXfake_app_id',
+ 'auth_token': '',
+ 'module_mode': px_constants.MODULE_MODE_MONITORING,
+ 'bypass_monitor_header': 'x-px-block'
+ });
+ headers = {'X-FORWARDED-FOR': '127.0.0.1',
+ 'remote-addr': '127.0.0.1',
+ 'x-px-block': '1',
+ 'content_length': '100'}
+ request_handler = PxRequestVerifier(config)
+ builder = EnvironBuilder(headers=headers, path='/')
+ env = builder.get_environ()
+ request = Request(env)
+ context = PxContext(request, request_handler.config)
+ context.score = 100
+ response = request_handler.handle_verification(context, request)
+ self.assertEqual(response.status, '403 Forbidden')
+
+ def test_bypass_monitor_header_disabled(self):
+ config = PxConfig({'app_id': 'PXfake_app_id',
+ 'auth_token': '',
+ 'module_mode': px_constants.MODULE_MODE_MONITORING,
+ 'bypass_monitor_header': 'x-px-block'
+ });
+ headers = {'X-FORWARDED-FOR': '127.0.0.1',
+ 'remote-addr': '127.0.0.1',
+ 'x-px-block': '0',
+ 'content_length': '100'}
+ request_handler = PxRequestVerifier(config)
+ builder = EnvironBuilder(headers=headers, path='/')
+ env = builder.get_environ()
+ request = Request(env)
+ context = PxContext(request, request_handler.config)
+ context.score = 100
+ response = request_handler.handle_verification(context, request)
+ self.assertEqual(response, True)
+
+ def test_bypass_monitor_header_configured_but_missing(self):
+ config = PxConfig({'app_id': 'PXfake_app_id',
+ 'auth_token': '',
+ 'module_mode': px_constants.MODULE_MODE_MONITORING,
+ 'bypass_monitor_header': 'x-px-block'
+ });
+ headers = {'X-FORWARDED-FOR': '127.0.0.1',
+ 'remote-addr': '127.0.0.1',
+ 'content_length': '100'}
+ request_handler = PxRequestVerifier(config)
+ builder = EnvironBuilder(headers=headers, path='/')
+ env = builder.get_environ()
+ request = Request(env)
+ context = PxContext(request, request_handler.config)
+ context.score = 100
+ response = request_handler.handle_verification(context, request)
+ self.assertEqual(response, True)
+
+ def test_bypass_monitor_header_on_valid_request(self):
+ config = PxConfig({'app_id': 'PXfake_app_id',
+ 'auth_token': '',
+ 'module_mode': px_constants.MODULE_MODE_MONITORING,
+ 'bypass_monitor_header': 'x-px-block'
+ });
+ headers = {'X-FORWARDED-FOR': '127.0.0.1',
+ 'remote-addr': '127.0.0.1',
+ 'x-px-block': '1',
+ 'content_length': '100'}
+ request_handler = PxRequestVerifier(config)
+ builder = EnvironBuilder(headers=headers, path='/')
+ env = builder.get_environ()
+ request = Request(env)
+ context = PxContext(request, request_handler.config)
+ context.score = 0
+ response = request_handler.handle_verification(context, request)
+ self.assertEqual(response, True)
\ No newline at end of file