def incoming(self, invocation): #log.debug("ValidateInterceptor.incoming: %s", invocation) if self.enabled: payload = invocation.message # If payload is IonObject, convert from dict to object for processing if "format" in invocation.headers and isinstance(payload, dict): clzz = invocation.headers["format"] if is_ion_object(clzz): payload = IonObject(clzz, payload) #log.debug("Payload, pre-validate: %s", payload) # IonObject _validate will throw AttributeError on validation failure. # Raise corresponding BadRequest exception into message stack. # Ideally the validator should pass on problems, but for now just log # any errors and keep going, since logging and seeing invalid situations are better # than skipping validation altogether. def validate_ionobj(obj): if isinstance(obj, IonObjectBase): obj._validate() return obj try: walk(payload, validate_ionobj) except AttributeError as e: if invocation.headers.has_key("raise-exception") and invocation.headers['raise-exception']: log.warn('message failed validation: %s\nheaders %s\npayload %s', e.message, invocation.headers, payload) raise BadRequest(e.message) else: log.warn('message failed validation, but allowing it anyway: %s\nheaders %s\npayload %s', e.message, invocation.headers, payload) return invocation
def get_resource_schema(resource_type): try: #Validate requesting user and expiry and add governance headers ion_actor_id, expiry = get_governance_info_from_request() ion_actor_id, expiry = validate_request(ion_actor_id, expiry) schema_info = dict() #Prepare the dict entry for schema information including all of the internal object types schema_info['schemas'] = dict() #ION Objects are not registered as UNICODE names ion_object_name = str(resource_type) ret_obj = IonObject(ion_object_name, {}) # If it's an op input param or response message object. # Walk param list instantiating any params that were marked None as default. if hasattr(ret_obj, "_svc_name"): schema = ret_obj._schema for field in ret_obj._schema: if schema[field]["default"] is None: try: value = IonObject(schema[field]["type"], {}) except NotFound: # TODO # Some other non-IonObject type. Just use None as default for now. value = None setattr(ret_obj, field, value) #Add schema information for sub object types schema_info['schemas'][ion_object_name] = ret_obj._schema for field in ret_obj._schema: obj_type = ret_obj._schema[field]['type'] #First look for ION objects if is_ion_object(obj_type): try: value = IonObject(obj_type, {}) schema_info['schemas'][obj_type] = value._schema except NotFound: pass #Next look for ION Enums elif ret_obj._schema[field].has_key('enum_type'): if isenum(ret_obj._schema[field]['enum_type']): value = IonObject(ret_obj._schema[field]['enum_type'], {}) schema_info['schemas'][ret_obj._schema[field]['enum_type']] = value._str_map #Add an instance of the resource type object schema_info['object'] = ret_obj return gateway_json_response(schema_info) except Exception, e: return build_error_response(e)
def get_resource_schema(resource_type): try: #Validate requesting user and expiry and add governance headers ion_actor_id, expiry = get_governance_info_from_request() ion_actor_id, expiry = validate_request(ion_actor_id, expiry) schema_info = dict() #Prepare the dict entry for schema information including all of the internal object types schema_info['schemas'] = dict() #ION Objects are not registered as UNICODE names ion_object_name = str(resource_type) ret_obj = IonObject(ion_object_name, {}) # If it's an op input param or response message object. # Walk param list instantiating any params that were marked None as default. if hasattr(ret_obj, "_svc_name"): schema = ret_obj._schema for field in ret_obj._schema: if schema[field]["default"] is None: try: value = IonObject(schema[field]["type"], {}) except NotFound: # TODO # Some other non-IonObject type. Just use None as default for now. value = None setattr(ret_obj, field, value) #Add schema information for sub object types schema_info['schemas'][ion_object_name] = ret_obj._schema for field in ret_obj._schema: obj_type = ret_obj._schema[field]['type'] #First look for ION objects if is_ion_object(obj_type): try: value = IonObject(obj_type, {}) schema_info['schemas'][obj_type] = value._schema except NotFound: pass #Next look for ION Enums elif ret_obj._schema[field].has_key('enum_type'): if isenum(ret_obj._schema[field]['enum_type']): value = IonObject(ret_obj._schema[field]['enum_type'], {}) schema_info['schemas'][ret_obj._schema[field] ['enum_type']] = value._str_map #Add an instance of the resource type object schema_info['object'] = ret_obj return gateway_json_response(schema_info) except Exception, e: return build_error_response(e)
def get_object_schema(resource_type): schema_info = dict() #Prepare the dict entry for schema information including all of the internal object types schema_info['schemas'] = dict() #ION Objects are not registered as UNICODE names ion_object_name = str(resource_type) ret_obj = IonObject(ion_object_name, {}) # If it's an op input param or response message object. # Walk param list instantiating any params that were marked None as default. if hasattr(ret_obj, "_svc_name"): schema = ret_obj._schema for field in ret_obj._schema: if schema[field]["default"] is None: try: value = IonObject(schema[field]["type"], {}) except NotFound: # TODO # Some other non-IonObject type. Just use None as default for now. value = None setattr(ret_obj, field, value) #Add schema information for sub object types schema_info['schemas'][ion_object_name] = ret_obj._schema for field in ret_obj._schema: obj_type = ret_obj._schema[field]['type'] #First look for ION objects if is_ion_object(obj_type): try: value = IonObject(obj_type, {}) schema_info['schemas'][obj_type] = value._schema except NotFound: pass #Next look for ION Enums elif ret_obj._schema[field].has_key('enum_type'): if isenum(ret_obj._schema[field]['enum_type']): value = IonObject(ret_obj._schema[field]['enum_type'], {}) schema_info['schemas'][ret_obj._schema[field]['enum_type']] = value._str_map schema_info['object'] = ret_obj return schema_info
def incoming(self, invocation): if self.enabled: payload = invocation.message # If payload is IonObject, convert from dict to object for processing if "format" in invocation.headers and isinstance(payload, dict): clzz = invocation.headers["format"] if is_ion_object(clzz): payload = IonObject(clzz, payload) #log.debug("Payload, pre-validate: %s", payload) # IonObject _validate will throw AttributeError on validation failure. # Raise corresponding BadRequest exception into message stack. # Ideally the validator should pass on problems, but for now just log # any errors and keep going, since logging and seeing invalid situations are better # than skipping validation altogether. def validate_ionobj(obj): if isinstance(obj, IonObjectBase): obj._validate(validate_objects=False) return obj try: walk(payload, validate_ionobj) except AttributeError as e: raise_hdr = invocation.headers.get('raise-exception', None) if (self.raise_exception and raise_hdr is not False) or invocation.headers.get( 'raise-exception', None): log.warn( 'message failed validation: %s\nheaders %s\npayload %s', e.message, invocation.headers, payload) raise BadRequest(e.message) else: log.warn( 'message failed validation, but allowing it anyway: %s\nheaders %s\npayload %s', e.message, invocation.headers, payload) return invocation
def incoming(self, invocation): log.debug("ValidateInterceptor.incoming: %s", invocation) if self.enabled: payload = invocation.message # If payload is IonObject, convert from dict to object for processing if "format" in invocation.headers and isinstance(payload, dict): clzz = invocation.headers["format"] if is_ion_object(clzz): payload = IonObject(clzz, payload) log.debug("Payload, pre-validate: %s", payload) # IonObject _validate will throw AttributeError on validation failure. # Raise corresponding BadRequest exception into message stack. def validate_ionobj(obj): if isinstance(obj, IonObjectBase): obj._validate() return obj try: walk(payload, validate_ionobj) except AttributeError as e: import traceback import sys (exc_type, exc_value, exc_traceback) = sys.exc_info() tb_list = traceback.extract_tb(sys.exc_info()[2]) tb_list = traceback.format_list(tb_list) tb_output = "" for elt in tb_list: tb_output += elt log.debug("Object validation failed. %s" % e.message) log.debug("Traceback: %s" % str(tb_output)) raise BadRequest(e.message) return invocation
def incoming(self, invocation): # log.trace("PolicyInterceptor.incoming: %s", invocation.get_arg_value('process', invocation)) # print "========" # print invocation.headers # If missing the performative header, consider it as a failure message. msg_performative = invocation.get_header_value("performative", "failure") message_format = invocation.get_header_value("format", "") op = invocation.get_header_value("op", "unknown") process_type = invocation.get_invocation_process_type() sender, sender_type = invocation.get_message_sender() # TODO - This should be removed once better process security is implemented # THis fix infers that all messages that do not specify an actor id are TRUSTED wihtin the system policy_loaded = CFG.get_safe("system.load_policy", False) if policy_loaded: actor_id = invocation.get_header_value("ion-actor-id", None) else: actor_id = invocation.get_header_value("ion-actor-id", "anonymous") # Only check messages marked as the initial rpc request - TODO - remove the actor_id is not None when headless process have actor_ids if msg_performative == "request" and actor_id is not None: receiver = invocation.get_message_receiver() # Can's check policy if the controller is not initialized if self.governance_controller is None: log.debug("Skipping policy check for %s(%s) since governance_controller is None", receiver, op) invocation.message_annotations[ GovernanceDispatcher.POLICY__STATUS_ANNOTATION ] = GovernanceDispatcher.STATUS_SKIPPED return invocation # No need to check for requests from the system actor - should increase performance during startup if actor_id == self.governance_controller.system_actor_id: log.debug("Skipping policy check for %s(%s) for the system actor", receiver, op) invocation.message_annotations[ GovernanceDispatcher.POLICY__STATUS_ANNOTATION ] = GovernanceDispatcher.STATUS_SKIPPED return invocation # Check to see if there is a AlwaysVerifyPolicy decorator always_verify_policy = False if is_ion_object(message_format): try: msg_class = message_classes[message_format] always_verify_policy = has_class_decorator(msg_class, "AlwaysVerifyPolicy") except Exception: pass # For services only - if this is a sub RPC request from a higher level service that has already been validated and set a token # then skip checking policy yet again - should help with performance and to simplify policy # All calls from the RMS must be checked if ( not always_verify_policy and process_type == "service" and sender != "resource_management" and self.has_valid_token(invocation, PERMIT_SUB_CALLS) ): # log.debug("Skipping policy check for service call %s %s since token is valid", receiver, op) # print "skipping call to " + receiver + " " + op + " from " + actor_id + " process_type: " + process_type invocation.message_annotations[ GovernanceDispatcher.POLICY__STATUS_ANNOTATION ] = GovernanceDispatcher.STATUS_SKIPPED return invocation # log.debug("Checking request for %s: %s(%s) from %s ", process_type, receiver, op, actor_id) # Annotate the message has started policy checking invocation.message_annotations[ GovernanceDispatcher.POLICY__STATUS_ANNOTATION ] = GovernanceDispatcher.STATUS_STARTED ret = None # First check for Org boundary policies if the container is configured as such org_id = self.governance_controller.get_container_org_boundary_id() if org_id is not None: ret = self.governance_controller.policy_decision_point_manager.check_resource_request_policies( invocation, org_id ) if str(ret) != Decision.DENY_STR: # Next check endpoint process specific policies if process_type == "agent": ret = self.governance_controller.policy_decision_point_manager.check_agent_request_policies( invocation ) elif process_type == "service": ret = self.governance_controller.policy_decision_point_manager.check_service_request_policies( invocation ) # log.debug("Policy Decision: %s", ret) # Annonate the message has completed policy checking invocation.message_annotations[ GovernanceDispatcher.POLICY__STATUS_ANNOTATION ] = GovernanceDispatcher.STATUS_COMPLETE if ret is not None: if str(ret) == Decision.DENY_STR: self.annotate_denied_message(invocation) else: self.permit_sub_rpc_calls_token(invocation) else: invocation.message_annotations[ GovernanceDispatcher.POLICY__STATUS_ANNOTATION ] = GovernanceDispatcher.STATUS_SKIPPED return invocation
def incoming(self, invocation): """Policy governance process interceptor for messages received. Checks policy based on message headers. """ #log.trace("PolicyInterceptor.incoming: %s", invocation.get_arg_value('process', invocation)) #print "========" #print invocation.headers # If missing the performative header, consider it as a failure message. msg_performative = invocation.get_header_value(MSG_HEADER_PERFORMATIVE, 'failure') message_format = invocation.get_header_value(MSG_HEADER_FORMAT, '') op = invocation.get_header_value(MSG_HEADER_OP, 'unknown') process_type = invocation.get_invocation_process_type() sender, sender_type = invocation.get_message_sender() # TODO - This should be removed once better process security is implemented # We assume all external requests have security headers set (even anonymous calls), # so that calls from within the system (e.g. headless processes) can be considered trusted. policy_loaded = CFG.get_safe('system.load_policy', False) if policy_loaded: # With policy: maintain the actor id actor_id = invocation.get_header_value(MSG_HEADER_ACTOR, None) else: # Without policy: default to anonymous actor_id = invocation.get_header_value(MSG_HEADER_ACTOR, ANONYMOUS_ACTOR) # Only check messages marked as the initial rpc request # TODO - remove the actor_id is not None when headless process have actor_ids if msg_performative == 'request' and actor_id is not None: receiver = invocation.get_message_receiver() # Can't check policy if the controller is not initialized if self.governance_controller is None: log.debug("Skipping policy check for %s(%s) since governance_controller is None", receiver, op) invocation.message_annotations[GovernanceDispatcher.POLICY__STATUS_ANNOTATION] = GovernanceDispatcher.STATUS_SKIPPED return invocation # No need to check for requests from the system actor - should increase performance during startup if actor_id == self.governance_controller.system_actor_id: log.debug("Skipping policy check for %s(%s) for the system actor", receiver, op) invocation.message_annotations[GovernanceDispatcher.POLICY__STATUS_ANNOTATION] = GovernanceDispatcher.STATUS_SKIPPED return invocation # Check to see if there is a AlwaysVerifyPolicy decorator always_verify_policy = False if is_ion_object(message_format): try: msg_class = message_classes[message_format] always_verify_policy = has_class_decorator(msg_class, DECORATOR_ALWAYS_VERIFY_POLICY) except Exception: pass # For services only - if this is a sub RPC request from a higher level service that has # already been validated and set a token then skip checking policy yet again - should help # with performance and to simplify policy. # All calls from the RMS must be checked; it acts as generic facade forwarding many kinds of requests if not always_verify_policy and process_type == PROCTYPE_SERVICE and sender != 'resource_management' and \ self.has_valid_token(invocation, PERMIT_SUB_CALLS): #log.debug("Skipping policy check for service call %s %s since token is valid", receiver, op) invocation.message_annotations[GovernanceDispatcher.POLICY__STATUS_ANNOTATION] = GovernanceDispatcher.STATUS_SKIPPED return invocation #log.debug("Checking request for %s: %s(%s) from %s ", process_type, receiver, op, actor_id) # Annotate the message has started policy checking invocation.message_annotations[GovernanceDispatcher.POLICY__STATUS_ANNOTATION] = GovernanceDispatcher.STATUS_STARTED ret = None # ---- POLICY RULE CHECKS HERE ---- # First check for Org boundary policies if the container is configured as such org_id = self.governance_controller.get_container_org_boundary_id() if org_id is not None: ret = self.governance_controller.policy_decision_point_manager.check_resource_request_policies(invocation, org_id) if str(ret) != Decision.DENY_STR: # Next check endpoint process specific policies if process_type == PROCTYPE_AGENT: ret = self.governance_controller.policy_decision_point_manager.check_agent_request_policies(invocation) elif process_type == PROCTYPE_SERVICE: ret = self.governance_controller.policy_decision_point_manager.check_service_request_policies(invocation) #log.debug("Policy Decision: %s", ret) # ---- POLICY RULE CHECKS END ---- # Annotate the message has completed policy checking invocation.message_annotations[GovernanceDispatcher.POLICY__STATUS_ANNOTATION] = GovernanceDispatcher.STATUS_COMPLETE if ret is not None: if str(ret) == Decision.DENY_STR: self.annotate_denied_message(invocation) else: self.permit_sub_rpc_calls_token(invocation) else: invocation.message_annotations[GovernanceDispatcher.POLICY__STATUS_ANNOTATION] = GovernanceDispatcher.STATUS_SKIPPED return invocation
def _create_request_from_message(self, invocation, receiver, receiver_type='service'): sender, sender_type = invocation.get_message_sender() op = invocation.get_header_value('op', 'Unknown') ion_actor_id = invocation.get_header_value('ion-actor-id', 'anonymous') actor_roles = invocation.get_header_value('ion-actor-roles', {}) message_format = invocation.get_header_value('format', '') #log.debug("Checking XACML Request: receiver_type: %s, sender: %s, receiver:%s, op:%s, ion_actor_id:%s, ion_actor_roles:%s", receiver_type, sender, receiver, op, ion_actor_id, actor_roles) request = Request() subject = Subject() subject.attributes.append(self.create_string_attribute(SENDER_ID, sender)) subject.attributes.append(self.create_string_attribute(Identifiers.Subject.SUBJECT_ID, ion_actor_id)) #Get the Org name associated with the endpoint process endpoint_process = invocation.get_arg_value('process', None) if endpoint_process is not None and hasattr(endpoint_process,'org_governance_name'): org_governance_name = endpoint_process.org_governance_name else: org_governance_name = self.governance_controller.system_root_org_name #If this process is not associated wiht the root Org, then iterate over the roles associated with the user only for #the Org that this process is associated with otherwise include all roles and create attributes for each if org_governance_name == self.governance_controller.system_root_org_name: #log.debug("Including roles for all Orgs") #If the process Org name is the same for the System Root Org, then include all of them to be safe for org in actor_roles: self.create_org_role_attribute(actor_roles[org],subject) else: if actor_roles.has_key(org_governance_name): log.debug("Org Roles (%s): %s" , org_governance_name, ' '.join(actor_roles[org_governance_name])) self.create_org_role_attribute(actor_roles[org_governance_name],subject) #Handle the special case for the ION system actor if actor_roles.has_key(self.governance_controller.system_root_org_name): if ION_MANAGER in actor_roles[self.governance_controller.system_root_org_name]: log.debug("Including ION_MANAGER role") self.create_org_role_attribute([ION_MANAGER],subject) request.subjects.append(subject) resource = Resource() resource.attributes.append(self.create_string_attribute(Identifiers.Resource.RESOURCE_ID, receiver)) resource.attributes.append(self.create_string_attribute(RECEIVER_TYPE, receiver_type)) request.resources.append(resource) request.action = Action() request.action.attributes.append(self.create_string_attribute(Identifiers.Action.ACTION_ID, op)) #Check to see if there is a OperationVerb decorator specifying a Verb used with policy if is_ion_object(message_format): try: msg_class = message_classes[message_format] operation_verb = get_class_decorator_value(msg_class,'OperationVerb') if operation_verb is not None: request.action.attributes.append(self.create_string_attribute(ACTION_VERB, operation_verb)) except NotFound: pass #Create generic attributes for each of the primitive message parameter types to be available in XACML rules parameter_dict = {'message': invocation.message, 'headers': invocation.headers, 'annotations': invocation.message_annotations } if endpoint_process is not None: parameter_dict['process'] = endpoint_process request.action.attributes.append(self.create_dict_attribute(ACTION_PARAMETERS, parameter_dict)) return request
def _create_request_from_message(self, invocation, receiver, receiver_type=PROCTYPE_SERVICE): sender, sender_type = invocation.get_message_sender() op = invocation.get_header_value(MSG_HEADER_OP, 'Unknown') actor_id = invocation.get_header_value(MSG_HEADER_ACTOR, ANONYMOUS_ACTOR) user_context_id = invocation.get_header_value(MSG_HEADER_USER_CONTEXT_ID, "") user_context_differs = bool(actor_id and actor_id != ANONYMOUS_ACTOR and user_context_id and actor_id != user_context_id) actor_roles = invocation.get_header_value(MSG_HEADER_ROLES, {}) message_format = invocation.get_header_value(MSG_HEADER_FORMAT, '') # if receiver == "agpro_exchange": # print "### POLICY DECISION rty=%s recv=%s actor=%s context=%s differ:%s" % (receiver_type, receiver, actor_id, user_context_id, user_context_differs) # print " Headers: %s" % invocation.headers #log.debug("Checking XACML Request: receiver_type: %s, sender: %s, receiver:%s, op:%s, ion_actor_id:%s, ion_actor_roles:%s", receiver_type, sender, receiver, op, ion_actor_id, actor_roles) request = Request() subject = Subject() subject.attributes.append(self.create_string_attribute(SENDER_ID, sender)) subject.attributes.append(self.create_string_attribute(Identifiers.Subject.SUBJECT_ID, actor_id)) subject.attributes.append(self.create_string_attribute(USER_CONTEXT_ID, user_context_id)) subject.attributes.append(self.create_string_attribute(USER_CONTEXT_DIFFERS, str(user_context_differs))) # Get the Org name associated with the endpoint process endpoint_process = invocation.get_arg_value('process', None) if endpoint_process is not None and hasattr(endpoint_process, 'org_governance_name'): org_governance_name = endpoint_process.org_governance_name else: org_governance_name = self.governance_controller.system_root_org_name # If this process is not associated with the root Org, then iterate over the roles associated # with the user only for the Org that this process is associated with otherwise include all roles # and create attributes for each if org_governance_name == self.governance_controller.system_root_org_name: #log.debug("Including roles for all Orgs") # If the process Org name is the same for the System Root Org, then include all of them to be safe for org in actor_roles: self.create_org_role_attribute(actor_roles[org], subject) else: if org_governance_name in actor_roles: log.debug("Org Roles (%s): %s", org_governance_name, ' '.join(actor_roles[org_governance_name])) self.create_org_role_attribute(actor_roles[org_governance_name], subject) # Handle the special case for the ION system actor if self.governance_controller.system_root_org_name in actor_roles: if SUPERUSER_ROLE in actor_roles[self.governance_controller.system_root_org_name]: log.debug("Including SUPERUSER role") self.create_org_role_attribute([SUPERUSER_ROLE], subject) request.subjects.append(subject) resource = Resource() resource.attributes.append(self.create_string_attribute(Identifiers.Resource.RESOURCE_ID, receiver)) resource.attributes.append(self.create_string_attribute(RECEIVER_TYPE, receiver_type)) request.resources.append(resource) request.action = Action() request.action.attributes.append(self.create_string_attribute(Identifiers.Action.ACTION_ID, op)) # Check to see if there is a OperationVerb decorator specifying a Verb used with policy if is_ion_object(message_format): try: msg_class = message_classes[message_format] operation_verb = get_class_decorator_value(msg_class, DECORATOR_OP_VERB) if operation_verb is not None: request.action.attributes.append(self.create_string_attribute(ACTION_VERB, operation_verb)) except NotFound: pass # Create generic attributes for each of the primitive message parameter types to be available in XACML rules # and evaluation functions parameter_dict = {'message': invocation.message, 'headers': invocation.headers, 'annotations': invocation.message_annotations} if endpoint_process is not None: parameter_dict['process'] = endpoint_process request.action.attributes.append(self.create_dict_attribute(ACTION_PARAMETERS, parameter_dict)) return request
def get_object_schema(resource_type): """ This function returns the schema for a given resource_type @param resource_type name of an object type @return schema dict """ schema_info = dict() #Prepare the dict entry for schema information including all of the internal object types schema_info['schemas'] = dict() #ION Objects are not registered as UNICODE names ion_object_name = str(resource_type) ret_obj = IonObject(ion_object_name, {}) # If it's an op input param or response message object. # Walk param list instantiating any params that were marked None as default. if hasattr(ret_obj, "_svc_name"): schema = ret_obj._schema for field in ret_obj._schema: if schema[field]["default"] is None: try: value = IonObject(schema[field]["type"], {}) except NotFound: # TODO # Some other non-IonObject type. Just use None as default for now. value = None setattr(ret_obj, field, value) #Add schema information for sub object types if hasattr(ret_obj, '_schema'): schema_info['schemas'][ion_object_name] = ret_obj._schema for field in ret_obj._schema: obj_type = ret_obj._schema[field]['type'] #First look for ION objects if is_ion_object(obj_type): try: value = IonObject(obj_type, {}) schema_info['schemas'][obj_type] = value._schema except NotFound: pass #Next look for ION Enums elif ret_obj._schema[field].has_key('enum_type'): if isenum(ret_obj._schema[field]['enum_type']): value = IonObject(ret_obj._schema[field]['enum_type'], {}) schema_info['schemas'][ret_obj._schema[field] ['enum_type']] = value._str_map schema_info['object'] = ret_obj elif isenum(resource_type): schema_info['schemas'][resource_type] = {} schema_info['schemas'][resource_type] = ret_obj._str_map else: raise ('%s is not an ION Object', resource_type) return schema_info