def test_has_been_revoked_true(self, mock_thing, mock_crypto, mock_request): mock_crypto.load_certificate.return_value = MagicMock() mock_crypto.load_certificate( ).get_serial_number.return_value = 0x000111222333 serial_number = hex( mock_crypto.load_certificate().get_serial_number())[2:] url = "{0}/ca/CN={1},O=EJBCA/certificate/{2}/status".format( MOCK_CONFIG["security"]["ejbca_url"], MOCK_CONFIG["security"]["ejbca_ca_name"], serial_number) mock_request.get.return_value = MagicMock() mock_request.get().json().get.return_value = MagicMock() mock_request.get().json.return_value = { 'status': { 'return': { 'reason': 0 }, }, } result = CertClient.has_been_revoked(mock_thing) mock_request.get.assert_called_with(url) self.assertTrue(result) mock_request.get().json.return_value = {} result = CertClient.has_been_revoked(mock_thing) self.assertFalse(result)
def revoke_cert(self) -> None: """ Revoke a certificate and emit an event whether it succeeded or not. """ if self.should_revoke_now(): try: CertClient.revoke_cert(self.new_cert) except Exception as exception: Utils.fire_locust_failure(request_type=REQUEST_TYPE, name=MESSAGE_TYPE_REVOKE, response_time=0, response_length=0, exception=exception) else: if CertClient.has_been_revoked(self.new_cert): Utils.fire_locust_success(request_type=REQUEST_TYPE, name=MESSAGE_TYPE_REVOKE, response_time=0, response_length=0) self.should_revoke = False else: Utils.fire_locust_failure( request_type=REQUEST_TYPE, name=MESSAGE_TYPE_REVOKE, response_time=0, response_length=0, exception=CertRevogationError("failed to revoke"))
def configure_mqtt(self) -> None: """ Configures the MQTT connection. """ # Certification files cert_dir = CONFIG["security"]["cert_dir"] ca_cert_file = cert_dir + CONFIG["security"]["ca_cert_file"] cert_file = self.device_cert_dir + CertClient.get_certificate_file( self.device_id) key_file = self.device_cert_dir + CertClient.get_private_key_file( self.device_id) # Configuring MQTT client self.mqttc = mqtt.Client(client_id=self.device_id) # Sets exponential reconnect delay self.mqttc.reconnect_delay_set( min_delay=CONFIG["security"]["min_time_reconn"], max_delay=CONFIG["security"]["max_time_reconn"]) # Setting up TLS self.mqttc.tls_set(ca_cert_file, cert_file, key_file) # TODO: investigate the problem when the insecure TLS mode is False # This problem seems to happen because the TLS implementation does not # expects an IP, but a hostname self.mqttc.tls_insecure_set(True) # Registering MQTT client callbacks self.mqttc.on_connect = self.locust_on_connect self.mqttc.on_disconnect = self.locust_on_disconnect self.mqttc.on_publish = self.locust_on_publish self.mqttc.on_subscribe = self.locust_on_subscribe self.mqttc.on_message = self.locust_on_message
def test_create_cert_files_exception(self, mock_thing): """ Should not build a correct filename for the certificate. """ mock_thing.device_id = 'thind-dev-id' mock_thing.thing_certificate = 'thing-certificate' mock_thing.private_key = 'private-key' directory = 'dir-to-create-certs/' with patch('src.ejbca.cert_client.open', mock_open()) as mock_builtin_open: mock_builtin_open.side_effect = Exception() with self.assertRaises(Exception): CertClient.create_cert_files(mock_thing, directory)
def test_get_certificate_file(self, mock_utils): """ Should build a correct filename for the certificate. """ mock_utils.validate_device_id.return_value = MagicMock() device_id = "dev-id" filename = device_id + ".crt" self.assertEqual(CertClient.get_certificate_file(device_id), filename) mock_utils.reset_mock()
def test_revoke_cert(mock_thing, mock_crypto, mock_request): """ Test certifcate revoke cert """ mock_crypto.load_certificate.return_value = MagicMock() mock_crypto.load_certificate( ).get_serial_number.return_value = 0x000111222333 serial_number = hex( mock_crypto.load_certificate().get_serial_number())[2:] url = MOCK_CONFIG["security"][ "ejbca_url"] + "/ca/CN={0},O=EJBCA/certificate/{1}".format( MOCK_CONFIG["security"]["ejbca_ca_name"], serial_number) CertClient.revoke_cert(mock_thing) mock_request.delete.assert_called_with(url) mock_thing.reset_mock() mock_crypto.reset_mock() mock_request.reset_mock()
def test_new_cert(self, mock_utils, mock_thing): """ Test certifcate new cert creation """ tenant = 'tenant' dev_id = 'dev-id' created_thing = CertClient.new_cert(tenant, dev_id) self.assertIsNotNone(created_thing) mock_utils.validate_tenant.assert_called() mock_utils.validate_device_id.assert_called() mock_thing.assert_called_with(tenant, dev_id) mock_thing.reset_mock()
def setup(self) -> None: """ Initializes the required parameters. """ logging.basicConfig(**CONFIG["app"]["log_config"]) self.username = '******'.format(self.tenant, self.device_id) self.topic = "{0}/attrs".format(self.username) self.sub_topic = "{0}/config".format(self.username) self.device_cert_dir = CONFIG["security"]["cert_dir"] # Creating a new certificate if the client was chosen to be revoked if self.should_revoke: self.device_cert_dir = self.device_cert_dir + CONFIG["security"][ "revoke_cert_dir"] self.new_cert = CertClient.new_cert(self.tenant, self.device_id) CertClient.create_cert_files(self.new_cert, self.device_cert_dir) elif self.should_renew: self.device_cert_dir = self.device_cert_dir + CONFIG["security"][ "renew_cert_dir"] self.new_cert = CertClient.new_cert(self.tenant, self.device_id) CertClient.create_cert_files(self.new_cert, self.device_cert_dir) self.configure_mqtt()
def test_create_cert_files(self, mock_thing): """ Should build a correct filename for the certificate. """ mock_thing.device_id = 'thind-dev-id' mock_thing.thing_certificate = 'thing-certificate' mock_thing.private_key = 'private-key' directory = 'dir-to-create-certs/' thing_path = directory + mock_thing.device_id with patch('src.ejbca.cert_client.open', mock_open()) as mock_builtin_open: CertClient.create_cert_files(mock_thing, directory) calls = [ call(thing_path + '.key', "w"), call(thing_path + '.crt', "w"), call().write(mock_thing.thing_certificate), call().write(mock_thing.private_key) ] mock_builtin_open.assert_has_calls(calls, any_order=True) mock_builtin_open.reset_mock() mock_thing.reset_mock()
def initialize_mqtt(self) -> None: """ Initializes the MQTT connection. """ # Certification files cert_dir = CONFIG["security"]["cert_dir"] ca_cert_file = cert_dir + CONFIG["security"]["ca_cert_file"] cert_file = self.device_cert_dir + CertClient.get_certificate_file( self.device_id) key_file = self.device_cert_dir + CertClient.get_private_key_file( self.device_id) self.username = '******'.format(self.tenant, self.device_id) self.topic = "{0}/attrs".format(self.username) self.sub_topic = "{0}/config".format(self.username) self.log = LogController(self.run_id) # Configuring MQTT client self.mqttc = mqtt.Client(client_id=self.device_id) # Sets exponential reconnect delay self.mqttc.reconnect_delay_set( min_delay=CONFIG["security"]["min_time_reconn"], max_delay=CONFIG["security"]["max_time_reconn"]) # Setting up TLS self.mqttc.tls_set(ca_cert_file, cert_file, key_file) # TODO: investigate the problem when the insecure TLS mode is False self.mqttc.tls_insecure_set(True) # Registering MQTT client callbacks self.mqttc.on_connect = self.locust_on_connect self.mqttc.on_disconnect = self.locust_on_disconnect self.mqttc.on_publish = self.locust_on_publish self.mqttc.on_subscribe = self.locust_on_subscribe self.mqttc.on_message = self.locust_on_message
def __init__(self, device_id: str, run_id: str, should_revoke: bool, should_renew: bool): """MQTT client constructor. Args: device_id: device identifier run_id: client run identifier should_revoke: whether this client should have its certificate revoked should_renew: whether this client should have its certificate renewed tenant: tenant that owns the device """ self.device_id = device_id self.run_id = run_id self.should_revoke = should_revoke self.should_renew = should_renew self.tenant = CONFIG["app"]["tenant"] self.is_connected = False self.start_time = 0 # Creating a new certificate if the client was chosen to be revoked self.device_cert_dir = CONFIG["security"]["cert_dir"] if self.should_revoke: self.device_cert_dir = self.device_cert_dir + CONFIG["security"][ "revoke_cert_dir"] self.new_cert = CertClient.new_cert(self.tenant, self.device_id) CertClient.create_cert_files(self.device_id, self.new_cert, \ self.device_cert_dir) elif self.should_renew: self.device_cert_dir = self.device_cert_dir + CONFIG["security"][ "renew_cert_dir"] self.new_cert = CertClient.new_cert(self.tenant, self.device_id) CertClient.create_cert_files(self.device_id, self.new_cert, \ self.device_cert_dir) self.pubmmap = {} self.submmap = {} self.recvmqueue = Queue() self.initialize_mqtt()