From 86242a021d55199f37c18826b5f8c99173bf84b0 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 1 Aug 2022 18:45:00 +0200 Subject: [PATCH 1/9] Island: Return island mode only as a string --- .../monkey_island/cc/resources/island_mode.py | 7 +++--- .../cc/resources/test_island_mode.py | 22 ++++++------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/monkey/monkey_island/cc/resources/island_mode.py b/monkey/monkey_island/cc/resources/island_mode.py index 5bd695b3d..07d5d8095 100644 --- a/monkey/monkey_island/cc/resources/island_mode.py +++ b/monkey/monkey_island/cc/resources/island_mode.py @@ -2,7 +2,7 @@ import json import logging from http import HTTPStatus -from flask import make_response, request +from flask import request from monkey_island.cc.models import IslandMode as IslandModeEnum from monkey_island.cc.resources.AbstractResource import AbstractResource @@ -21,8 +21,7 @@ class IslandMode(AbstractResource): @jwt_required def put(self): try: - body = json.loads(request.data) - mode = IslandModeEnum(body.get("mode")) + mode = IslandModeEnum(json.loads(request.data)) self._island_mode_service.set_mode(mode) @@ -35,4 +34,4 @@ class IslandMode(AbstractResource): @jwt_required def get(self): island_mode = self._island_mode_service.get_mode() - return make_response({"mode": island_mode.value}, HTTPStatus.OK) + return island_mode.value, HTTPStatus.OK diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py index 642c5c936..97aa300e0 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py @@ -38,24 +38,18 @@ def flask_client(build_flask_client): ) def test_island_mode_post(flask_client, mode): resp = flask_client.put( - IslandModeResource.urls[0], data=json.dumps({"mode": mode}), follow_redirects=True + IslandModeResource.urls[0], data=json.dumps(mode), follow_redirects=True ) assert resp.status_code == HTTPStatus.NO_CONTENT def test_island_mode_post__invalid_mode(flask_client): resp = flask_client.put( - IslandModeResource.urls[0], data=json.dumps({"mode": "bogus mode"}), follow_redirects=True + IslandModeResource.urls[0], data=json.dumps("bogus mode"), follow_redirects=True ) assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY -@pytest.mark.parametrize("invalid_json", ["42", "{test"]) -def test_island_mode_post__invalid_json(flask_client, invalid_json): - resp = flask_client.put(IslandModeResource.urls[0], data="{test", follow_redirects=True) - assert resp.status_code == HTTPStatus.BAD_REQUEST - - def test_island_mode_post__internal_server_error(build_flask_client): mock_island_mode_service = MagicMock(spec=IslandModeService) mock_island_mode_service.set_mode = MagicMock(side_effect=RetrievalError) @@ -66,7 +60,7 @@ def test_island_mode_post__internal_server_error(build_flask_client): with build_flask_client(container) as flask_client: resp = flask_client.put( IslandModeResource.urls[0], - data=json.dumps({"mode": IslandMode.RANSOMWARE.value}), + data=json.dumps(IslandMode.RANSOMWARE.value), follow_redirects=True, ) @@ -75,18 +69,16 @@ def test_island_mode_post__internal_server_error(build_flask_client): @pytest.mark.parametrize("mode", [IslandMode.RANSOMWARE.value, IslandMode.ADVANCED.value]) def test_island_mode_endpoint(flask_client, mode): - flask_client.put( - IslandModeResource.urls[0], data=json.dumps({"mode": mode}), follow_redirects=True - ) + flask_client.put(IslandModeResource.urls[0], data=json.dumps(mode), follow_redirects=True) resp = flask_client.get(IslandModeResource.urls[0], follow_redirects=True) assert resp.status_code == HTTPStatus.OK - assert json.loads(resp.data)["mode"] == mode + assert json.loads(resp.data) == mode def test_island_mode_endpoint__invalid_mode(flask_client): resp_post = flask_client.put( - IslandModeResource.urls[0], data=json.dumps({"mode": "bogus_mode"}), follow_redirects=True + IslandModeResource.urls[0], data=json.dumps("bogus_mode"), follow_redirects=True ) resp_get = flask_client.get(IslandModeResource.urls[0], follow_redirects=True) assert resp_post.status_code == HTTPStatus.UNPROCESSABLE_ENTITY - assert json.loads(resp_get.data)["mode"] == IslandMode.UNSET.value + assert json.loads(resp_get.data) == IslandMode.UNSET.value From cf084242f08a65363995cfda2bfcd4edd50b53f4 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 1 Aug 2022 18:51:00 +0200 Subject: [PATCH 2/9] UI: Use only string from api/island/mode --- monkey/monkey_island/cc/ui/src/components/Main.tsx | 2 +- .../monkey_island/cc/ui/src/components/pages/LandingPage.tsx | 2 +- .../cc/ui/src/components/ui-components/IslandResetModal.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/Main.tsx b/monkey/monkey_island/cc/ui/src/components/Main.tsx index d65c71a67..fd36b85a1 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.tsx +++ b/monkey/monkey_island/cc/ui/src/components/Main.tsx @@ -115,7 +115,7 @@ class AppComponent extends AuthComponent { setMode = () => { return IslandHttpClient.get('/api/island/mode') .then(res => { - this.setState({islandMode: res.body.mode}); + this.setState({islandMode: res.body}); }); } diff --git a/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx b/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx index 3c2bf1037..79d511758 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx +++ b/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx @@ -74,7 +74,7 @@ const LandingPageComponent = (props: Props) => { } function setScenario(scenario: string) { - IslandHttpClient.put('/api/island/mode', {'mode': scenario}) + IslandHttpClient.put('/api/island/mode', scenario) .then(() => { props.onStatusChange(); }); diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx b/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx index 67f3256b4..ac7a8afd6 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx @@ -111,9 +111,9 @@ const IslandResetModal = (props: Props) => { if (res.ok) { return auth.authFetch('/api/propagation-credentials/configured-credentials', {method: 'PUT', body:'[]'}) }}) - .then(res => { + .then(res => { if (res.ok) { - return auth.authFetch('/api/island/mode', {method: 'PUT', body: '{"mode": "unset"}'}) + return auth.authFetch('/api/island/mode', {method: 'PUT', body: '"unset"'}) }}) .then(res => { if (!res.ok) { From 53048c03ed95bc7cbb9070aa5e1f244ccf68b04d Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 1 Aug 2022 18:52:19 +0200 Subject: [PATCH 3/9] BB: Use string when unsetting island mode --- envs/monkey_zoo/blackbox/island_client/monkey_island_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 7b359abb3..53d02ae9d 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -120,7 +120,7 @@ class MonkeyIslandClient(object): assert False def _reset_island_mode(self): - if self.requests.put("api/island/mode", data='{"mode": "unset"}').ok: + if self.requests.put("api/island/mode", data='"unset"').ok: LOGGER.info("Resseting island mode after the test.") else: LOGGER.error("Failed to reset island mode") From c098afaee1c519f20fe8ad592121bf921e613198 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 2 Aug 2022 12:22:53 +0530 Subject: [PATCH 4/9] BB: Fix spelling in log message in MonkeyIslandClient --- envs/monkey_zoo/blackbox/island_client/monkey_island_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 53d02ae9d..c8142404d 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -121,7 +121,7 @@ class MonkeyIslandClient(object): def _reset_island_mode(self): if self.requests.put("api/island/mode", data='"unset"').ok: - LOGGER.info("Resseting island mode after the test.") + LOGGER.info("Resetting island mode after the test.") else: LOGGER.error("Failed to reset island mode") assert False From f652a489b71ef6a55279bba7ec9b2c708076cf7d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 3 Aug 2022 13:00:43 +0530 Subject: [PATCH 5/9] UI: Pass 'Content-Type' header in PUT request when resetting Island mode --- .../ui/src/components/ui-components/IslandResetModal.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx b/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx index ac7a8afd6..f5b47ac04 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/IslandResetModal.tsx @@ -113,7 +113,14 @@ const IslandResetModal = (props: Props) => { }}) .then(res => { if (res.ok) { - return auth.authFetch('/api/island/mode', {method: 'PUT', body: '"unset"'}) + return auth.authFetch( + '/api/island/mode', + { + method: 'PUT', + headers: {'Content-Type': 'application/json'}, + body: '"unset"' + } + ) }}) .then(res => { if (!res.ok) { From d56951f15216434c553b8316302a2f8c618f233a Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 3 Aug 2022 13:01:19 +0530 Subject: [PATCH 6/9] Island: Simplify logic to get data from request in IslandMode PUT --- monkey/monkey_island/cc/resources/island_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/resources/island_mode.py b/monkey/monkey_island/cc/resources/island_mode.py index 07d5d8095..84d2858c5 100644 --- a/monkey/monkey_island/cc/resources/island_mode.py +++ b/monkey/monkey_island/cc/resources/island_mode.py @@ -21,7 +21,7 @@ class IslandMode(AbstractResource): @jwt_required def put(self): try: - mode = IslandModeEnum(json.loads(request.data)) + mode = IslandModeEnum(request.json) self._island_mode_service.set_mode(mode) From 9c17cf44b18a8f1fe1484745636fb2e7e079a3dc Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 3 Aug 2022 13:35:02 +0530 Subject: [PATCH 7/9] UT: Pass headers in PUT requests in test_island_mode.py --- .../cc/resources/test_island_mode.py | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py index 97aa300e0..c0321394a 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py @@ -38,14 +38,20 @@ def flask_client(build_flask_client): ) def test_island_mode_post(flask_client, mode): resp = flask_client.put( - IslandModeResource.urls[0], data=json.dumps(mode), follow_redirects=True + IslandModeResource.urls[0], + data=json.dumps(mode), + headers={"Content-Type": "application/json"}, + follow_redirects=True, ) assert resp.status_code == HTTPStatus.NO_CONTENT def test_island_mode_post__invalid_mode(flask_client): resp = flask_client.put( - IslandModeResource.urls[0], data=json.dumps("bogus mode"), follow_redirects=True + IslandModeResource.urls[0], + data=json.dumps("bogus mode"), + headers={"Content-Type": "application/json"}, + follow_redirects=True, ) assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY @@ -61,6 +67,7 @@ def test_island_mode_post__internal_server_error(build_flask_client): resp = flask_client.put( IslandModeResource.urls[0], data=json.dumps(IslandMode.RANSOMWARE.value), + headers={"Content-Type": "application/json"}, follow_redirects=True, ) @@ -69,7 +76,12 @@ def test_island_mode_post__internal_server_error(build_flask_client): @pytest.mark.parametrize("mode", [IslandMode.RANSOMWARE.value, IslandMode.ADVANCED.value]) def test_island_mode_endpoint(flask_client, mode): - flask_client.put(IslandModeResource.urls[0], data=json.dumps(mode), follow_redirects=True) + flask_client.put( + IslandModeResource.urls[0], + data=json.dumps(mode), + headers={"Content-Type": "application/json"}, + follow_redirects=True, + ) resp = flask_client.get(IslandModeResource.urls[0], follow_redirects=True) assert resp.status_code == HTTPStatus.OK assert json.loads(resp.data) == mode @@ -77,7 +89,10 @@ def test_island_mode_endpoint(flask_client, mode): def test_island_mode_endpoint__invalid_mode(flask_client): resp_post = flask_client.put( - IslandModeResource.urls[0], data=json.dumps("bogus_mode"), follow_redirects=True + IslandModeResource.urls[0], + data=json.dumps("bogus_mode"), + headers={"Content-Type": "application/json"}, + follow_redirects=True, ) resp_get = flask_client.get(IslandModeResource.urls[0], follow_redirects=True) assert resp_post.status_code == HTTPStatus.UNPROCESSABLE_ENTITY From 4bcab891b24853767ffe3af53a6cd564da97b7ab Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 3 Aug 2022 15:26:48 +0530 Subject: [PATCH 8/9] UI: Don't convert response to JSON before creating Response object in IslandHttpClient's put() --- monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx b/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx index ef8d8adf5..11e6387b7 100644 --- a/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx +++ b/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx @@ -20,7 +20,7 @@ class IslandHttpClient extends AuthComponent { headers: {'Content-Type': 'application/json'}, body: JSON.stringify(contents) }) - .then(res => {status = res.status; return res.json()}) + .then(res => {status = res.status; return res}) .then(res => new Response(res, status)); } From 5a06e88913a6cbd33b8a9e16ac27cc1c288b641e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 3 Aug 2022 18:14:46 +0530 Subject: [PATCH 9/9] UT: Simplify some logic in test_island_mode.py --- .../cc/resources/test_island_mode.py | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py index c0321394a..322f62502 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_island_mode.py @@ -1,4 +1,3 @@ -import json from http import HTTPStatus from unittest.mock import MagicMock @@ -39,8 +38,7 @@ def flask_client(build_flask_client): def test_island_mode_post(flask_client, mode): resp = flask_client.put( IslandModeResource.urls[0], - data=json.dumps(mode), - headers={"Content-Type": "application/json"}, + json=mode, follow_redirects=True, ) assert resp.status_code == HTTPStatus.NO_CONTENT @@ -49,8 +47,7 @@ def test_island_mode_post(flask_client, mode): def test_island_mode_post__invalid_mode(flask_client): resp = flask_client.put( IslandModeResource.urls[0], - data=json.dumps("bogus mode"), - headers={"Content-Type": "application/json"}, + json="bogus mode", follow_redirects=True, ) assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY @@ -66,8 +63,7 @@ def test_island_mode_post__internal_server_error(build_flask_client): with build_flask_client(container) as flask_client: resp = flask_client.put( IslandModeResource.urls[0], - data=json.dumps(IslandMode.RANSOMWARE.value), - headers={"Content-Type": "application/json"}, + json=IslandMode.RANSOMWARE.value, follow_redirects=True, ) @@ -78,22 +74,20 @@ def test_island_mode_post__internal_server_error(build_flask_client): def test_island_mode_endpoint(flask_client, mode): flask_client.put( IslandModeResource.urls[0], - data=json.dumps(mode), - headers={"Content-Type": "application/json"}, + json=mode, follow_redirects=True, ) resp = flask_client.get(IslandModeResource.urls[0], follow_redirects=True) assert resp.status_code == HTTPStatus.OK - assert json.loads(resp.data) == mode + assert resp.json == mode def test_island_mode_endpoint__invalid_mode(flask_client): resp_post = flask_client.put( IslandModeResource.urls[0], - data=json.dumps("bogus_mode"), - headers={"Content-Type": "application/json"}, + json="bogus_mode", follow_redirects=True, ) resp_get = flask_client.get(IslandModeResource.urls[0], follow_redirects=True) assert resp_post.status_code == HTTPStatus.UNPROCESSABLE_ENTITY - assert json.loads(resp_get.data) == IslandMode.UNSET.value + assert resp_get.json == IslandMode.UNSET.value