def send_system_notification(user_id, category, message, configuration): """Send system notification to *user_id* through grid_notify""" logger = configuration.logger if not configuration.site_enable_notify: logger.warning("System notify helper is disabled in configuration!") return False if not user_id: logger.error("Invalid user_id: %s" % user_id) return False client_id = expand_openid_alias(user_id, configuration) if not client_id or not extract_field(client_id, 'email'): logger.error("send_system_notification: Invalid user_id: %s" % user_id) return False if not isinstance(category, list): logger.error("send_system_notification: category must be a list") return False notification = { 'category': category, 'user_id': user_id, 'message': message, 'timestamp': time.time(), } pickled_notification = pickle.dumps(notification) return send_message_to_grid_notify(pickled_notification, configuration.logger, configuration)
def recv_notification(configuration, path): """Read notification event from file""" logger = configuration.logger # logger.debug("read_notification: %s" % file) status = True new_notification = unpickle(path, logger) if not new_notification: logger.error("Failed to unpickle: %s" % path) return False user_id = new_notification.get('user_id', '') # logger.debug("Received user_id: '%s'" % user_id) if not user_id: status = False logger.error("Missing user_id in notification: %s" % path) else: client_id = expand_openid_alias(user_id, configuration) # logger.debug("resolved client_id: '%s'" % client_id) if not client_id or not extract_field(client_id, 'email'): status = False logger.error("Failed to resolve client_id from user_id: '%s'" % user_id) if status: category = new_notification.get('category', []) # logger.debug("Received category: %s" % category) if not isinstance(category, list): status = False logger.error("Received category: %s must be a list" % category) if status: logger.info("Received event: %s, from: '%s'" % (category, client_id)) new_timestamp = new_notification.get('timestamp') message = new_notification.get('message', '') # logger.debug("Received message: %s" % message) client_dict = received_notifications.get(client_id, {}) if not client_dict: received_notifications[client_id] = client_dict files_list = client_dict.get('files', []) if not files_list: client_dict['files'] = files_list if path in files_list: logger.warning("Skipping prevoursly received notification: '%s'" % path) else: files_list.append(path) client_dict['timestamp'] = min( client_dict.get('timestamp', sys.maxint), new_timestamp) messages_dict = client_dict.get('messages', {}) if not messages_dict: client_dict['messages'] = messages_dict header = " ".join(category) if not header: header = '* UNKNOWN *' body_dict = messages_dict.get(header, {}) if not body_dict: messages_dict[header] = body_dict message_count = body_dict.get(message, 0) body_dict[message] = message_count + 1 return status
def check_twofactor_session(configuration, username, addr, proto): """Run any required 2-factor authentication checks for given username and proto. First check if site enables twofactor at all and in that case if the user actually requires it for given proto. Finally check the validity of the corresponding 2FA session file if so. """ logger = configuration.logger if not configuration.site_enable_twofactor: logger.debug("twofactor support disabled site-wide") return True client_id = expand_openid_alias(username, configuration) if configuration.site_enable_gdp: client_id = get_client_id_from_project_client_id( configuration, client_id) twofactor_dict = load_twofactor(client_id, configuration, allow_missing=True) # logger.debug("found twofactor_dict for %s : %s" % # (client_id, twofactor_dict)) if not twofactor_dict: # logger.debug("fall back to twofactor defaults for %s" % client_id) twofactor_dict = dict([ (i, j['Value']) for (i, j) in twofactor_defaults(configuration).items() ]) if proto in ('ssh-pw', 'sftp-pw', 'scp-pw', 'rsync-pw'): proto_field = 'SFTP_PASSWORD' elif proto in ('ssh-key', 'sftp-key', 'scp-key', 'rsync-key'): proto_field = 'SFTP_KEY' elif proto in ('dav', 'davs'): proto_field = 'WEBDAVS' elif proto in ('ftp', 'ftps'): proto_field = 'FTPS' else: logger.error("Invalid protocol: %s" % proto) return False proto_field += "_TWOFACTOR" if not twofactor_dict.get(proto_field, False): if configuration.site_enable_gdp: # GDP require twofactor settings for all protocols msg = "Missing GDP twofactor settings for user: %s, protocol: %s" \ % (client_id, proto) logger.error(msg) return False else: # logger.debug("user %s does not require twofactor for %s" \ # % (client_id, proto)) return True # logger.debug("check required 2FA session in %s for %s" % (proto, username)) return valid_twofactor_session(configuration, client_id, addr)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] output_objects.append({'object_type': 'header', 'text' : 'Add %s Member' % configuration.site_vgrid_label}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() cert_id = accepted['cert_id'][-1].strip() cert_dir = client_id_dir(cert_id) # Allow openid alias as subject if openid with alias is enabled if configuration.user_openid_providers and configuration.user_openid_alias: cert_id = expand_openid_alias(cert_id, configuration) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'member', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text' : msg}) return (output_objects, returnvalues.CLIENT_ERROR) # don't add if already an owner if vgrid_is_owner(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text' : '%s is already an owner of %s or a parent %s.' % (cert_id, vgrid_name, configuration.site_vgrid_label)}) return (output_objects, returnvalues.CLIENT_ERROR) # don't add if already a member if vgrid_is_member(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text' : '''%s is already a member of %s or a parent %s. Please remove the person first and then try this operation again.''' % \ (cert_id, vgrid_name, configuration.site_vgrid_label) }) return (output_objects, returnvalues.CLIENT_ERROR) # owner or member of subvgrid? (status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration) if not status: output_objects.append({'object_type': 'error_text', 'text' : 'Error getting list of sub%ss: %s' % (configuration.site_vgrid_label, subvgrids)}) return (output_objects, returnvalues.SYSTEM_ERROR) # TODO: we DO allow ownership of sub vgrids with parent membership so we # should support the (cumbersome) relinking of vgrid shares here. Leave it # to user to do it manually for now with temporary removal of ownership for subvgrid in subvgrids: if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text' : """%(cert_id)s is already an owner of a sub-%(_label)s ('%(subvgrid)s'). While we DO support members being owners of sub-%(_label)ss, we do not support adding parent %(_label)s members at the moment. Please (temporarily) remove the person as owner of all sub-%(_label)ss first and then try this operation again.""" % {'cert_id': cert_id, 'subvgrid': subvgrid, '_label': configuration.site_vgrid_label}}) return (output_objects, returnvalues.CLIENT_ERROR) if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text' : """%s is already a member of a sub-%s ('%s'). Please remove the person first and then try this operation again.""" % \ (cert_id, configuration.site_vgrid_label, subvgrid)}) return (output_objects, returnvalues.CLIENT_ERROR) # getting here means cert_id is neither owner or member of any parent or # sub-vgrids. # Please note that base_dir must end in slash to avoid access to other # vgrid dirs when own name is a prefix of another name base_dir = os.path.abspath(os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep # make sure all dirs can be created (that a file or directory with the same # name do not exist prior to adding the member) if os.path.exists(user_dir + vgrid_name): output_objects.append( {'object_type': 'error_text', 'text' : '''Could not add member, a file or directory in the home directory called %s exists! (%s)''' % (vgrid_name, user_dir + vgrid_name)}) return (output_objects, returnvalues.CLIENT_ERROR) # Add (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name, [cert_id]) if not add_status: output_objects.append({'object_type': 'error_text', 'text' : add_msg}) return (output_objects, returnvalues.SYSTEM_ERROR) vgrid_name_parts = vgrid_name.split('/') is_subvgrid = len(vgrid_name_parts) > 1 if is_subvgrid: try: # vgrid_name = IMADA/STUD/BACH # vgrid_name_last_fragment = BACH vgrid_name_last_fragment = \ vgrid_name_parts[len(vgrid_name_parts) - 1].strip() # vgrid_name_without_last_fragment = IMADA/STUD/ vgrid_name_without_last_fragment = \ ('/'.join(vgrid_name_parts[0:len(vgrid_name_parts) - 1]) + os.sep).strip() # create dirs if they do not exist dir1 = user_dir + vgrid_name_without_last_fragment if not os.path.isdir(dir1): os.makedirs(dir1) except Exception, exc: # out of range? should not be possible due to is_subvgrid check output_objects.append( {'object_type': 'error_text', 'text' : ('Could not create needed dirs on %s server! %s' % (configuration.short_title, exc))}) logger.error('%s when looking for dir %s.' % (exc, dir1)) return (output_objects, returnvalues.SYSTEM_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] output_objects.append({'object_type': 'header', 'text' : 'Add %s Owner' % configuration.site_vgrid_label}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() cert_id = accepted['cert_id'][-1].strip() cert_dir = client_id_dir(cert_id) # inherited vgrid membership inherit_vgrid_member = False # Allow openid alias as subject if openid with alias is enabled if configuration.user_openid_providers and configuration.user_openid_alias: cert_id = expand_openid_alias(cert_id, configuration) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'owner', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text' : msg}) return (output_objects, returnvalues.CLIENT_ERROR) # don't add if already an owner if vgrid_is_owner(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text' : '%s is already an owner of %s or a parent %s.' % (cert_id, vgrid_name, configuration.site_vgrid_label)}) return (output_objects, returnvalues.CLIENT_ERROR) # don't add if already a direct member if vgrid_is_member(vgrid_name, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text' : '%s is already a member of %s - please remove first.' % (cert_id, vgrid_name)}) return (output_objects, returnvalues.CLIENT_ERROR) # owner of subvgrid? (status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration) if not status: output_objects.append({'object_type': 'error_text', 'text' : 'Error getting list of sub%ss: %s' % (configuration.site_vgrid_label, subvgrids)}) return (output_objects, returnvalues.SYSTEM_ERROR) for subvgrid in subvgrids: if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text' : """%s is already an owner of a sub-%s ('%s'). Please remove the person first and then try this operation again.""" % \ (cert_id, configuration.site_vgrid_label, subvgrid)}) return (output_objects, returnvalues.CLIENT_ERROR) if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text' : """%s is already a member of a sub-%s ('%s'). Please remove the person first and then try this operation again.""" % \ (cert_id, configuration.site_vgrid_label, subvgrid)}) return (output_objects, returnvalues.CLIENT_ERROR) # we DO allow ownership if member of parent vgrid - only handle with care if vgrid_is_member(vgrid_name, cert_id, configuration): # list is in top-down order parent_vgrids = vgrid_list_parents(vgrid_name, configuration) inherit_vgrid_member = vgrid_name for parent in parent_vgrids: if vgrid_is_member(parent, cert_id, configuration, recursive=False): inherit_vgrid_member = parent break output_objects.append( {'object_type': 'text', 'text' : '''NOTE: %s is already a member of parent %s %s.''' % \ (cert_id, configuration.site_vgrid_label, inherit_vgrid_member) }) # getting here means cert_id is not owner of any parent or child vgrids. # may still be member of a parent grid but not a child vgrid. public_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name)) + os.sep private_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name)) + os.sep # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep user_public_base = os.path.abspath(os.path.join(user_dir, 'public_base')) + os.sep user_private_base = os.path.abspath(os.path.join(user_dir, 'private_base')) + os.sep # make sure all dirs can be created (that a file or directory with the same # name do not exist prior to adding the owner) if os.path.exists(user_public_base + vgrid_name): output_objects.append( {'object_type': 'error_text', 'text' : '''Could not add owner, a file or directory in public_base exists with the same name! %s''' % user_dir + vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) if os.path.exists(user_private_base + vgrid_name): output_objects.append( {'object_type': 'error_text', 'text' : '''Could not add owner, a file or directory in private_base exists with the same name!'''}) return (output_objects, returnvalues.CLIENT_ERROR) # vgrid share already exists if user is a member of parent vgrid if not inherit_vgrid_member and os.path.exists(user_dir + vgrid_name): output_objects.append( {'object_type': 'error_text', 'text' : '''Could not add owner, a file or directory in the home directory exists with the same name!'''}) return (output_objects, returnvalues.CLIENT_ERROR) # Add (add_status, add_msg) = vgrid_add_owners(configuration, vgrid_name, [cert_id]) if not add_status: output_objects.append({'object_type': 'error_text', 'text' : add_msg}) return (output_objects, returnvalues.SYSTEM_ERROR) vgrid_name_parts = vgrid_name.split('/') is_subvgrid = len(vgrid_name_parts) > 1 # create public_base in cert_ids home dir if it does not exists try: os.mkdir(user_public_base) except Exception, exc: pass
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Add %s Member" % label output_objects.append({'object_type': 'header', 'text': 'Add %s Member(s)' % label}) status = returnvalues.OK (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() cert_id_list = accepted['cert_id'] request_name = unhexlify(accepted['request_name'][-1]) rank_list = accepted['rank'] + ['' for _ in cert_id_list] if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append( {'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append( {'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label}) return (output_objects, returnvalues.CLIENT_ERROR) # make sure vgrid settings allow this owner to edit members (allow_status, allow_msg) = allow_members_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({'object_type': 'error_text', 'text': allow_msg}) return (output_objects, returnvalues.CLIENT_ERROR) cert_id_added = [] for (cert_id, rank_str) in zip(cert_id_list, rank_list): cert_id = cert_id.strip() cert_dir = client_id_dir(cert_id) try: rank = int(rank_str) except ValueError: rank = None # Allow openid alias as subject if openid with alias is enabled if configuration.user_openid_providers and configuration.user_openid_alias: cert_id = expand_openid_alias(cert_id, configuration) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'member', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) status = returnvalues.CLIENT_ERROR continue # don't add if already an owner if vgrid_is_owner(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text': '%s is already an owner of %s or a parent %s.' % (cert_id, vgrid_name, label)}) status = returnvalues.CLIENT_ERROR continue # don't add if already a member unless rank is given if rank is None and vgrid_is_member(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text': '''%s is already a member of %s or a parent %s. Please remove the person first and then try this operation again.''' % (cert_id, vgrid_name, label) }) status = returnvalues.CLIENT_ERROR continue # owner or member of subvgrid? (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration) if not list_status: output_objects.append({'object_type': 'error_text', 'text': 'Error getting list of sub%ss: %s' % (label, subvgrids)}) status = returnvalues.SYSTEM_ERROR continue # TODO: we DO allow ownership of sub vgrids with parent membership so we # should support the (cumbersome) relinking of vgrid shares here. Leave it # to user to do it manually for now with temporary removal of ownership skip_entity = False for subvgrid in subvgrids: if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text': """%(cert_id)s is already an owner of a sub-%(vgrid_label)s ('%(subvgrid)s'). While we DO support members being owners of sub-%(vgrid_label)ss, we do not support adding parent %(vgrid_label)s members at the moment. Please (temporarily) remove the person as owner of all sub-%(vgrid_label)ss first and then try this operation again.""" % {'cert_id': cert_id, 'subvgrid': subvgrid, 'vgrid_label': label}}) status = returnvalues.CLIENT_ERROR skip_entity = True break if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text': """%s is already a member of a sub-%s ('%s'). Please remove the person first and then try this operation again.""" % (cert_id, label, subvgrid)}) status = returnvalues.CLIENT_ERROR skip_entity = True break if skip_entity: continue # Check if only rank change was requested and apply if so if rank is not None: (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name, [cert_id], rank=rank) if not add_status: output_objects.append( {'object_type': 'error_text', 'text': add_msg}) status = returnvalues.SYSTEM_ERROR else: output_objects.append({'object_type': 'text', 'text': 'changed %s to member %d' % (cert_id, rank)}) # No further action after rank change as everything else exists continue # Getting here means cert_id is neither owner or member of any parent or # sub-vgrids. # Please note that base_dir must end in slash to avoid access to other # vgrid dirs when own name is a prefix of another name base_dir = os.path.abspath(os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep # make sure all dirs can be created (that a file or directory with the same # name do not exist prior to adding the member) if os.path.exists(user_dir + vgrid_name): output_objects.append( {'object_type': 'error_text', 'text': '''Could not add member, a file or directory in the home directory called %s exists! (%s)''' % (vgrid_name, user_dir + vgrid_name)}) status = returnvalues.CLIENT_ERROR continue # Add (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name, [cert_id]) if not add_status: output_objects.append( {'object_type': 'error_text', 'text': add_msg}) status = returnvalues.SYSTEM_ERROR continue vgrid_name_parts = vgrid_name.split('/') is_subvgrid = len(vgrid_name_parts) > 1 if is_subvgrid: try: # vgrid_name = IMADA/STUD/BACH # vgrid_name_last_fragment = BACH vgrid_name_last_fragment = \ vgrid_name_parts[len(vgrid_name_parts) - 1].strip() # vgrid_name_without_last_fragment = IMADA/STUD/ vgrid_name_without_last_fragment = \ ('/'.join(vgrid_name_parts[0:len(vgrid_name_parts) - 1]) + os.sep).strip() # create dirs if they do not exist dir1 = user_dir + vgrid_name_without_last_fragment if not os.path.isdir(dir1): os.makedirs(dir1) except Exception, exc: # out of range? should not be possible due to is_subvgrid check output_objects.append( {'object_type': 'error_text', 'text': ('Could not create needed dirs on %s server! %s' % (configuration.short_title, exc))}) logger.error('%s when looking for dir %s.' % (exc, dir1)) status = returnvalues.SYSTEM_ERROR continue # create symlink from users home directory to vgrid file directory link_src = os.path.abspath(configuration.vgrid_files_home + os.sep + vgrid_name) + os.sep link_dst = user_dir + vgrid_name # create symlink to vgrid files if not make_symlink(link_src, link_dst, logger): output_objects.append({'object_type': 'error_text', 'text': 'Could not create link to %s files!' % label }) logger.error('Could not create link to %s files! (%s -> %s)' % (label, link_src, link_dst)) status = returnvalues.SYSTEM_ERROR continue cert_id_added.append(cert_id)