def add_in_data(self, data, data_hash=None, encrypted_data_encryption_key=None, data_iv=None): """Add inData work order parameter.""" if data is None: return util.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, "Invalid data format for in data") in_data_copy = self.params_obj["inData"] new_data_list = self.__add_data_params(in_data_copy, data, data_hash, encrypted_data_encryption_key, data_iv) self.params_obj["inData"] = new_data_list code, err_msg = WOcheck.schema_validation("sdk_inData", self.params_obj["inData"]) if not code: return util.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err_msg) return None
def render_POST(self, request): response = {} logger.info('Received a new request from the client') try: # process the message encoding encoding = request.getHeader('Content-Type') data = request.content.read() if encoding == 'application/json': try: input_json_str = data.decode('utf-8') input_json = json.loads(input_json_str) jrpc_id = input_json["id"] response = self._process_request(input_json_str) except AttributeError: logger.error("Error while loading input json") response = jrpc_utility.create_error_response( WorkOrderStatus.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: Error while loading input JSON file") return response else: # JRPC response with 0 as id is returned because id can't be # fetched from a request with unknown encoding. response = jrpc_utility.create_error_response( WorkOrderStatus.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unknown message encoding") return response except Exception as err: logger.exception('exception while decoding http request %s: %s', request.path, str(err)) # JRPC response with 0 as id is returned because id can't be # fetched from improper request response = jrpc_utility.create_error_response( WorkOrderStatus.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unable to decode incoming request") return response # send back the results try: if encoding == 'application/json': response = json.dumps(response) logger.info('response[%s]: %s', encoding, response) request.setHeader('content-type', encoding) request.setResponseCode(http.OK) return response.encode('utf8') except Exception as err: logger.exception( 'unknown exception while processing request %s: %s', request.path, str(err)) response = jrpc_utility.create_error_response( WorkOrderStatus.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: unknown exception processing http " + "request {0}: {1}".format(request.path, str(err))) return response
def render_POST(self, request): """ Handle a POST request to the listener. Decode and delegate to _process_request for handling. Parameters : request - Request coming in from a client Returns : response - A dict type response """ response = {} logger.info('Received a new request from the client') try: # process the message encoding encoding = request.getHeader('Content-Type') data = request.content.read() if encoding == 'application/json': input_json_str = data.decode('utf-8') response = self._process_request(input_json_str) else: # JRPC response with 0 as id is returned because id can't be # fetched from a request with unknown encoding. response = jrpc_utility.create_error_response( JRPCErrorCodes.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unknown message encoding") return response except Exception as err: logger.exception('exception while decoding http request %s: %s', request.path, str(err)) # JRPC response with 0 as id is returned because id can't be # fetched from improper request response = jrpc_utility.create_error_response( JRPCErrorCodes.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unable to decode incoming request") return response # send back the results try: if encoding == 'application/json': response = json.dumps(response) logger.info('response[%s]: %s', encoding, response) request.setHeader('content-type', encoding) request.setResponseCode(http.OK) return response.encode('utf8') except Exception as err: logger.exception( 'unknown exception while processing request %s: %s', request.path, str(err)) response = jrpc_utility.create_error_response( JRPCErrorCodes.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: unknown exception processing http " + "request {0}: {1}".format(request.path, str(err))) return response
def workerType_validation(self, worker_type, json_rpc_request): """ Validate the worker type recived in worker related request Parameters: worker_type Worker type value derived from the worker's DID json_rpc_request JSON RPC request Returns: True if worker type is valid False with error response if workertype is invalid """ if worker_type is not None: if isinstance(worker_type, WorkerType): json_rpc_request["params"]["workerType"] = worker_type.value elif isinstance(worker_type, int) and \ (worker_type in [w.value for w in WorkerType]): json_rpc_request["params"]["workerType"] = worker_type else: return False, create_error_response( JRPCErrorCodes.INVALID_PARAMETER_FORMAT_OR_VALUE, json_rpc_request["id"], "WorkType should be an Integer of range 1-3") return True, ""
def _execute_wo_in_trusted_enclave(self, input_json_str): """ Submits workorder request to Worker enclave and retrieves the response Parameters : input_json_str - A JSON formatted str of the request to execute Returns : json_response - A JSON response received from the enclave. Errors are also wrapped in a JSON str if exceptions have occurred. """ try: pre_proc_output = self._wpe_requester\ .preprocess_work_order(input_json_str, self.encryption_key) if "error" in pre_proc_output: # If error in preprocessing response, skip workorder processing logger.error("Failed to preprocess at WPE enclave manager.") return pre_proc_output wo_response = self._send_wo_to_process(input_json_str, pre_proc_output) except Exception as e: logger.error("failed to execute work order; %s", str(e)) wo_response = create_error_response(WorkOrderStatus.FAILED, random.randint(0, 100000), str(e)) logger.info("unknown enclave type response = %s", wo_response) return wo_response
def _persist_wo_response_to_db(self, wo_id, status, wo_response=None, msg=None): """ persist the response of a work order processing into the database for success as well as failure. Construct response JSON in case one is not passed in. Make use of msg field in json. Parameters: @param wo_id - Id of the work-order being handled @param status - WorkOrderStatus of work order ro be persisted @param wo_response - Response JSON to be persisted @param msg - Message in response in case wo_response is None """ if wo_response is None: # Passing jrpc_id as 0 as this will be overridden anyways err_response = jrpc_utility.create_error_response( WorkOrderStatus.FAILED, "0", msg) wo_response = json.dumps(err_response) logger.info("Update response in wo-responses for workorder %s.", wo_id) self._kv_helper.set("wo-responses", wo_id, wo_response) logger.info( "Persist work order id %s in wo-worker-processed map.", wo_id) # Append wo_id to the list of work orders processed by this worker self._kv_helper.csv_append("wo-worker-processed", self._worker_id, wo_id)
def worker_retrieve(self, worker_id, id=None): """ Retrieve the worker identified by worker ID. Parameters: worker_id Worker ID value derived from the worker's DID id Optional Optional JSON RPC request ID Returns: JRPC response containing: organization ID, application ID, worker status, and worker details. """ if worker_id is None: return create_error_response( JRPCErrorCodes.INVALID_PARAMETER_FORMAT_OR_VALUE, id, "Empty params in the request") json_rpc_request = { "jsonrpc": "2.0", "method": "WorkerRetrieve", "id": id, "params": { "workerId": worker_id } } response = self.__uri_client._postmsg(json.dumps(json_rpc_request)) return response
def render_GET(self, request): # JRPC response with id 0 is returned because id parameter # will not be found in GET request response = jrpc_utility.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, "0", "Only POST request is supported") logger.error( "GET request is not supported. Only POST request is supported") return response
def test_create_error_response(self): """Tests to verify create_error_response(code, jrpc_id, message) function """ expected_response = { "jsonrpc": "2.0", "id": "id1", "error": { "code": 404, "message": "Page not found" }, } self.assertEquals(expected_response, create_error_response(404, "id1", "Page not found")) expected_response = { "jsonrpc": "2.0", "id": "id2", "error": { "code": "2", "message": "General error" }, } self.assertEquals(expected_response, create_error_response("2", "id2", "General error"))
def add_encrypted_request_hash(self): """ Calculates request hash based on EEA trusted-computing spec 6.1.8.1 and set encryptedRequestHash parameter in the request. """ try: sig_obj = signature.ClientSignature() self.request_hash = sig_obj.calculate_request_hash(self.params_obj) encrypted_request_hash = crypto_utility.encrypt_data( self.request_hash, self.session_key, self.session_iv) enc_request_hash_hex = crypto_utility.byte_array_to_hex( encrypted_request_hash) self.params_obj["encryptedRequestHash"] = enc_request_hash_hex return None except Exception as err: return util.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err)
def render_GET(self, request): """ Handle a GET request to the listener. Not supported. So only error is expected to be returned as response. Parameters : request - Request coming in from a client Returns : response - A dict type response which always contains error """ # JRPC response with id 0 is returned because id parameter # will not be found in GET request response = jrpc_utility.create_error_response( JRPCErrorCodes.INVALID_PARAMETER_FORMAT_OR_VALUE, "0", "Only POST request is supported") logger.error( "GET request is not supported. Only POST request is supported") return response
def create_request(self, work_order_id, worker_id, workload_id, requester_id, session_key, session_iv, requester_nonce, verifying_key=None, payload_format="JSON-RPC", response_timeout_msecs=6000, result_uri=None, notify_uri=None, worker_encryption_key=None, data_encryption_algorithm=None, encrypted_session_key=None): """validate and creates workorder request with received values""" if work_order_id: self.set_work_order_id(work_order_id) self.set_response_timeout_msecs(response_timeout_msecs) self.set_payload_format(payload_format) self.set_requester_nonce(requester_nonce) self.session_key = session_key self.set_workload_id(workload_id) self.set_worker_id(worker_id) if requester_id is not None: self.set_requester_id(requester_id) if session_iv: self.set_session_key_iv( crypto_utility.byte_array_to_hex(session_iv)) if result_uri: self.set_result_uri(result_uri) if notify_uri: self.set_notify_uri(notify_uri) if worker_encryption_key: self.set_worker_encryption_key(worker_encryption_key) if data_encryption_algorithm: self.set_data_encryption_algorithm(data_encryption_algorithm) self.set_encrypted_session_key(encrypted_session_key) code, err_msg = WOcheck.schema_validation("sdk_WorkOrderSubmit", self.params_obj) # When the WorkorderSubmit request fails basic Json Validation # the init object created is deleted to avoid futhur processing # on that object by the user. if not code: return util.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err_msg) self.set_worker_encryption_key( worker_encryption_key.encode("UTF-8").hex()) self.session_iv = session_iv self.params_obj["encryptedRequestHash"] = "" self.params_obj["requesterSignature"] = "" self.params_obj["inData"] = list() if encrypted_session_key is None: try: encrypted_session_key = crypto_utility.generate_encrypted_key( session_key, worker_encryption_key) self.set_encrypted_session_key( crypto_utility.byte_array_to_hex(encrypted_session_key)) except Exception as err: return util.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err) return None