From adab0436be1508e111a4a054a6b04cf9d75ab03d Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 2 Feb 2021 17:53:25 +0530 Subject: [PATCH] Add tests for AzureInstance --- monkey/common/cloud/azure/azure_instance.py | 7 +- .../common/cloud/azure/test_azure_instance.py | 179 ++++++++++++++++++ monkey/monkey_island/requirements.txt | 1 + 3 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 monkey/common/cloud/azure/test_azure_instance.py diff --git a/monkey/common/cloud/azure/azure_instance.py b/monkey/common/cloud/azure/azure_instance.py index 2599dc71b..79e6b24da 100644 --- a/monkey/common/cloud/azure/azure_instance.py +++ b/monkey/common/cloud/azure/azure_instance.py @@ -19,7 +19,7 @@ class AzureInstance(CloudInstance): Based on Azure metadata service: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service """ def is_instance(self): - return self.on_azure + return self._on_azure def get_cloud_provider_name(self) -> Environment: return Environment.AZURE @@ -31,13 +31,12 @@ class AzureInstance(CloudInstance): self.instance_name = None self.instance_id = None self.location = None - self.on_azure = False + self._on_azure = False try: response = requests.get(AZURE_METADATA_SERVICE_URL, headers={"Metadata": "true"}, timeout=SHORT_REQUEST_TIMEOUT) - self.on_azure = True # If not on cloud, the metadata URL is non-routable and the connection will fail. # If on AWS, should get 404 since the metadata service URL is different, so bool(response) will be false. @@ -48,7 +47,6 @@ class AzureInstance(CloudInstance): logger.warning(f"On Azure, but metadata response not ok: {response.status_code}") except requests.RequestException: logger.debug("Failed to get response from Azure metadata service: This instance is not on Azure.") - self.on_azure = False def try_parse_response(self, response): try: @@ -56,5 +54,6 @@ class AzureInstance(CloudInstance): self.instance_name = response_data["compute"]["name"] self.instance_id = response_data["compute"]["vmId"] self.location = response_data["compute"]["location"] + self._on_azure = True except (KeyError, simplejson.errors.JSONDecodeError) as e: logger.exception(f"Error while parsing response from Azure metadata service: {e}") diff --git a/monkey/common/cloud/azure/test_azure_instance.py b/monkey/common/cloud/azure/test_azure_instance.py new file mode 100644 index 000000000..0894205c1 --- /dev/null +++ b/monkey/common/cloud/azure/test_azure_instance.py @@ -0,0 +1,179 @@ +import pytest +import requests +import requests_mock +import simplejson + +from common.cloud.azure.azure_instance import (AZURE_METADATA_SERVICE_URL, + AzureInstance) +from common.cloud.environment_names import Environment + + +GOOD_DATA = { + 'compute': {'azEnvironment': 'AZUREPUBLICCLOUD', + 'isHostCompatibilityLayerVm': 'true', + 'licenseType': 'Windows_Client', + 'location': 'westus', + 'name': 'examplevmname', + 'offer': 'Windows', + 'osProfile': {'adminUsername': 'admin', + 'computerName': 'examplevmname', + 'disablePasswordAuthentication': 'true'}, + 'osType': 'linux', + 'placementGroupId': 'f67c14ab-e92c-408c-ae2d-da15866ec79a', + 'plan': {'name': 'planName', + 'product': 'planProduct', + 'publisher': 'planPublisher'}, + 'platformFaultDomain': '36', + 'platformUpdateDomain': '42', + 'publicKeys': [{'keyData': 'ssh-rsa 0', + 'path': '/home/user/.ssh/authorized_keys0'}, + {'keyData': 'ssh-rsa 1', + 'path': '/home/user/.ssh/authorized_keys1'}], + 'publisher': 'RDFE-Test-Microsoft-Windows-Server-Group', + 'resourceGroupName': 'macikgo-test-may-23', + 'resourceId': '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/' + 'providers/Microsoft.Compute/virtualMachines/examplevmname', + 'securityProfile': {'secureBootEnabled': 'true', + 'virtualTpmEnabled': 'false'}, + 'sku': 'Windows-Server-2012-R2-Datacenter', + 'storageProfile': {'dataDisks': [{'caching': 'None', + 'createOption': 'Empty', + 'diskSizeGB': '1024', + 'image': {'uri': ''}, + 'lun': '0', + 'managedDisk': {'id': '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/' + 'resourceGroups/macikgo-test-may-23/providers/' + 'Microsoft.Compute/disks/exampledatadiskname', + 'storageAccountType': 'Standard_LRS'}, + 'name': 'exampledatadiskname', + 'vhd': {'uri': ''}, + 'writeAcceleratorEnabled': 'false'}], + 'imageReference': {'id': '', + 'offer': 'UbuntuServer', + 'publisher': 'Canonical', + 'sku': '16.04.0-LTS', + 'version': 'latest'}, + 'osDisk': {'caching': 'ReadWrite', + 'createOption': 'FromImage', + 'diskSizeGB': '30', + 'diffDiskSettings': {'option': 'Local'}, + 'encryptionSettings': {'enabled': 'false'}, + 'image': {'uri': ''}, + 'managedDisk': {'id': '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/' + 'resourceGroups/macikgo-test-may-23/providers/' + 'Microsoft.Compute/disks/exampleosdiskname', + 'storageAccountType': 'Standard_LRS'}, + 'name': 'exampleosdiskname', + 'osType': 'Linux', + 'vhd': {'uri': ''}, + 'writeAcceleratorEnabled': 'false'}}, + 'subscriptionId': 'xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx', + 'tags': 'baz:bash;foo:bar', + 'version': '15.05.22', + 'vmId': '02aab8a4-74ef-476e-8182-f6d2ba4166a6', + 'vmScaleSetName': 'crpteste9vflji9', + 'vmSize': 'Standard_A3', + 'zone': ''}, + 'network': {'interface': [{'ipv4': {'ipAddress': [{'privateIpAddress': '10.144.133.132', + 'publicIpAddress': ''}], + 'subnet': [{'address': '10.144.133.128', + 'prefix': '26'}]}, + 'ipv6': {'ipAddress': []}, + 'macAddress': '0011AAFFBB22'}]} + } + + +BAD_DATA_NOT_JSON = '\n\n\n\n\nWaiting...\n\n\n \n\n' + + +BAD_DATA_JSON = {'': ''} + + +def get_test_azure_instance(url, **kwargs): + with requests_mock.Mocker() as m: + m.get(url, **kwargs) + test_azure_instance_object = AzureInstance() + return test_azure_instance_object + + +# good request, good data +@pytest.fixture +def good_data_mock_instance(): + return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, text=simplejson.dumps(GOOD_DATA)) + + +def test_is_instance_good_data(good_data_mock_instance): + assert good_data_mock_instance.is_instance() + + +def test_get_cloud_provider_name_good_data(good_data_mock_instance): + assert good_data_mock_instance.get_cloud_provider_name() == Environment.AZURE + + +def test_try_parse_response_good_data(good_data_mock_instance): + assert good_data_mock_instance.instance_name == GOOD_DATA['compute']['name'] + assert good_data_mock_instance.instance_id == GOOD_DATA['compute']['vmId'] + assert good_data_mock_instance.location == GOOD_DATA['compute']['location'] + + +# good request, bad data (json) +@pytest.fixture +def bad_data_json_mock_instance(): + return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, text=simplejson.dumps(BAD_DATA_JSON)) + + +def test_is_instance_bad_data_json(bad_data_json_mock_instance): + assert bad_data_json_mock_instance.is_instance() is False + + +def test_get_cloud_provider_name_bad_data_json(bad_data_json_mock_instance): + assert bad_data_json_mock_instance.get_cloud_provider_name() == Environment.AZURE + + +def test_instance_attributes_bad_data_json(bad_data_json_mock_instance): + assert bad_data_json_mock_instance.instance_name is None + assert bad_data_json_mock_instance.instance_id is None + assert bad_data_json_mock_instance.location is None + + +# good request, bad data (not json) +@pytest.fixture +def bad_data_not_json_mock_instance(): + return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, text=BAD_DATA_NOT_JSON) + + +def test_is_instance_bad_data_not_json(bad_data_not_json_mock_instance): + assert bad_data_not_json_mock_instance.is_instance() is False + + +def test_get_cloud_provider_name_bad_data_not_json(bad_data_not_json_mock_instance): + assert bad_data_not_json_mock_instance.get_cloud_provider_name() == Environment.AZURE + + +def test_instance_attributes_bad_data_not_json(bad_data_not_json_mock_instance): + assert bad_data_not_json_mock_instance.instance_name is None + assert bad_data_not_json_mock_instance.instance_id is None + assert bad_data_not_json_mock_instance.location is None + + +# bad request +@pytest.fixture +def bad_request_mock_instance(): + return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, exc=requests.RequestException) + + +def test_is_instance_bad_request(bad_request_mock_instance): + assert bad_request_mock_instance.is_instance() is False + + +def test_get_cloud_provider_name_bad_request(bad_request_mock_instance): + assert bad_request_mock_instance.get_cloud_provider_name() == Environment.AZURE + + +def test_instance_attributes_bad_request(bad_request_mock_instance): + assert bad_request_mock_instance.instance_name is None + assert bad_request_mock_instance.instance_id is None + assert bad_request_mock_instance.location is None diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt index f1e80161c..3cb3a4e42 100644 --- a/monkey/monkey_island/requirements.txt +++ b/monkey/monkey_island/requirements.txt @@ -18,6 +18,7 @@ pycryptodome==3.9.8 pytest>=5.4 python-dateutil>=2.1,<3.0.0 requests>=2.24 +requests-mock==1.8.0 ring>=0.7.3 stix2>=2.0.2 six>=1.13.0