def find_user_info_by_subject(self, subject=''): # Find UserCredentials objects, matches = self.clients.resource_registry.find_resources( RT.UserCredentials, None, subject, id_only=False) if not objects: raise NotFound("UserCredentials with subject %s does not exist" % subject) if len(objects) > 1: raise Inconsistent( "Multiple UserCredentials with subject %s exist" % subject) user_credentials_id = objects[0]._id subjects, assocs = self.clients.resource_registry.find_subjects( RT.ActorIdentity, PRED.hasCredentials, user_credentials_id) if not subjects or len(subjects) == 0: raise NotFound( "ActorIdentity to UserCredentials association for subject %s does not exist" % subject) if len(subjects) > 1: raise Inconsistent( "Multiple ActorIdentity to UserCredentials associations for subject %s exist" % subject) actor_identity_id = subjects[0]._id # Look up UserInfo via association with ActorIdentity objects, assocs = self.clients.resource_registry.find_objects( actor_identity_id, PRED.hasInfo, RT.UserInfo) if not objects: raise NotFound("UserInfo for subject %s does not exist" % subject) if len(objects) > 1: raise Inconsistent("Multiple UserInfos for subject %s exist" % subject) user_info = objects[0] return user_info
def delete_user_info(self, user_info_id='', actor_identity_id=''): # Read UserInfo user_info = self.clients.resource_registry.read(user_info_id) if not user_info: raise NotFound("UserInfo %s does not exist" % user_info_id) # Find and break association with ActorIdentity if not actor_identity_id: subjects, assocs = self.clients.resource_registry.find_subjects( RT.ActorIdentity, PRED.hasInfo, user_info_id) if not assocs: raise NotFound( "ActorIdentity to UserInfo association for user info id %s does not exist" % user_info_id) actor_identity_id = subjects[0]._id assocs = self.clients.resource_registry.find_associations( actor_identity_id, PRED.hasInfo, user_info_id) if not assocs: raise NotFound( "ActorIdentity to UserInfo association for user info id %s does not exist" % user_info_id) association_id = assocs[0]._id self.clients.resource_registry.delete_association(association_id) # Delete the UserInfo self.clients.resource_registry.delete(user_info_id)
def get_service_spec(self, service_name=None, spec_name=None): try: if not self._swagger_gen: raise NotFound("Spec not available") if spec_name != "swagger.json": raise NotFound("Unknown spec format") swagger_json = self._swagger_gen.get_spec(service_name) resp = flask.make_response(flask.jsonify(swagger_json)) self._add_cors_headers(resp) return resp except Exception as ex: return self.gateway_error_response(ex)
def undeclare_exchange_name(self, canonical_name='', exchange_space_id=''): """Remove an exhange name resource """ exchange_space_obj = self._validate_resource_id("exchange_space_id", exchange_space_id, RT.ExchangeSpace, optional=True) # TODO: currently we are using the exchange_name's id as the canonical name and exchange_space_id is unused? exchange_name = self.rr.read(canonical_name) if not exchange_name: raise NotFound("ExchangeName with id %s does not exist" % canonical_name) exchange_name_id = exchange_name._id # yes, this should be same, but let's make it look cleaner # Get associated XS first exchange_space_list, assocs = self.rr.find_subjects(RT.ExchangeSpace, PRED.hasExchangeName, exchange_name_id) if len(exchange_space_list) != 1: log.warn("ExchangeName %s has no associated Exchange Space" % exchange_name_id) exchange_space = exchange_space_list[0] if exchange_space_list else None # Remove association between itself and XS for assoc in assocs: self.rr.delete_association(assoc._id) # Remove XN self.rr.delete(exchange_name_id) # Call container API if exchange_space: xs = self.container.ex_manager.create_xs(exchange_space.name, declare=False) xn = self.container.ex_manager._create_xn(exchange_name.xn_type, exchange_name.name, xs, declare=False) self.container.ex_manager.delete_xn(xn)
def initiate_account_merge(self, merge_user_email=''): ''' Initiate merging two accounts @throws BadRequest: A parameter is missing @throws NotFound: Merge user email address is not found @retval token_string: Token string that will be email to the user for verification ''' if not merge_user_email: raise BadRequest( "initiate_account_merge: merge_user_email must be set") # Find UserInfo of the account that needs to be merged into merge_user_info = self.find_user_info_by_email(merge_user_email) if not merge_user_info: raise NotFound("initiate_account_merge: email address not found") # Validate current user and the merger user are two different accounts if self.find_user_info_by_id( self._get_current_user_id())._id == merge_user_info._id: raise BadRequest( "initiate_account_merge: current and merge accounts are the same" ) token_str = self._generate_token() expire_time = calendar.timegm( (datetime.utcnow() + timedelta(days=2)).timetuple()) # Set token expire time token = SecurityToken(token_string=token_str, expires=expire_time, status="OPEN", merge_email=merge_user_email) self._update_user_info_token(token) return token_str
def cancel_member_enrollment(self, org_id="", actor_id=""): """Cancels the membership of a specific actor actor within the specified Org. Once canceled, the actor will no longer have access to the resource of that Org. """ org_obj = self._validate_resource_id("org_id", org_id, RT.Org) actor_obj = self._validate_resource_id("actor_id", actor_id, RT.ActorIdentity) if org_obj.name == self._get_root_org_name(): raise BadRequest( "A request to cancel enrollment in the root ION Org is not allowed" ) # First remove all associations to any roles role_list = self.list_actor_roles(actor_id, org_id) for user_role in role_list: self._delete_role_association(org_obj, actor_obj, user_role) # Finally remove the association to the Org aid = self.rr.get_association(org_obj, PRED.hasMember, actor_obj) if not aid: raise NotFound( "The membership association between the specified actor and Org is not found" ) self.rr.delete_association(aid) self.event_pub.publish_event( event_type=OT.OrgMembershipCancelledEvent, origin=org_id, origin_type="Org", description="The member has cancelled enrollment in the Org", actor_id=actor_id, org_name=org_obj.name)
def test_read_user_info_not_found(self): self.mock_read.side_effect = NotFound("bad") # TEST: Execute the service operation call with self.assertRaises(NotFound) as cm: self.identity_management_service.read_user_info('bad') self.mock_read.assert_called_once_with('bad', '')
def find_user_info_by_id(self, actor_id=''): # Look up UserInfo via association with ActorIdentity objects, assocs = self.clients.resource_registry.find_objects( actor_id, PRED.hasInfo, RT.UserInfo) if not objects: raise NotFound("UserInfo for user id %s does not exist" % actor_id) user_info = objects[0] return user_info
def find_user_info_by_name(self, name=''): objects, matches = self.clients.resource_registry.find_resources( RT.UserInfo, None, name, id_only=False) if not objects: raise NotFound("UserInfo with name %s does not exist" % name) if len(objects) > 1: raise Inconsistent("Multiple UserInfo objects with name %s exist" % name) return objects[0]
def find_actor_identity_by_username(self, username=''): if not username: raise BadRequest("Invalid username") res_ids, _ = self.rr.find_resources_ext(alt_id_ns="UNAME", alt_id=username, id_only=True) if not res_ids: raise NotFound("No actor found with username") return res_ids[0]
def query_view(self, view_id='', view_name='', ext_query=None, id_only=True, search_args=None): """Execute an existing query as defined within a View resource, providing additional arguments for parameterized values. If ext_query is provided, it will be combined with the query defined by the View. Search_args may contain parameterized values. Returns a list of resource or event objects or their IDs only. """ if not view_id and not view_name: raise BadRequest("Must provide argument view_id or view_name") if view_id and view_name: raise BadRequest("Cannot provide both arguments view_id and view_name") if view_id: view_obj = self.clients.resource_registry.read(view_id) else: view_obj = self.ds_discovery.get_builtin_view(view_name) if not view_obj: view_objs, _ = self.clients.resource_registry.find_resources(restype=RT.View, name=view_name) if not view_objs: raise NotFound("View with name '%s' not found" % view_name) view_obj = view_objs[0] if view_obj.type_ != RT.View: raise BadRequest("Argument view_id is not a View resource") view_query = view_obj.view_definition if not QUERY_EXP_KEY in view_query: raise BadRequest("Unknown View query format") # Get default query params and override them with provided args param_defaults = {param.name: param.default for param in view_obj.view_parameters} query_params = param_defaults if view_obj.param_values: query_params.update(view_obj.param_values) if search_args: query_params.update(search_args) # Merge ext_query into query if ext_query: if ext_query["where"] and view_query["where"]: view_query["where"] = [DQ.EXP_AND, [view_query["where"], ext_query["where"]]] else: view_query["where"] = view_query["where"] or ext_query["where"] if ext_query["order_by"]: # Override ordering if present view_query["where"] = ext_query["order_by"] # Other query settings view_qargs = view_query["query_args"] ext_qargs = ext_query["query_args"] view_qargs["id_only"] = ext_qargs.get("id_only", view_qargs["id_only"]) view_qargs["limit"] = ext_qargs.get("limit", view_qargs["limit"]) view_qargs["skip"] = ext_qargs.get("skip", view_qargs["skip"]) return self._discovery_request(view_query, id_only=id_only, search_args=search_args, query_params=query_params)
def delete_user_credential_association(self, user_credential_id, actor_identity_id): association_id = self.clients.resource_registry.find_associations( actor_identity_id, PRED.hasCredentials, user_credential_id, id_only=True) if not association_id: raise NotFound( "complete_account_merge: Association between UserCredentials and ActorIdentity not found. ActorIdentity ID %s, UserCredentials ID: %s " % actor_identity_id % user_credential_id) self.clients.resource_registry.delete_association(association_id[0])
def check_actor_credentials(self, username='', password=''): if not username: raise BadRequest("Invalid argument username") if not password: raise BadRequest("Invalid argument password") actor_id = self.find_actor_identity_by_username(username) actor_obj = self.read_actor_identity(actor_id) try: if actor_obj.auth_status != AuthStatusEnum.ENABLED: raise NotFound("identity not enabled") cred_obj = None for cred in actor_obj.credentials: if cred.username == username: cred_obj = cred break if bcrypt.hashpw(password, cred_obj.password_salt) != cred_obj.password_hash: # Failed login if password: # Only record fail if password is non-empty and wrong actor_obj.auth_fail_count += 1 actor_obj.auth_ts_last_fail = get_ion_ts() max_fail_cnt = IdentityUtils.get_auth_fail_lock_count() if actor_obj.auth_fail_count > max_fail_cnt: actor_obj.auth_status = AuthStatusEnum.LOCKED raise NotFound("Invalid password") # Success actor_obj.auth_count += 1 actor_obj.auth_fail_count = 0 actor_obj.auth_ts_last = get_ion_ts() return actor_obj._id finally: # Lower level RR call to avoid credentials clearing self.rr.update(actor_obj)
def _find_org_role(self, org_id="", role_name=""): if not org_id: raise BadRequest("The org_id argument is missing") if not role_name: raise BadRequest("The role_name argument is missing") # Iterating (vs. query) is just fine, because the number of org roles is sufficiently small org_roles = self._list_org_roles(org_id) for role in org_roles: if role.governance_name == role_name: return role raise NotFound("Role %s not found in Org id=%s" % (role_name, org_id))
def find_actor_identity_by_name(self, name=''): """Return the ActorIdentity object whose name attribute matches the passed value. """ objects, _ = self.rr.find_resources(RT.ActorIdentity, None, name, id_only=False) if not objects: raise NotFound("ActorIdentity with name %s does not exist" % name) if len(objects) > 1: raise Inconsistent( "Multiple ActorIdentity objects with name %s exist" % name) return objects[0]
def unregister_user_credentials(self, actor_id='', credentials_name=''): # Read UserCredentials objects, matches = self.clients.resource_registry.find_resources( RT.UserCredentials, None, credentials_name, id_only=False) if not objects or len(objects) == 0: raise NotFound("UserCredentials %s does not exist" % credentials_name) if len(objects) > 1: raise Conflict( "Multiple UserCredentials objects found for subject %s" % credentials_name) user_credentials_id = objects[0]._id # Find and break association with ActorIdentity assocs = self.clients.resource_registry.find_associations( actor_id, PRED.hasCredentials, user_credentials_id) if not assocs or len(assocs) == 0: raise NotFound( "ActorIdentity to UserCredentials association for user id %s to credential %s does not exist" % (actor_id, credentials_name)) association_id = assocs[0]._id self.clients.resource_registry.delete_association(association_id) # Delete the UserCredentials self.clients.resource_registry.delete(user_credentials_id)
def find_org(self, name=""): """Finds an Org object with the specified name. Defaults to the root ION object. Throws a NotFound exception if the object does not exist. """ # Default to the root ION Org if not specified if not name: name = self._get_root_org_name() res_list, _ = self.rr.find_resources(restype=RT.Org, name=name, id_only=False) if not res_list: raise NotFound("The Org with name %s does not exist" % name) return res_list[0]
def find_actor_identity_by_name(self, name=''): """Return the ActorIdentity object whose name attribute matches the passed value. @param name str @retval user_info ActorIdentity @throws NotFound failed to find ActorIdentity @throws Inconsistent Multiple ActorIdentity objects matched name """ objects, matches = self.clients.resource_registry.find_resources( RT.ActorIdentity, None, name, id_only=False) if not objects: raise NotFound("ActorIdentity with name %s does not exist" % name) if len(objects) > 1: raise Inconsistent( "Multiple ActorIdentity objects with name %s exist" % name) return objects[0]
def unaffiliate_org(self, org_id="", affiliate_org_id=""): """Removes an association between multiple Orgs as an affiliation. Throws a NotFound exception if neither id is found. """ org_obj = self._validate_resource_id("org_id", org_id, RT.Org) affiliate_org_obj = self._validate_resource_id("affiliate_org_id", affiliate_org_id, RT.Org) aid = self.rr.get_association(org_obj, PRED.hasAffiliation, affiliate_org_obj) if not aid: raise NotFound( "The affiliation association between the specified Orgs is not found" ) self.rr.delete_association(aid)
def _validate_token_string(self, token_string, user_info): # Find the token from the UserInfo token_obj = [ token for token in user_info.tokens if token.token_string == token_string ] if not token_obj or not token_obj[0].merge_email or not token_obj[ 0].expires: raise NotFound("_validate_token: Token data not found") token_obj = token_obj[0] # Validate the expiration time and token status current_time = calendar.timegm((datetime.utcnow()).timetuple()) if current_time > token_obj.expires or "OPEN" != token_obj.status: raise BadRequest( "_validate_token: access token expired or token status is invalid" ) return token_obj
def _delete_role_association(self, org, actor, user_role): aid = self.rr.get_association(actor, PRED.hasRole, user_role) if not aid: raise NotFound( "ActorIdentity %s to UserRole %s association not found" % (actor._id, user_role._id)) self.rr.delete_association(aid) self.event_pub.publish_event(event_type=OT.UserRoleRevokedEvent, origin=org._id, origin_type="Org", sub_type=user_role.governance_name, description="Revoked the %s role" % user_role.name, actor_id=actor._id, role_name=user_role.governance_name, org_name=org.name)
def __init__(self, resource_id, *args, **kwargs): """ Resource agent client constructor. @param resource_id The ID this service represents. @param name Use this kwarg to set the target exchange name (= agent process id or service name) (service or process). """ # Assert and set the resource ID. if not resource_id: raise BadRequest("resource_id must be set for an agent") self.resource_id = resource_id self.agent_process_id = None self.agent_dir_entry = None # Set the name, retrieve as proc ID if not set by user. if 'name' not in kwargs: self.agent_process_id = self._get_agent_process_id( self.resource_id, client_instance=self) if self.agent_process_id: log.debug("Use agent process %s for resource_id=%s" % (self.agent_process_id, self.resource_id)) else: log.debug("No agent process found for resource_id %s" % self.resource_id) raise NotFound("No agent process found for resource_id %s" % self.resource_id) else: self.agent_process_id = kwargs.pop("name") # transpose name -> to_name to make underlying layer happy #kwargs["to_name"] = self.agent_process_id kwargs["to_name"] = resource_id # HACK to allow use of this client without process if "process" not in kwargs: log.warn( "Using FakeProcess to allow agent client without process arg") kwargs["process"] = StreamingAgentClient.FakeAgentProcess() kwargs["declare_name"] = False # Superclass constructor. StreamingAgentProcessClient.__init__(self, *args, **kwargs)
def unregister_credentials(self, actor_id='', credentials_name=''): actor_obj = self._validate_resource_id("actor_id", actor_id, RT.ActorIdentity) if not credentials_name: raise BadRequest("Invalid credentials_name") found_cred = -1 for i, cred in enumerate(actor_obj.credentials): if cred.username == credentials_name: found_cred = i break if found_cred != -1: del actor_obj.credentials[found_cred] else: raise NotFound("Credentials not found") actor_obj.alt_ids.remove("UNAME:" + credentials_name) # Lower level RR call to avoid credentials clearing self.rr.update(actor_obj)
def unshare_resource(self, org_id="", resource_id=""): """Unshare a resource with the specified Org. Once unshared, the resource will be removed from the directory of available resources within the Org. """ org_obj = self._validate_resource_id("org_id", org_id, RT.Org) resource_obj = self._validate_resource_id("resource_id", resource_id) aid = self.rr.get_association(org_obj, PRED.hasResource, resource_obj) if not aid: raise NotFound("Association between Resource and Org not found") self.rr.delete_association(aid) self.event_pub.publish_event( event_type=OT.ResourceUnsharedEvent, origin=org_obj._id, origin_type="Org", sub_type=resource_obj.type_, description="The resource has been unshared in the Org", resource_id=resource_id, org_name=org_obj.name)
def get_user_info_extension(self, user_info_id='', org_id=''): """Returns an UserInfoExtension object containing additional related information @param user_info_id str @param org_id str - An optional org id that the user is interested in filtering against. @retval user_info UserInfoExtension @throws BadRequest A parameter is missing @throws NotFound An object with the specified actor_id does not exist """ if not user_info_id: raise BadRequest("The user_info_id parameter is empty") #THis is a hack to get the UI going. It would be preferable to get the actor id from the extended resource #container below, but their would need to be a guarantee of order of field processing in order #to ensure that the actor identity has been found BEFORE the negotiation methods are called - and probably #some elegant way to indicate the field and sub field; ie actor_identity._id actors, _ = self.clients.resource_registry.find_subjects( subject_type=RT.ActorIdentity, predicate=PRED.hasInfo, object=user_info_id, id_only=True) actor_id = actors[0] if len(actors) > 0 else '' extended_resource_handler = ExtendedResourceContainer(self) extended_user = extended_resource_handler.create_extended_resource_container( extended_resource_type=OT.UserInfoExtension, resource_id=user_info_id, computed_resource_type=OT.ComputedAttributes, user_id=user_info_id, org_id=org_id, actor_id=actor_id) #If the org_id is not provided then skip looking for Org related roles. if extended_user: #Did not setup a dependency to org_management service to avoid a potential circular bootstrap issue # since this method should never be called until the system is fully running try: org_client = OrgManagementServiceProcessClient(process=self) roles = org_client.find_all_roles_by_user( extended_user.actor_identity._id) extended_user.roles = list() for org_name in roles: for role in roles[org_name]: flattened_role = copy.copy(role.__dict__) del flattened_role[ 'type_'] #Have to do this to appease the message validators for ION objects flattened_role[ 'org_name'] = org_name #Nothing like forcing a value into the dict to appease the UI code extended_user.roles.append(flattened_role) except Exception, e: raise NotFound( 'Could not retrieve UserRoles for User Info id: %s - %s' % (user_info_id, e.message)) #filter notification requests that are retired extended_user.subscriptions = [ nr for nr in extended_user.subscriptions if nr.temporal_bounds.end_datetime == '' ] #filter owned resources that are retired nr_removed = [] for rsrc in extended_user.owned_resources: #remove all the Notifications if rsrc.type_ != OT.NotificationRequest: nr_removed.append(rsrc) extended_user.owned_resources = [ rsrc for rsrc in nr_removed if rsrc.lcstate != 'DELETED' ] #now append the active NotificationRequests extended_user.owned_resources.extend(extended_user.subscriptions)
def test_delete_actor_identity_not_found(self): self.mock_delete.side_effect = NotFound("bad") # TEST: Execute the service operation call with self.assertRaises(NotFound) as cm: self.identity_management_service.delete_actor_identity('bad')
def complete_account_merge(self, token_string=""): ''' Completes merging the two accounts after verifying the token string @throws BadRequest A parameter is missing @throws NotFound Merge data not found ''' log.debug("complete_account_merge with token string: %s" % token_string) if not token_string: raise BadRequest("complete_account_merge: token_str must be set") # Get current UserInfo current_user_id = self._get_current_user_id() current_user_info = self.find_user_info_by_id(current_user_id) # Find all the necessary data of the merge account token_obj = self._validate_token_string(token_string, current_user_info) merge_user_info_obj = self.find_user_info_by_email( token_obj.merge_email) # Find UserInfo of the merge account merge_user_info_id = merge_user_info_obj._id subjects, associations = self.clients.resource_registry.find_subjects( RT.ActorIdentity, PRED.hasInfo, merge_user_info_id) # Find ActorIdentity of the merge account if not associations: raise NotFound( "complete_account_merge: ActorIdentity and UserInfo association does not exist. UserInfo ID: %s" % merge_user_info_id) merge_actor_identity_id = subjects[0]._id # Find UserCredentials of the merge account merge_user_credential_id, matches = self.clients.resource_registry.find_objects( merge_actor_identity_id, PRED.hasCredentials, RT.UserCredentials, id_only=True) if not merge_user_credential_id: raise NotFound( "complete_account_merge: UserCredentials and ActorIdentity association does not exist.ActorIdentity ID: %s" % merge_actor_identity_id) merge_user_credential_id = merge_user_credential_id[0] # Remove association bewteeen ActorIdentity and UserCreentials log.debug( "complete_account_merge: merge account data: merge_user_info_id: %s merge_user_credential_id:%s merge_actor_identity_id:%s" % (merge_user_info_id, merge_user_credential_id, merge_actor_identity_id)) self.delete_user_credential_association(merge_user_credential_id, merge_actor_identity_id) # Remove the merge account ActorIdentity and merge UserInfo. self.delete_user_info(merge_user_info_id, merge_actor_identity_id) self.delete_actor_identity(merge_actor_identity_id) # Create association between the current user ActorIdentity and the merge user UserCredentials self.clients.resource_registry.create_association( current_user_id, PRED.hasCredentials, merge_user_credential_id) # Update the token status token_obj.status = "VERIFIED" self.update_user_info(current_user_info) log.debug( "complete_account_merge: account merge completed from %s to %s" % (merge_actor_identity_id, current_user_id)) return True