diff --git a/plugins/microsoft_teams/.CHECKSUM b/plugins/microsoft_teams/.CHECKSUM index c84e3cf825..50853f4c4a 100644 --- a/plugins/microsoft_teams/.CHECKSUM +++ b/plugins/microsoft_teams/.CHECKSUM @@ -1,7 +1,7 @@ { - "spec": "a8a98f7a39f3a451cbc6e721d2f18763", - "manifest": "740cde9c1eb4f00811dddc3a01849bb1", - "setup": "24e90b270dbea48610bc4fefd61145ff", + "spec": "c4f984c13d6e66960beb754ecbc27671", + "manifest": "bf3360c95879e501c81bf9aef6b5c90a", + "setup": "fb45935165f7144352b5743d1fa6f285", "schemas": [ { "identifier": "add_channel_to_team/schema.py", diff --git a/plugins/microsoft_teams/bin/icon_microsoft_teams b/plugins/microsoft_teams/bin/icon_microsoft_teams index 367399ef40..9afd40529d 100755 --- a/plugins/microsoft_teams/bin/icon_microsoft_teams +++ b/plugins/microsoft_teams/bin/icon_microsoft_teams @@ -6,7 +6,7 @@ from sys import argv Name = "Microsoft Teams" Vendor = "rapid7" -Version = "3.1.4" +Version = "3.1.5" Description = "The Microsoft Teams plugin allows you to send and trigger workflows on new messages. The plugin will also allow for teams management with the ability to add and remove teams, channels, and users" diff --git a/plugins/microsoft_teams/help.md b/plugins/microsoft_teams/help.md index 633912ebb3..c0865a7ec0 100644 --- a/plugins/microsoft_teams/help.md +++ b/plugins/microsoft_teams/help.md @@ -13,6 +13,10 @@ This plugin uses the [Microsoft Teams API](https://docs.microsoft.com/en-us/grap * Username and Password * Secret Key, similar to API Key +# Supported Product Versions + +_There are no supported product versions listed._ + # Documentation ## Setup @@ -873,6 +877,7 @@ If there is more than one team with the same name in your organization, the olde # Version History +* 3.1.5 - Add `microsoft_teams` and `office365` keywords | Removed `microsoft, teams, office 365` keywords * 3.1.4 - Update help.md to include troubleshooting message about team names * 3.1.3 - Update `docs_url` in plugin spec with a new link to [plugin setup guide](https://docs.rapid7.com/insightconnect/microsoft-teams/) * 3.1.2 - Fix issue where a name with a bracket could crash the plugin diff --git a/plugins/microsoft_teams/plugin.spec.yaml b/plugins/microsoft_teams/plugin.spec.yaml index 634d67db1d..d01ef5b863 100644 --- a/plugins/microsoft_teams/plugin.spec.yaml +++ b/plugins/microsoft_teams/plugin.spec.yaml @@ -4,7 +4,7 @@ products: [insightconnect] name: microsoft_teams title: Microsoft Teams description: The Microsoft Teams plugin allows you to send and trigger workflows on new messages. The plugin will also allow for teams management with the ability to add and remove teams, channels, and users -version: 3.1.4 +version: 3.1.5 vendor: rapid7 support: community status: [] @@ -20,7 +20,7 @@ tags: - chat hub_tags: use_cases: [alerting_and_notifications, application_management, threat_detection_and_response, user_management] - keywords: [microsoft, teams, office 365, chat] + keywords: [microsoft_teams, office365, chat] features: [] types: team: diff --git a/plugins/microsoft_teams/setup.py b/plugins/microsoft_teams/setup.py index 590dc46667..6770937826 100755 --- a/plugins/microsoft_teams/setup.py +++ b/plugins/microsoft_teams/setup.py @@ -3,7 +3,7 @@ setup(name="microsoft_teams-rapid7-plugin", - version="3.1.4", + version="3.1.5", description="The Microsoft Teams plugin allows you to send and trigger workflows on new messages. The plugin will also allow for teams management with the ability to add and remove teams, channels, and users", author="rapid7", author_email="", diff --git a/plugins/microsoft_teams/unit_test/payloads/get_messages.json b/plugins/microsoft_teams/unit_test/payloads/get_messages.json new file mode 100644 index 0000000000..46d8bccb4e --- /dev/null +++ b/plugins/microsoft_teams/unit_test/payloads/get_messages.json @@ -0,0 +1,16 @@ +{ + "value": [ + { + "body": { + "content": "This is very old" + }, + "createdDateTime": 0 + }, + { + "body": { + "content": "This should be first" + }, + "createdDateTime": 11 + } + ] +} \ No newline at end of file diff --git a/plugins/microsoft_teams/unit_test/test_add_words_to_message.py b/plugins/microsoft_teams/unit_test/test_add_words_to_message.py deleted file mode 100644 index 7808552a32..0000000000 --- a/plugins/microsoft_teams/unit_test/test_add_words_to_message.py +++ /dev/null @@ -1,16 +0,0 @@ -from unittest import TestCase -from icon_microsoft_teams.util.words_utils import add_words_values_to_message -import json - - -class TestAddWords(TestCase): - def test_add_words(self): - with open("../examples/message.json") as json_file: - data = json.load(json_file) - - result = add_words_values_to_message(data.get("message")) - - self.assertTrue("words" in result.keys()) - self.assertTrue("first_word" in result.keys()) - self.assertEqual(result.get("first_word"), "Hello") - self.assertEqual(result.get("words"), ["Hello", "from", "a", "command", "line", "test!"]) diff --git a/plugins/microsoft_teams/unit_test/test_azure_ad_utils.py b/plugins/microsoft_teams/unit_test/test_azure_ad_utils.py deleted file mode 100644 index 1c23e88fa3..0000000000 --- a/plugins/microsoft_teams/unit_test/test_azure_ad_utils.py +++ /dev/null @@ -1,251 +0,0 @@ -import logging -import json -from time import sleep - -from unittest import TestCase, mock -from icon_microsoft_teams.util.azure_ad_utils import ( - get_user_info, - add_user_to_group, - remove_user_from_group, - create_group, - get_group_id_from_name, - delete_group, - enable_teams_for_group, -) -from icon_microsoft_teams.connection.connection import Connection -from komand.exceptions import PluginException - - -class MockConnection: - def __init__(self): - self.tenant_id = "fake_tenant_id" - - def get_headers(self): - return {"value": "header"} - - -def mocked_requests_get(*args, **kwargs): - class MockResponse: - def __init__(self, json_data, status_code): - self.json_data = json_data - self.status_code = status_code - self.text = "This is some response text" - - def json(self): - return self.json_data - - if args[0] == f"https://graph.microsoft.com/v1.0/fake_tenant_id/groups/fake_group_id/team": - return MockResponse({}, 400) - - print(f"Failed api call: {args[0]}") - return MockResponse(None, 404) - - -class TestAzureADUtils(TestCase): - def test_get_user_info(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - - result = get_user_info(log, connection, "jmcadams@komanddev.onmicrosoft.com") - - self.assertEqual("Joey McAdams", result.get("displayName")) - self.assertEqual("08290005-23ba-46b4-a377-b381d651a2fb", result.get("id")) - - result = get_user_info(log, connection, "jschipp@komanddev.onmicrosoft.com") - - self.assertEqual("Jon Schipp", result.get("displayName")) - self.assertEqual("ac785ffe-530a-45a1-bbf4-e275457e464b", result.get("id")) - - def test_add_user_to_group(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - - # Komand-Test_Everyone - # jmcadams@komanddev.onmicrosoft.com - try: - remove_user_from_group( - log, - connection, - "7af08a76-01fe-4a1d-bfa1-84d2b5509cdd", - "08290005-23ba-46b4-a377-b381d651a2fb", - ) - log.info("Successfully removed user.") - except Exception as e: - log.info("Remove user failed!") - print(e) - pass - sleep(10) - result = add_user_to_group( - log, - connection, - "7af08a76-01fe-4a1d-bfa1-84d2b5509cdd", - "08290005-23ba-46b4-a377-b381d651a2fb", - ) - - self.assertTrue(result) - - def test_remove_user_from_group(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - - # Komand-Test_Everyone - # jmcadams@komanddev.onmicrosoft.com - try: - add_user_to_group( - log, - connection, - "7af08a76-01fe-4a1d-bfa1-84d2b5509cdd", - "08290005-23ba-46b4-a377-b381d651a2fb", - ) - log.info("Successfully addeded user.") - except Exception as e: - log.info("Add user failed!") - print(e) - pass - sleep(10) - result = remove_user_from_group( - log, - connection, - "7af08a76-01fe-4a1d-bfa1-84d2b5509cdd", - "08290005-23ba-46b4-a377-b381d651a2fb", - ) - - self.assertTrue(result) - - def test_create_group(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - - owners = ["jmcadams@komanddev.onmicrosoft.com"] - members = ["jschipp@komanddev.onmicrosoft.com", "jmcadams@komanddev.onmicrosoft.com"] - - result = create_group( - log, - connection, - "test_group_delete_me", - "A test group to delete", - "nickname_goes_here", - True, - owners, - members, - ) - - self.assertIsNotNone(result) - self.assertEqual(result.get("displayName"), "test_group_delete_me") - self.assertEqual(result.get("description"), "A test group to delete") - - def test_get_group_id(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - result = get_group_id_from_name(log, connection, "test_group_delete_me") - - self.assertIsNotNone(result) - self.assertEqual(type(result), str) - - def test_delete_group(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - result = delete_group(log, connection, "test_group_delete_me") - - self.assertTrue(result) - - def test_enable_teams_for_group(self): - log = logging.getLogger() - connection = Connection() - connection.logger = log - - with open("../tests/get_teams.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - connection.connect(connection_params) - - # try nuking the group first, create_group fails if it's already there - try: - delete_group(logging, connection, "test_group_delete_me") - sleep(10) # give Azure time to do it's thing - except Exception: - pass - - result = create_group( - log, - connection, - "test_group_delete_me", - "A test group to delete", - "nickname_goes_here", - True, - None, - None, - ) - - self.assertIsNotNone(result) - self.assertEqual(result.get("displayName"), "test_group_delete_me") - self.assertEqual(result.get("description"), "A test group to delete") - - group_id = result.get("id") - success = enable_teams_for_group(log, connection, group_id) - - self.assertTrue(success) - - @mock.patch("requests.put", side_effect=mocked_requests_get) - def test_enable_teams_for_group_and_sleep(self, mockGet): - log = logging.getLogger() - connection = MockConnection() - connection.logger = log - - group_id = "fake_group_id" - with self.assertRaises(PluginException): - enable_teams_for_group(log, connection, group_id) - - # verify 5 attempts were made to enable the team - self.assertEqual(mockGet.call_count, 5) - self.assertEqual( - mockGet.call_args_list[0][0][0], - "https://graph.microsoft.com/v1.0/fake_tenant_id/groups/fake_group_id/team", - ) - self.assertEqual( - mockGet.call_args_list[4][0][0], - "https://graph.microsoft.com/v1.0/fake_tenant_id/groups/fake_group_id/team", - ) diff --git a/plugins/microsoft_teams/unit_test/test_connection.py b/plugins/microsoft_teams/unit_test/test_connection.py deleted file mode 100644 index 1cf3b897e9..0000000000 --- a/plugins/microsoft_teams/unit_test/test_connection.py +++ /dev/null @@ -1,19 +0,0 @@ -from unittest import TestCase -from icon_microsoft_teams.connection import Connection -import json -import logging - - -class TestConnection(TestCase): - def test_connection(self): - log = logging.getLogger("Test") - test_conn = Connection() - test_conn.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_conn.connect(connection_params) - - self.assertIsNotNone(test_conn.api_token) diff --git a/plugins/microsoft_teams/unit_test/test_get_channels.py b/plugins/microsoft_teams/unit_test/test_get_channels.py deleted file mode 100644 index 44bb602134..0000000000 --- a/plugins/microsoft_teams/unit_test/test_get_channels.py +++ /dev/null @@ -1,29 +0,0 @@ -from unittest import TestCase -from icon_microsoft_teams.actions import GetChannelsForTeam -from icon_microsoft_teams.connection import Connection -import logging -import json - - -class TestGetChannels(TestCase): - def test_get_channels(self): - log = logging.getLogger("Test") - - test_action = GetChannelsForTeam() - test_connection = Connection() - - test_action.logger = log - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - test_action.connection = test_connection - - run_params = {"team_name": "Komand-Test-Everyone", "channel_name": "29_test_channel_2"} - - result = test_action.run(run_params) - self.assertIsNotNone(result) - self.assertEqual(result.get("channels")[0].get("displayName"), "29_test_channel_2") diff --git a/plugins/microsoft_teams/unit_test/test_get_teams.py b/plugins/microsoft_teams/unit_test/test_get_teams.py deleted file mode 100644 index 66232278f0..0000000000 --- a/plugins/microsoft_teams/unit_test/test_get_teams.py +++ /dev/null @@ -1,51 +0,0 @@ -from unittest import TestCase -from icon_microsoft_teams.actions import GetTeams -from icon_microsoft_teams.connection import Connection -import logging -import json - - -class TestGetTeams(TestCase): - def test_get_teams(self): - log = logging.getLogger("Test") - - test_action = GetTeams() - test_connection = Connection() - - test_action.logger = log - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - test_action.connection = test_connection - - run_params = {"team_name": "Dream Team"} - - result = test_action.run(run_params) - self.assertIsNotNone(result) - self.assertEqual(result.get("teams")[0].get("displayName"), "Dream Team") - - def test_get_teams_with_regex(self): - log = logging.getLogger("Test") - - test_action = GetTeams() - test_connection = Connection() - - test_action.logger = log - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - test_action.connection = test_connection - - run_params = {"team_name": "Team"} - - result = test_action.run(run_params) - self.assertIsNotNone(result) - self.assertEqual(result.get("teams")[0].get("displayName"), "Dream Team") diff --git a/plugins/microsoft_teams/unit_test/test_new_message_received.py b/plugins/microsoft_teams/unit_test/test_new_message_received.py index 6f386916d0..5beb34421f 100644 --- a/plugins/microsoft_teams/unit_test/test_new_message_received.py +++ b/plugins/microsoft_teams/unit_test/test_new_message_received.py @@ -2,6 +2,7 @@ import json import logging import requests +import os from icon_microsoft_teams.triggers.new_message_received import NewMessageReceived from komand.exceptions import PluginException @@ -31,7 +32,7 @@ def raise_for_status(self): def json(self): return json.loads(self.text) - messages_payload = read_file_to_string("./payloads/get_messages.json") + messages_payload = read_file_to_string(os.path.join(os.path.dirname(__file__), "./payloads/get_messages.json")) if args[0] == "http://somefakeendpoint.com": return MockResponse(messages_payload, 200) @@ -42,7 +43,7 @@ def json(self): class TestNewMessageReceived(TestCase): def test_sort_messages_from_request(self): - with open("./payloads/get_messages.json") as f: + with open(os.path.join(os.path.dirname(__file__), "./payloads/get_messages.json")) as f: text = f.read() json_payload = json.loads(text) diff --git a/plugins/microsoft_teams/unit_test/test_send_message.py b/plugins/microsoft_teams/unit_test/test_send_message.py deleted file mode 100644 index df7123d85e..0000000000 --- a/plugins/microsoft_teams/unit_test/test_send_message.py +++ /dev/null @@ -1,32 +0,0 @@ -from unittest import TestCase -from icon_microsoft_teams.actions import SendMessage -from icon_microsoft_teams.connection import Connection -import logging -import json - - -class TestGetTeams(TestCase): - def test_get_teams(self): - log = logging.getLogger("Test") - - test_action = SendMessage() - test_connection = Connection() - - test_action.logger = log - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - test_action.connection = test_connection - - run_params = { - "team_name": "Dream Team", - "channel_name": "test123", - "message": "Hello from a Unit Test!", - } - - result = test_action.run(run_params) - self.assertIsNotNone(result) diff --git a/plugins/microsoft_teams/unit_test/test_teams_utils.py b/plugins/microsoft_teams/unit_test/test_teams_utils.py deleted file mode 100644 index 496c623756..0000000000 --- a/plugins/microsoft_teams/unit_test/test_teams_utils.py +++ /dev/null @@ -1,115 +0,0 @@ -from unittest import TestCase - -from komand.exceptions import PluginException - -from icon_microsoft_teams.connection.connection import Connection -from icon_microsoft_teams.util.teams_utils import ( - create_channel, - delete_channel, - get_channels_from_microsoft, - get_teams_from_microsoft, -) - -import logging -import json -import time - -# Globals -TEAM_ID = "7af08a76-01fe-4a1d-bfa1-84d2b5509cdd" # Komand-Test-Everyone -TEST_CHANNEL_NAME = "test_channel_delete_me_2" - - -class TestTeamsUtils(TestCase): - def test_integraion_create_channel(self): - log = logging.getLogger("Test") - test_connection = Connection() - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - - result = create_channel(log, test_connection, TEAM_ID, TEST_CHANNEL_NAME, "some really cool test description") - - # This code is used to bulk create channels. Needed to max out a team with channels to test - # pagination - - # for i in range(200): - # channel_name = f"{i}_test_channel" - # create_channel(log, test_connection, TEAM_ID, channel_name, "some really cool test description") - - self.assertTrue(result) - - def test_integration_delete_channel(self): - log = logging.getLogger("Test") - test_connection = Connection() - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - - channels = get_channels_from_microsoft(log, test_connection, TEAM_ID, TEST_CHANNEL_NAME, True) - channel_id = channels[0].get("id") - - result = delete_channel(log, test_connection, TEAM_ID, channel_id) - - # Leaving this code here - This can be used for bulk delete if needed - - # for i in range(100): - # channel_name = f"{i}_test_channel_3" - # channels = get_channels_from_microsoft(log, test_connection, TEAM_ID, channel_name) - # channel_id = channels[0].get("id") - # delete_channel(log, test_connection, TEAM_ID, channel_id) - # time.sleep(1) - - self.assertTrue(result) - - def test_integration_get_team(self): - log = logging.getLogger("Test") - test_connection = Connection() - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - - expected = "[Test] for customer" - teams = get_teams_from_microsoft(log, test_connection, expected, True) - self.assertEquals(teams[0].get("displayName"), expected) - - expected = "Dream Team" - teams = get_teams_from_microsoft(log, test_connection, expected, True) - self.assertEquals(teams[0].get("displayName"), expected) - - expected = "change_me" - teams = get_teams_from_microsoft(log, test_connection, expected, True) - self.assertEquals(teams[0].get("displayName"), expected) - - expected = "Komand-Test-Everyone" - teams = get_teams_from_microsoft(log, test_connection, expected, True) - self.assertEquals(teams[0].get("displayName"), expected) - - def test_integration_negative_get_blank_team(self): - log = logging.getLogger("Test") - test_connection = Connection() - test_connection.logger = log - - with open("../tests/send_message.json") as file: - data = json.load(file) - connection_params = data.get("body").get("connection") - - test_connection.connect(connection_params) - expected = "" - with self.assertRaises(PluginException): - teams = get_teams_from_microsoft(log, test_connection, expected, True) - - expected = "DONT FIND THIS" - with self.assertRaises(PluginException): - teams = get_teams_from_microsoft(log, test_connection, expected, True)