def test_assert_methods(self): requestor_keys = self._fake_keys() provider_keys = self._fake_keys() concent_keys = self._fake_keys() rct = msg_factories.tasks.ReportComputedTaskFactory() dump(rct, provider_keys.raw_privkey, requestor_keys.raw_pubkey) stored_rct = pickle.loads(pickle.dumps(rct)) frct_concent = message.concents.ForceReportComputedTask( report_computed_task=rct) frct_concent_data = dump(frct_concent, provider_keys.raw_privkey, concent_keys.raw_pubkey) stored_frct = pickle.loads(pickle.dumps(frct_concent)) frct_concent_rcv = load(frct_concent_data, concent_keys.raw_privkey, provider_keys.raw_pubkey) concent_rct = frct_concent_rcv.report_computed_task frct_requestor = message.concents.ForceReportComputedTask( report_computed_task=concent_rct) frct_requestor_data = dump(frct_requestor, concent_keys.raw_privkey, requestor_keys.raw_pubkey) frct_requestor_rcv = load(frct_requestor_data, requestor_keys.raw_privkey, concent_keys.raw_pubkey) self.assertEqual(frct_requestor_rcv.report_computed_task, stored_rct) self.assertNotEqual(frct_requestor_rcv, stored_frct) self.assertSamePayload(frct_requestor_rcv, stored_frct)
def test_message_sig(self): """Signed message inside a signed message""" concent_keys = cryptography.ECCx(None) provider_keys = cryptography.ECCx(None) requestor_keys = cryptography.ECCx(None) report_computed_task = factories.tasks.ReportComputedTaskFactory() # Dump TaskToCompute to make it signed s_rct = shortcuts.dump( report_computed_task, requestor_keys.raw_privkey, provider_keys.raw_pubkey, ) # Load TaskToCompute back to its original format # Task TaskToCompute is verified correctly report_computed_task = shortcuts.load( s_rct, provider_keys.raw_privkey, requestor_keys.raw_pubkey, ) first_sig = report_computed_task.sig first_hash = report_computed_task.get_short_hash() force_report = message.ForceReportComputedTask() force_report.report_computed_task = report_computed_task s_force_report = shortcuts.dump( force_report, provider_keys.raw_privkey, concent_keys.raw_pubkey, ) force_report = shortcuts.load( s_force_report, concent_keys.raw_privkey, provider_keys.raw_pubkey, ) second_sig = force_report.report_computed_task.sig second_hash = force_report.report_computed_task.get_short_hash() self.assertEqual(first_sig, second_sig) self.assertEqual(first_hash, second_hash) # Now, attached TaskToCompute should still be verified using # original key. ecdsa_verify will raise InvalidSignature on # failure. cryptography.ecdsa_verify( requestor_keys.raw_pubkey, force_report.report_computed_task.sig, force_report.report_computed_task.get_short_hash(), )
def test_validation(self): for key in ('nonce', 'gasprice', 'startgas', 'value', 'r', 's'): invalid_message_instance = self.FACTORY(**{key: '1' * 79}) serialized_message = dump(invalid_message_instance, None, None) with self.assertRaises(FieldError): load(serialized_message, None, None) invalid_message_instance = self.FACTORY(v='1' * 4) serialized_message = dump(invalid_message_instance, None, None) with self.assertRaises(FieldError): load(serialized_message, None, None)
def test_send_should_return_http_200_if_message_timeout(self): assert StoredMessage.objects.count() == 0 task_to_compute = self.task_to_compute task_to_compute.compute_task_def[ 'deadline'] = self.message_timestamp - 1 # pylint: disable=no-member task_to_compute.sig = None task_to_compute = self._sign_message(task_to_compute) report_computed_task = self._get_deserialized_report_computed_task( task_to_compute=task_to_compute) correct_golem_data = self._get_deserialized_force_report_computed_task( report_computed_task=report_computed_task) response = self.client.post( reverse('core:send'), data=dump(correct_golem_data, self.PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY), content_type='application/octet-stream', ) self.assertEqual(response.status_code, 200) response_message = load( response.content, self.PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY, ) self.assertIsInstance(response_message, message.concents.ForceReportComputedTaskResponse)
def test_load_without_public_key_should_load_message(self): """ Test that message loaded with load_without_public_key function will be the same as load with golem_messages load function. """ # Create and fill some data into ComputeTaskDef compute_task_def = tasks.ComputeTaskDefFactory( task_id=generate_uuid_for_tests(), subtask_id=generate_uuid_for_tests(), deadline=1510912800, ) # Create TaskToCompute task_to_compute = tasks.TaskToComputeFactory( compute_task_def = compute_task_def, price=0, ) # Dump TaskToCompute to make it signed dumped_task_to_compute = dump(task_to_compute, REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY) loaded_task_to_compute_with_utility_function = load_without_public_key( dumped_task_to_compute, REQUESTOR_PUBLIC_KEY, ) loaded_task_to_compute_with_golem_messages_load = load( dumped_task_to_compute, CONCENT_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, ) self.assertEqual(loaded_task_to_compute_with_utility_function, loaded_task_to_compute_with_golem_messages_load)
def test_send_should_return_http_200_if_message_timeout(self): assert StoredMessage.objects.count() == 0 task_to_compute = self._get_deserialized_task_to_compute( deadline=self.message_timestamp - 1 ) report_computed_task = self._get_deserialized_report_computed_task( task_to_compute=task_to_compute ) correct_golem_data = self._get_deserialized_force_report_computed_task( report_computed_task=report_computed_task ) response = self.send_request( url='core:send', data=dump( correct_golem_data, self.PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY), ) self.assertEqual(response.status_code, 200) response_message = load( response.content, self.PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY, ) self.assertIsInstance(response_message, message.concents.ForceReportComputedTaskResponse) self.assertEqual(response_message.reason, message.concents.ForceReportComputedTaskResponse.REASON.SubtaskTimeout)
def test_send_should_return_http_400_if_task_to_compute_deadline_exceeded(self): compute_task_def = message.ComputeTaskDef() compute_task_def['task_id'] = '8' compute_task_def['deadline'] = self.message_timestamp - 9000 with freeze_time(datetime.datetime.fromtimestamp(self.message_timestamp - 10000)): task_to_compute = tasks.TaskToComputeFactory( compute_task_def = self.compute_task_def, provider_public_key = PROVIDER_PUBLIC_KEY, requestor_public_key = REQUESTOR_PUBLIC_KEY, price=0, ) serialized_task_to_compute = dump(task_to_compute, REQUESTOR_PRIVATE_KEY, PROVIDER_PUBLIC_KEY) deserialized_task_to_compute = load(serialized_task_to_compute, PROVIDER_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, check_time = False) ack_report_computed_task = message.AckReportComputedTask() ack_report_computed_task.report_computed_task = message.ReportComputedTask( task_to_compute = deserialized_task_to_compute ) response_400 = self.client.post( reverse('core:send'), data = dump( ack_report_computed_task, PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY ), content_type = 'application/octet-stream', ) self._test_400_response( response_400, error_code=ErrorCode.QUEUE_COMMUNICATION_NOT_STARTED )
def receive_all_left_pending_responses( host: str, endpoint: str, client_private_key: bytes, client_public_key: bytes, concent_public_key: bytes, client_name: str, ) -> None: url = f"{host}/api/v1/{endpoint}/" status_code = 200 received_messages = [] while status_code == 200: response = requests.post(f"{url}", headers=REQUEST_HEADERS, data=create_client_auth_message( client_private_key, client_public_key, concent_public_key), verify=False) status_code = response.status_code if status_code == 200: if isinstance(response.content, bytes) and response.headers[ 'Content-Type'] == 'application/octet-stream': received_messages.append( load(response.content, client_private_key, concent_public_key).__class__.__name__) if len(received_messages) > 0: print( f'Concent had {len(received_messages)} messages which waited for {client_name} to receive. Name of these messages: {received_messages}' ) else: print(f'Concent had not any pending messages for {client_name}')
def test_ethereum_address(self): msg = factories.tasks.TaskToComputeFactory() serialized = shortcuts.dump(msg, None, None) msg_l = shortcuts.load(serialized, None, None) for addr_slot in ( 'requestor_ethereum_address', 'provider_ethereum_address'): address = getattr(msg_l, addr_slot) self.assertEqual(len(address), 2 + (20*2))
def try_to_decode_golem_message(private_key, public_key, content): try: decoded_response = load(content, private_key, public_key, check_time=False) except MessageError: print("Failed to decode a Golem Message.") raise return decoded_response
def test_send_should_return_http_400_if_task_to_compute_deadline_is_not_an_integer(self): compute_task_def = ComputeTaskDefFactory() invalid_values = [ -11, 'a11b', {}, [], (1, 2, 3), None, ] for deadline in invalid_values: StoredMessage.objects.all().delete() compute_task_def['deadline'] = deadline task_to_compute = tasks.TaskToComputeFactory( compute_task_def=compute_task_def, provider_public_key=self._get_provider_hex_public_key(), requestor_public_key=self._get_requestor_hex_public_key(), ) serialized_task_to_compute = dump( task_to_compute, self.REQUESTOR_PRIVATE_KEY, self.PROVIDER_PUBLIC_KEY, ) deserialized_task_to_compute = load( serialized_task_to_compute, self.PROVIDER_PRIVATE_KEY, self.REQUESTOR_PUBLIC_KEY, check_time=False, ) with freeze_time("2017-11-17 10:00:00"): force_report_computed_task = message.concents.ForceReportComputedTask( report_computed_task=message.tasks.ReportComputedTask( task_to_compute=deserialized_task_to_compute ) ) response_400 = self.send_request( url='core:send', data=dump( force_report_computed_task, self.PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY ), ) self._test_400_response(response_400)
def test_validate_that_golem_messages_are_signed_with_key_should_raise_error_if_incorrect_message_and_key_is_used(self): task_to_compute = tasks.TaskToComputeFactory() dumped_task_to_compute = dump(task_to_compute, CONCENT_PRIVATE_KEY, CONCENT_PUBLIC_KEY) task_to_compute = load(dumped_task_to_compute, CONCENT_PRIVATE_KEY, CONCENT_PUBLIC_KEY) assert task_to_compute.sig is not None assert task_to_compute.SIGN is not False with self.assertRaises(Http400): validate_that_golem_messages_are_signed_with_key( REQUESTOR_PUBLIC_KEY, task_to_compute, )
def test_validate_that_golem_messages_are_signed_with_key_should_not_raise_error_if_correct_message_and_key_is_used(self): task_to_compute = tasks.TaskToComputeFactory() dumped_task_to_compute = dump(task_to_compute, CONCENT_PRIVATE_KEY, CONCENT_PUBLIC_KEY) task_to_compute = load(dumped_task_to_compute, CONCENT_PRIVATE_KEY, CONCENT_PUBLIC_KEY) assert task_to_compute.sig is not None assert task_to_compute.SIGN is not False try: validate_that_golem_messages_are_signed_with_key( CONCENT_PUBLIC_KEY, task_to_compute, ) except Http400: self.fail()
def test_send_should_return_http_400_if_task_to_compute_deadline_is_not_an_integer( self): compute_task_def = message.ComputeTaskDef() compute_task_def['task_id'] = '8' compute_task_def['subtask_id'] = '8' invalid_values = [ -11, 'a11b', {}, [], (1, 2, 3), None, ] for deadline in invalid_values: StoredMessage.objects.all().delete() compute_task_def['deadline'] = deadline task_to_compute = tasks.TaskToComputeFactory( compute_task_def=compute_task_def, provider_public_key=PROVIDER_PUBLIC_KEY, requestor_public_key=REQUESTOR_PUBLIC_KEY, price=0, ) serialized_task_to_compute = dump(task_to_compute, REQUESTOR_PRIVATE_KEY, PROVIDER_PUBLIC_KEY) deserialized_task_to_compute = load(serialized_task_to_compute, PROVIDER_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, check_time=False) with freeze_time("2017-11-17 10:00:00"): force_report_computed_task = message.ForceReportComputedTask( report_computed_task=message.tasks.ReportComputedTask( task_to_compute=deserialized_task_to_compute)) response_400 = self.client.post( reverse('core:send'), data=dump(force_report_computed_task, PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY), content_type='application/octet-stream', ) self._test_400_response(response_400)
def _exchange_message(self, priv_key, cluster_url, data): headers = { 'Content-Type': 'application/octet-stream', } response = requests.post(cluster_url, headers=headers, data=data) if response.status_code == 202: print('') print('STATUS: 202 Message Accepted') elif response.status_code == 204: print('') print('STATUS: 204 No Content') elif response.status_code in [400, 404, 500, 503]: print('') print('STATUS: {}'.format(response.status_code)) print('Response Content:', response.content) else: deserialized_response = load(response.content, priv_key, self.concent_pub_key, check_time=False) print_message(deserialized_response, cluster_url, '')
def test_message_remove_task_container(self): test_cases = 10 task_ids = ['test-{}'.format(uuid.uuid4()) for _ in range(test_cases)] remove_tasks = [message.RemoveTask(task_id=task_ids[i]) for i in range(test_cases)] msg = message.RemoveTaskContainer(remove_tasks=remove_tasks) serialized = shortcuts.dump(msg, None, None) msg_l = shortcuts.load(serialized, None, None) expected = [ ['remove_tasks', remove_tasks] ] self.assertEqual(expected, msg_l.slots()) self.assertEqual(len(msg_l.remove_tasks), test_cases) for msg_remove_task in msg_l.remove_tasks: self.assertIsInstance( msg_remove_task, message.p2p.RemoveTask ) for i in range(test_cases): self.assertEqual(msg_l.remove_tasks[i].task_id, task_ids[i])
def test_timestamp_and_timezones(self, *_): epoch_t = 1475238345 def set_tz(tz): os.environ['TZ'] = tz try: time.tzset() except AttributeError: raise unittest.SkipTest("tzset required") set_tz('Europe/Warsaw') warsaw_time = time.localtime(epoch_t) msg_pre = message.Hello(header=datastructures.MessageHeader( message.Hello.TYPE, epoch_t, False, )) data = shortcuts.dump(msg_pre, None, None) set_tz('US/Eastern') msg_post = shortcuts.load(data, None, None) newyork_time = time.localtime(msg_post.timestamp) self.assertNotEqual(warsaw_time, newyork_time) self.assertEqual(time.gmtime(epoch_t), time.gmtime(msg_post.timestamp))
def test_receive_should_accept_valid_message(self): message_timestamp = datetime.datetime.now(timezone.utc) new_message = StoredMessage( type=self.force_golem_data.report_computed_task.TYPE, timestamp=message_timestamp, data=self.force_golem_data.report_computed_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member ) new_message.full_clean() new_message.save() client_provider = Client(public_key_bytes=PROVIDER_PUBLIC_KEY) client_provider.full_clean() client_provider.save() client_requestor = Client(public_key_bytes=REQUESTOR_PUBLIC_KEY) client_requestor.full_clean() client_requestor.save() task_to_compute_message = StoredMessage( type=self.task_to_compute.TYPE, timestamp=message_timestamp, data=self.task_to_compute.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member ) task_to_compute_message.full_clean() task_to_compute_message.save() subtask = Subtask( task_id=self.compute_task_def['task_id'], subtask_id=self.compute_task_def['subtask_id'], task_to_compute=task_to_compute_message, report_computed_task=new_message, state=Subtask.SubtaskState.REPORTED.name, # pylint: disable=no-member provider=client_provider, requestor=client_requestor, result_package_size=self.size, computation_deadline=parse_timestamp_to_utc_datetime( self.compute_task_def['deadline'])) subtask.full_clean() subtask.save() new_message_inbox = PendingResponse( response_type=PendingResponse.ResponseType.ForceReportComputedTask. name, # pylint: disable=no-member client=client_requestor, queue=PendingResponse.Queue.Receive.name, # pylint: disable=no-member subtask=subtask, ) new_message_inbox.full_clean() new_message_inbox.save() response = self.client.post( reverse('core:receive'), content_type='application/octet-stream', data=self._create_client_auth_message(REQUESTOR_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY), ) decoded_response = load( response.content, REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY, ) self.assertEqual(response.status_code, 200) self.assertEqual( new_message.task_id, decoded_response.report_computed_task. task_to_compute.compute_task_def['task_id']) self.assertEqual( new_message.subtask_id, decoded_response.report_computed_task. task_to_compute.compute_task_def['subtask_id'])
def test_serialization(self): message_instance = self.get_instance() serialized_message = dump(message_instance, None, None) deserialized_message = load(serialized_message, None, None) self.assertEqual(message_instance, deserialized_message)
def test_receive_should_return_first_messages_in_order_they_were_added_to_queue_if_the_receive_queue_contains_only_force_report_and_its_past_deadline(self): message_timestamp = parse_timestamp_to_utc_datetime(get_current_utc_timestamp()) new_message = StoredMessage( type=self.force_golem_data.report_computed_task.header.type_, timestamp=message_timestamp, data=self.force_golem_data.report_computed_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) new_message.full_clean() new_message.save() want_to_compute_message = StoredMessage( type=self.want_to_compute_task.header.type_, timestamp=message_timestamp, data=self.want_to_compute_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) want_to_compute_message.full_clean() want_to_compute_message.save() task_to_compute_message = StoredMessage( type=self.task_to_compute.header.type_, timestamp=message_timestamp, data=self.task_to_compute.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) task_to_compute_message.full_clean() task_to_compute_message.save() ack_report_computed_task = message.tasks.AckReportComputedTask( report_computed_task=self.report_computed_task ) stored_ack_report_computed_task = StoredMessage( type=ack_report_computed_task.header.type_, timestamp=message_timestamp, data=ack_report_computed_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) stored_ack_report_computed_task.full_clean() stored_ack_report_computed_task.save() client_provider = Client( public_key_bytes=self.PROVIDER_PUBLIC_KEY ) client_provider.full_clean() client_provider.save() client_requestor = Client( public_key_bytes=self.REQUESTOR_PUBLIC_KEY ) client_requestor.full_clean() client_requestor.save() subtask = Subtask( task_id = self.compute_task_def['task_id'], subtask_id = self.compute_task_def['subtask_id'], report_computed_task = new_message, task_to_compute = task_to_compute_message, want_to_compute_task=want_to_compute_message, ack_report_computed_task = stored_ack_report_computed_task, state = Subtask.SubtaskState.REPORTED.name, # pylint: disable=no-member provider = client_provider, requestor = client_requestor, result_package_size=self.size, computation_deadline=parse_timestamp_to_utc_datetime(self.compute_task_def['deadline']) ) subtask.full_clean() subtask.save() new_message_inbox = PendingResponse( response_type=PendingResponse.ResponseType.ForceReportComputedTask.name, # pylint: disable=no-member client=client_requestor, queue=PendingResponse.Queue.Receive.name, # pylint: disable=no-member subtask=subtask, ) new_message_inbox.full_clean() new_message_inbox.save() new_message_inbox_out_of_band = PendingResponse( response_type=PendingResponse.ResponseType.VerdictReportComputedTask.name, # pylint: disable=no-member client=client_requestor, queue=PendingResponse.Queue.ReceiveOutOfBand.name, # pylint: disable=no-member subtask=subtask, ) new_message_inbox_out_of_band.full_clean() new_message_inbox_out_of_band.save() with freeze_time("2017-11-17 12:00:00"): response = self.send_request( url='core:receive', data=self._create_client_auth_message(self.REQUESTOR_PRIVATE_KEY, self.REQUESTOR_PUBLIC_KEY), ) decoded_message = load( response.content, self.REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY, check_time=False, ) self.assertIsInstance(decoded_message, message.concents.ForceReportComputedTask) self.assertEqual(response.status_code, 200) self.assertEqual(decoded_message.timestamp, self._create_timestamp_from_string("2017-11-17 12:00:00")) self.assertEqual(decoded_message.report_computed_task.task_to_compute.compute_task_def, self.task_to_compute.compute_task_def) # pylint: disable=no-member self.assertEqual(decoded_message.report_computed_task.task_to_compute.sig, self.task_to_compute.sig) with freeze_time("2017-11-17 12:00:00"): response = self.send_request( url='core:receive', data=self._create_client_auth_message(self.REQUESTOR_PRIVATE_KEY, self.REQUESTOR_PUBLIC_KEY), ) decoded_message = load( response.content, self.REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY, check_time=False, ) self.assertIsInstance(decoded_message, message.concents.VerdictReportComputedTask) self.assertEqual(response.status_code, 200) self.assertEqual(decoded_message.timestamp, self._create_timestamp_from_string("2017-11-17 12:00:00")) self.assertEqual(decoded_message.ack_report_computed_task.report_computed_task.task_to_compute.compute_task_def, self.task_to_compute.compute_task_def) # pylint: disable=no-member self.assertEqual(decoded_message.ack_report_computed_task.report_computed_task.task_to_compute.sig, self.task_to_compute.sig)
def test_receive_should_accept_valid_message(self): message_timestamp = parse_timestamp_to_utc_datetime(get_current_utc_timestamp()) new_message = StoredMessage( type=self.force_golem_data.report_computed_task.header.type_, timestamp=message_timestamp, data=self.force_golem_data.report_computed_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) new_message.full_clean() new_message.save() client_provider = Client( public_key_bytes=self.PROVIDER_PUBLIC_KEY ) client_provider.full_clean() client_provider.save() client_requestor = Client( public_key_bytes=self.REQUESTOR_PUBLIC_KEY ) client_requestor.full_clean() client_requestor.save() want_to_compute_message = StoredMessage( type=self.want_to_compute_task.header.type_, timestamp=message_timestamp, data=self.want_to_compute_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) want_to_compute_message.full_clean() want_to_compute_message.save() task_to_compute_message = StoredMessage( type=self.task_to_compute.header.type_, timestamp=message_timestamp, data=self.task_to_compute.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member protocol_version=settings.GOLEM_MESSAGES_VERSION, ) task_to_compute_message.full_clean() task_to_compute_message.save() subtask = Subtask( task_id = self.compute_task_def['task_id'], subtask_id = self.compute_task_def['subtask_id'], task_to_compute = task_to_compute_message, want_to_compute_task=want_to_compute_message, report_computed_task = new_message, state = Subtask.SubtaskState.REPORTED.name, # pylint: disable=no-member provider = client_provider, requestor = client_requestor, result_package_size=self.size, computation_deadline=parse_timestamp_to_utc_datetime(self.compute_task_def['deadline']) ) subtask.full_clean() subtask.save() new_message_inbox = PendingResponse( response_type=PendingResponse.ResponseType.ForceReportComputedTask.name, # pylint: disable=no-member client=client_requestor, queue=PendingResponse.Queue.Receive.name, # pylint: disable=no-member subtask=subtask, ) new_message_inbox.full_clean() new_message_inbox.save() response = self.send_request( url='core:receive', data=self._create_client_auth_message(self.REQUESTOR_PRIVATE_KEY, self.REQUESTOR_PUBLIC_KEY), ) decoded_response = load( response.content, self.REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY, ) self.assertEqual(response.status_code, 200) self.assertEqual(new_message.task_id, decoded_response.report_computed_task.task_to_compute.compute_task_def['task_id']) self.assertEqual(new_message.subtask_id, decoded_response.report_computed_task.task_to_compute.compute_task_def['subtask_id'])
def parse_headers( request: WSGIRequest, path_to_file: str, operation: FileTransferToken.Operation, ) -> Union[FileTransferToken.FileInfo, JsonResponse]: # Decode and check if request header contains a golem message: if 'HTTP_AUTHORIZATION' not in request.META: return gatekeeper_access_denied_response( "Missing 'Authorization' header.", operation, ErrorCode.HEADER_AUTHORIZATION_MISSING, path_to_file, ) authorization_scheme_and_token = request.META['HTTP_AUTHORIZATION'].split(" ", 1) assert len(authorization_scheme_and_token) in [1, 2] if len(authorization_scheme_and_token) == 1: return gatekeeper_access_denied_response( "Missing token in the 'Authorization' header.", operation, ErrorCode.HEADER_AUTHORIZATION_MISSING_TOKEN, path_to_file, ) (scheme, token) = authorization_scheme_and_token if scheme != 'Golem': return gatekeeper_access_denied_response( "Unrecognized scheme in the 'Authorization' header.", operation, ErrorCode.HEADER_AUTHORIZATION_UNRECOGNIZED_SCHEME, path_to_file, ) try: decoded_auth_header_content = b64decode(token, validate = True) except binascii.Error: return gatekeeper_access_denied_response( "Unable to decode token in the 'Authorization' header.", operation, ErrorCode.HEADER_AUTHORIZATION_NOT_BASE64_ENCODED_VALUE, path_to_file, ) try: loaded_golem_message = load( decoded_auth_header_content, settings.CONCENT_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, check_time = False ) except MessageError: return gatekeeper_access_denied_response( "Token in the 'Authorization' header is not a valid Golem message.", operation, ErrorCode.HEADER_AUTHORIZATION_TOKEN_INVALID_MESSAGE, path_to_file, ) assert isinstance(loaded_golem_message, Message) # Check if request header contains Concent-Auth: if 'HTTP_CONCENT_AUTH' not in request.META: return gatekeeper_access_denied_response( 'Missing Concent-Auth header.', operation, ErrorCode.AUTH_CLIENT_AUTH_MESSAGE_MISSING, path_to_file, loaded_golem_message.subtask_id ) # Try to load in ClientAuthorization message from Concent-Auth header try: client_authorization = load( b64decode(request.META['HTTP_CONCENT_AUTH'], validate=True), settings.CONCENT_PRIVATE_KEY, loaded_golem_message.authorized_client_public_key, ) concent_client_public_key = b64encode(client_authorization.client_public_key).decode('ascii') except (MessageError, binascii.Error): return gatekeeper_access_denied_response( 'Cannot load ClientAuthorization message from Concent-Auth header.', operation, ErrorCode.AUTH_CLIENT_AUTH_MESSAGE_INVALID, path_to_file, loaded_golem_message.subtask_id ) logging.log( logger, f"{loaded_golem_message.operation.capitalize()} request will be validated. " f"Message type: '{loaded_golem_message.__class__.__name__}'. File: '{path_to_file}'", subtask_id=loaded_golem_message.subtask_id, client_public_key=concent_client_public_key, ) current_time = get_current_utc_timestamp() if current_time > loaded_golem_message.token_expiration_deadline: return gatekeeper_access_denied_response( 'token_expiration_deadline has passed.', operation, ErrorCode.MESSAGE_TOKEN_EXPIRATION_DEADLINE_PASSED, path_to_file, loaded_golem_message.subtask_id, concent_client_public_key ) try: validate_file_transfer_token(loaded_golem_message) except FileTransferTokenError as exception: return gatekeeper_access_denied_response( exception.error_message, operation, exception.error_code, path_to_file, loaded_golem_message.subtask_id, concent_client_public_key ) authorized_client_public_key_base64 = (b64encode(loaded_golem_message.authorized_client_public_key)).decode('ascii') if concent_client_public_key != authorized_client_public_key_base64: return gatekeeper_access_denied_response( 'You are not authorized to use this token.', operation, ErrorCode.MESSAGE_AUTHORIZED_CLIENT_PUBLIC_KEY_UNAUTHORIZED_CLIENT, path_to_file, loaded_golem_message.subtask_id, concent_client_public_key ) # -OPERATION if request.method == 'POST' and loaded_golem_message.operation != FileTransferToken.Operation.upload: return gatekeeper_access_denied_response( 'Upload requests must use POST method.', operation, ErrorCode.MESSAGE_OPERATION_INVALID, path_to_file, loaded_golem_message.subtask_id, concent_client_public_key ) if request.method in ['GET', 'HEAD'] and loaded_golem_message.operation != FileTransferToken.Operation.download: return gatekeeper_access_denied_response( 'Download requests must use GET or HEAD method.', operation, ErrorCode.MESSAGE_OPERATION_INVALID, path_to_file, loaded_golem_message.subtask_id, concent_client_public_key ) matching_files = [file for file in loaded_golem_message.files if path_to_file == file['path']] if len(matching_files) == 1: logging.log( logger, f"{loaded_golem_message.operation.capitalize()} request passed all validations. " f"Message type: '{loaded_golem_message.__class__.__name__}'. File: '{path_to_file}'", subtask_id=loaded_golem_message.subtask_id, client_public_key=concent_client_public_key ) return matching_files[0] else: assert len(matching_files) == 0 return gatekeeper_access_denied_response( 'Your token does not authorize you to transfer the requested file.', operation, ErrorCode.MESSAGE_FILES_PATH_NOT_LISTED_IN_FILES, path_to_file, loaded_golem_message.subtask_id, concent_client_public_key )
def test_task_to_compute_basic(self): ttc = factories.tasks.TaskToComputeFactory() serialized = shortcuts.dump(ttc, None, None) msg = shortcuts.load(serialized, None, None) self.assertIsInstance(msg, message.tasks.TaskToCompute)
def _dump_and_load(msg): msg_d = shortcuts.dump(msg, None, None) return shortcuts.load(msg_d, None, None)
def test_receive_should_return_first_messages_in_order_they_were_added_to_queue_if_the_receive_queue_contains_only_force_report_and_its_past_deadline( self): message_timestamp = datetime.datetime.now(timezone.utc) new_message = StoredMessage( type=self.force_golem_data.report_computed_task.TYPE, timestamp=message_timestamp, data=self.force_golem_data.report_computed_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member ) new_message.full_clean() new_message.save() task_to_compute_message = StoredMessage( type=self.task_to_compute.TYPE, timestamp=message_timestamp, data=self.task_to_compute.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member ) task_to_compute_message.full_clean() task_to_compute_message.save() ack_report_computed_task = message.AckReportComputedTask( report_computed_task=message.ReportComputedTask( task_to_compute=self.task_to_compute, )) stored_ack_report_computed_task = StoredMessage( type=ack_report_computed_task.TYPE, timestamp=message_timestamp, data=ack_report_computed_task.serialize(), task_id=self.compute_task_def['task_id'], # pylint: disable=no-member subtask_id=self.compute_task_def['subtask_id'], # pylint: disable=no-member ) stored_ack_report_computed_task.full_clean() stored_ack_report_computed_task.save() client_provider = Client(public_key_bytes=PROVIDER_PUBLIC_KEY) client_provider.full_clean() client_provider.save() client_requestor = Client(public_key_bytes=REQUESTOR_PUBLIC_KEY) client_requestor.full_clean() client_requestor.save() subtask = Subtask( task_id=self.compute_task_def['task_id'], subtask_id=self.compute_task_def['subtask_id'], report_computed_task=new_message, task_to_compute=task_to_compute_message, ack_report_computed_task=stored_ack_report_computed_task, state=Subtask.SubtaskState.REPORTED.name, # pylint: disable=no-member provider=client_provider, requestor=client_requestor, result_package_size=self.size, computation_deadline=parse_timestamp_to_utc_datetime( self.compute_task_def['deadline'])) subtask.full_clean() subtask.save() new_message_inbox = PendingResponse( response_type=PendingResponse.ResponseType.ForceReportComputedTask. name, # pylint: disable=no-member client=client_requestor, queue=PendingResponse.Queue.Receive.name, # pylint: disable=no-member subtask=subtask, ) new_message_inbox.full_clean() new_message_inbox.save() new_message_inbox_out_of_band = PendingResponse( response_type=PendingResponse.ResponseType. VerdictReportComputedTask.name, # pylint: disable=no-member client=client_requestor, queue=PendingResponse.Queue.ReceiveOutOfBand.name, # pylint: disable=no-member subtask=subtask, ) new_message_inbox_out_of_band.full_clean() new_message_inbox_out_of_band.save() with freeze_time("2017-11-17 12:00:00"): response = self.client.post( reverse('core:receive'), content_type='application/octet-stream', data=self._create_client_auth_message(REQUESTOR_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY), ) decoded_message = load( response.content, REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY, check_time=False, ) self.assertIsInstance(decoded_message, message.concents.ForceReportComputedTask) self.assertEqual(response.status_code, 200) self.assertEqual( decoded_message.timestamp, int(dateutil.parser.parse("2017-11-17 12:00:00").timestamp())) self.assertEqual(decoded_message.report_computed_task.task_to_compute. compute_task_def, self.task_to_compute.compute_task_def) # pylint: disable=no-member self.assertEqual( decoded_message.report_computed_task.task_to_compute.sig, self.task_to_compute.sig) with freeze_time("2017-11-17 12:00:00"): response = self.client.post( reverse('core:receive_out_of_band'), content_type='application/octet-stream', data=self._create_client_auth_message(REQUESTOR_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY), ) decoded_message = load( response.content, REQUESTOR_PRIVATE_KEY, CONCENT_PUBLIC_KEY, check_time=False, ) self.assertIsInstance(decoded_message, message.concents.VerdictReportComputedTask) self.assertEqual(response.status_code, 200) self.assertEqual( decoded_message.timestamp, int(dateutil.parser.parse("2017-11-17 12:00:00").timestamp())) self.assertEqual(decoded_message.ack_report_computed_task. report_computed_task.task_to_compute.compute_task_def, self.task_to_compute.compute_task_def) # pylint: disable=no-member self.assertEqual( decoded_message.ack_report_computed_task.report_computed_task. task_to_compute.sig, self.task_to_compute.sig)
def test_message_sig(self): """Signed message inside a signed message""" concent_keys = cryptography.ECCx(None) provider_keys = cryptography.ECCx(None) requestor_keys = cryptography.ECCx(None) task_to_compute = message.TaskToCompute() ctd = message.ComputeTaskDef({ 'task_id': 20, }) task_to_compute.compute_task_def = ctd # Dump TaskToCompute to make it signed s_task_to_compute = shortcuts.dump( task_to_compute, requestor_keys.raw_privkey, provider_keys.raw_pubkey, ) # Load TaskToCompute back to its original format task_to_compute = shortcuts.load( s_task_to_compute, provider_keys.raw_privkey, requestor_keys.raw_pubkey, ) first_sig = task_to_compute.sig first_hash = task_to_compute.get_short_hash() # Task TaskToCompute is verified correctly cryptography.ecdsa_verify( requestor_keys.raw_pubkey, task_to_compute.sig, task_to_compute.get_short_hash(), ) force_report = message.ForceReportComputedTask() force_report.task_to_compute = task_to_compute s_force_report = shortcuts.dump( force_report, provider_keys.raw_privkey, concent_keys.raw_pubkey, ) force_report = shortcuts.load( s_force_report, concent_keys.raw_privkey, provider_keys.raw_pubkey, ) second_sig = force_report.task_to_compute.sig second_hash = force_report.task_to_compute.get_short_hash() self.assertEqual(first_sig, second_sig) self.assertEqual(first_hash, second_hash) # Now, attached TaskToCompute should still be verified using # original key. ecdsa_verify will raise InvalidSignature on # failure. cryptography.ecdsa_verify( requestor_keys.raw_pubkey, force_report.task_to_compute.sig, force_report.task_to_compute.get_short_hash(), )