Exemplo n.º 1
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)
  
    status = returnvalues.OK
  
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Job Manager'
    title_entry['style'] = css_tmpl(configuration)
    title_entry['javascript'] = js_tmpl()
  
    output_objects.append({'object_type': 'header', 'text': 'Job Manager'})
    output_objects.append({'object_type': 'html_form', 'text': html_pre()})
    output_objects.append({'object_type': 'table_pager', 'entry_name': 'jobs',
                           'default_entries': default_pager_entries,
                           'form_append': pager_append()})
    output_objects.append({'object_type': 'html_form', 'text': html_post()})
  
    return (output_objects, status)
Exemplo n.º 2
0
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)
    output_objects.append({'object_type': 'header', 'text'
                          : 'Public project links'})
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_public_base = configuration.vgrid_public_base
    linklist = []
    for public_vgrid_dir in os.listdir(vgrid_public_base):
        if os.path.exists(os.path.join(vgrid_public_base,
                          public_vgrid_dir, 'index.html')):

            # public project listing is enabled, link to the vgrid's public page

            new_link = {'object_type': 'link',
                        'text': public_vgrid_dir,
                        'destination': '%s/vgrid/%s/path/index.html'\
                         % (configuration.migserver_http_url,
                        public_vgrid_dir)}
            linklist.append(new_link)
    output_objects.append({'object_type': 'linklist', 'links'
                          : linklist})

    return (output_objects, returnvalues.OK)
Exemplo n.º 3
0
def main(client_id, user_arguments_dict, environ=None):
    """Main function used by front end"""

    if environ is None:
        environ = os.environ
    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False,
                                  op_menu=False)
    defaults = signature()[1]
    (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)

    logger.debug('Accepted arguments: %s' % accepted)

    status = returnvalues.OK
    packed_url = accepted['redirect_to'][-1].strip()
    # IMPORTANT: further validate that packed redirect_to is signed and safe
    try:
        (unpacked_url,
         unpacked_query) = base32urldecode(configuration, packed_url)
    except Exception, exc:
        logger.error('base32urldecode failed: %s' % exc)
        output_objects.append({
            'object_type': 'error_text',
            'text': '''failed to unpack redirect_to value!'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)
Exemplo n.º 4
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = initialize_main_variables(client_id)
    output_objects.append({"object_type": "text", "text": "--------- Trying to STATUS exe ----------"})

    defaults = signature()[1]
    (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)
    unique_resource_name = accepted["unique_resource_name"][-1]
    exe_name_list = accepted["exe_name"]
    all = accepted["all"][-1].lower() == "true"
    parallel = accepted["parallel"][-1].lower() == "true"

    if not is_owner(client_id, unique_resource_name, configuration.resource_home, logger):
        output_objects.append(
            {
                "object_type": "error_text",
                "text": "Failure: You must be an owner of " + unique_resource_name + " to get status for the exe!",
            }
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    exit_status = returnvalues.OK

    if all:
        exe_name_list = get_all_exe_names(unique_resource_name)

    # take action based on supplied list of exes

    if len(exe_name_list) == 0:
        output_objects.append(
            {"object_type": "text", "text": "No exes specified and 'all' argument not set to true: Nothing to do!"}
        )

    workers = []
    task_list = []
    for exe_name in exe_name_list:
        task = Worker(
            target=status_resource_exe, args=(unique_resource_name, exe_name, configuration.resource_home, logger)
        )
        workers.append((exe_name, [task]))
        task_list.append(task)
        throttle_max_concurrent(task_list)
        task.start()
        if not parallel:
            task.join()

    for (exe_name, task_list) in workers:
        (status, msg) = task_list[0].finish()
        output_objects.append({"object_type": "header", "text": "Status exe"})
        if not status:
            output_objects.append({"object_type": "error_text", "text": "Problems getting exe status: %s" % msg})
            exit_status = returnvalues.SYSTEM_ERROR
        else:
            output_objects.append({"object_type": "text", "text": "Status command run, output: %s" % msg})
    return (output_objects, exit_status)
Exemplo n.º 5
0
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,
                                  op_menu=client_id)
    output_objects.append({
        'object_type': 'header',
        'text': 'Personal Sandbox Administration and Monitor'
    })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        output_objects.append({
            'object_type': 'link',
            'destination': 'ssslogin.py',
            'text': 'Retry login'
        })
        return (accepted, returnvalues.CLIENT_ERROR)

    username = accepted['username'][-1].strip()
    password = accepted['password'][-1].strip()
    newuser = accepted['newuser'][-1].strip()
    expert_string = accepted['expert'][-1].strip()
    expert = False
    if 'true' == expert_string.lower():
        expert = True
    admin_email = configuration.admin_email

    if not configuration.site_enable_sandboxes:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Sandbox resources are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    # Load the user DB

    try:
        userdb = load_sandbox_db(configuration)
    except IOError:

        # First time - create empty dict

        userdb = {}
    except Exception, exc:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Could not read sandbox database! %s' % exc
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 6
0
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,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox Monitor' % \
                            configuration.short_title 
                          })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    show_all = accepted['show_all'][-1].lower()
    sort = accepted['sort'][-1]
    group_by = accepted['group_by'][-1].lower()

    if not configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'text', 'text':
                               '''Sandbox resources are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    # Load the user file

    try:
        userdb = load_sandbox_db(configuration)
    except Exception, exc:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Could not load any sandbox information'})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 7
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (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 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)

    if not configuration.site_enable_jobs:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Job execution is not enabled on this system'''
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    external_dict = get_keywords_dict(configuration)
    mrsl = fields_to_mrsl(configuration, user_arguments_dict, external_dict)

    tmpfile = None

    # save to temporary file

    try:
        (filehandle, real_path) = tempfile.mkstemp(text=True)
        relative_path = os.path.basename(real_path)
        os.write(filehandle, mrsl)
        os.close(filehandle)
    except Exception, err:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Failed to write temporary mRSL file: %s' % err
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 8
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)

    unique_resource_name = accepted['unique_resource_name'][-1]
    resconfig = accepted['resconfig'][-1]

    output_objects.append({'object_type': 'header', 'text'
                          : 'Trying to Update resource configuration'})

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        logger.error(client_id + ' is not an owner of '
                      + unique_resource_name + ': update rejected!')
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of '
                               + unique_resource_name
                               + ' to update the configuration!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # TODO: race if two confs are uploaded concurrently!

    host_url, host_identifier = unique_resource_name.rsplit('.', 1)
    pending_file = os.path.join(configuration.resource_home,
                            unique_resource_name, 'config.tmp')

    # write new proposed config file to disk
    try:
        logger.info('write to file: %s' % pending_file)
        if not write_file(resconfig, pending_file, logger):
                output_objects.append({'object_type': 'error_text',
                        'text': 'Could not write: %s' % pending_file})
                return (output_objects, returnvalues.SYSTEM_ERROR)
    except Exception, err:
        logger.error('Resource conf %s could not be written: %s' % \
                     (pending_file, err))
        output_objects.append({'object_type': 'error_text', 'text':
                               'Could not write configuration!'})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 9
0
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]
    (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]
    path = accepted['path'][-1]
        
    if not vgrid_is_owner_or_member(vgrid_name, client_id,
                                    configuration):
        output_objects.append({'object_type': 'error_text', 'text':
                               '''You must be an owner or member of %s %s to
access the private files.''' % (vgrid_name, configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # 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

    base_dir = os.path.abspath(os.path.join(configuration.vgrid_private_base,
                                            vgrid_name)) + os.sep

    # Strip leading slashes to avoid join() throwing away prefix 

    rel_path = path.lstrip(os.sep)
    real_path = os.path.abspath(os.path.join(base_dir, rel_path))

    if not valid_user_path(real_path, base_dir, True):
        output_objects.append({'object_type': 'error_text', 'text':
                               '''You are not allowed to use paths outside %s
private files dir.''' % configuration.site_vgrid_label})
        return (output_objects, returnvalues.CLIENT_ERROR)
    
    try:
        private_fd = open(real_path, 'rb')
        entry = {'object_type': 'binary',
                 'data': private_fd.read()}
        # Cut away all the usual web page formatting to show only contents
        output_objects = [{'object_type': 'start', 'headers': []}, entry,
                          {'object_type': 'script_status'},
                          {'object_type': 'end'}]
        private_fd.close()
    except Exception, exc:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Error reading %s private file (%s)'
                               % (configuration.site_vgrid_label, exc)})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 10
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)

    output_objects.append({
        'object_type':
        'text',
        'text':
        '--------- Trying to get STATUS for frontend ----------'
    })

    defaults = signature()[1]
    (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)
    unique_resource_name = accepted['unique_resource_name'][-1]

    logger.info('%s attempts to get status for frontend at %s', client_id,
                unique_resource_name)

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'You must be an owner of ' + unique_resource_name +
            ' to get status for the resource frontend!'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    (status, msg) = status_resource(unique_resource_name,
                                    configuration.resource_home, logger)
    if not status:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s. Error getting resource status.' % msg
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # everything ok

    output_objects.append({'object_type': 'text', 'text': '%s' % msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 11
0
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, op_title=False,
                                  op_menu=client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    action = accepted['action'][-1]
    sandboxkey = accepted['sandboxkey'][-1]
    exe_name = accepted['exe_name'][-1]

    status = returnvalues.OK

    # Web format for cert access and no header for SID access
    if client_id:
        output_objects.append({'object_type': 'title', 'text'
                               : 'SSS script download'})
        output_objects.append({'object_type': 'header', 'text'
                               : 'SSS script download'})
    else:
        output_objects.append({'object_type': 'start'})

    if not configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'text', 'text':
                               '''Sandbox resources are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    (result, unique_resource_name) = get_resource_name(sandboxkey, logger)
    if not result:
        msg = unique_resource_name
    elif action == 'get_frontend_script':
        (result, msg) = get_frontend_script(unique_resource_name, logger)
    elif action == 'get_master_node_script':
        (result, msg) = get_master_node_script(unique_resource_name,
                                               exe_name, logger)
    else:
        result = False
        msg = 'Unknown action: %s' % action

    if not result:
        status = returnvalues.ERROR

    # Status code line followed by raw output
    if not client_id:
        output_objects.append({'object_type': 'script_status', 'text': ''})
        output_objects.append({'object_type': 'binary', 'data': '%s' % status[0]})
    output_objects.append({'object_type': 'binary', 'data': msg})
    return (output_objects, status)
Exemplo n.º 12
0
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]
    (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)

    user_dir = os.path.join(configuration.user_home, client_id_dir(client_id))

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'ARC Queues'
    output_objects.append({
        'object_type': 'header',
        'text': 'Available ARC queues'
    })

    if not configuration.site_enable_griddk:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Grid.dk features are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    # could factor out from here, to be usable from outside
    if not configuration.arc_clusters:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'No ARC support!'
        })
        return (output_objects, returnvalues.ERROR)
    try:
        session = arc.Ui(user_dir)
        queues = session.getQueues()

    except arc.NoProxyError, err:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Error while retrieving: %s' % err.what()
        })
        output_objects += arc.askProxy()
        return (output_objects, returnvalues.ERROR)
Exemplo n.º 13
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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 configuration.site_enable_jobs:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Job execution is not enabled on this system'''
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    status = returnvalues.OK

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Job Manager'
    user_settings = title_entry.get('user_settings', {})
    title_entry['style'] = css_tmpl(configuration, user_settings)
    csrf_map = {}
    method = 'post'
    limit = get_csrf_limit(configuration)
    for target_op in csrf_backends:
        csrf_map[target_op] = make_csrf_token(configuration, method, target_op,
                                              client_id, limit)
    (add_import, add_init, add_ready) = js_tmpl_parts(csrf_map)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready

    output_objects.append({'object_type': 'header', 'text': 'Job Manager'})
    output_objects.append({
        'object_type': 'table_pager',
        'entry_name': 'jobs',
        'default_entries': default_pager_entries,
        'form_append': pager_append()
    })
    output_objects.append({'object_type': 'html_form', 'text': html_post()})

    return (output_objects, status)
Exemplo n.º 14
0
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)
    output_objects.append({"object_type": "header", "text": "%s Virtual Desktop" % configuration.short_title})
    status = returnvalues.OK
    defaults = signature()[1]
    (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)

    title_entry = find_entry(output_objects, "title")
    title_entry["text"] = "Virtual Machines"

    if not configuration.site_enable_vmachines:
        output_objects.append(
            {
                "object_type": "text",
                "text": """Virtual machines are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
"""
                % configuration.admin_email,
            }
        )
        return (output_objects, returnvalues.OK)

    settings_dict = load_settings(client_id, configuration)
    if not settings_dict or not settings_dict.has_key("VNCDISPLAY"):
        logger.info("Settings dict does not have VNCDISPLAY key - using default")
        (vnc_display_width, vnc_display_height) = (1024, 768)
    else:
        (vnc_display_width, vnc_display_height) = settings_dict["VNCDISPLAY"]

    # Make room for vnc control menu

    vnc_menu_height = 24
    vnc_display_height += vnc_menu_height
    password = vms.vnc_jobid(accepted["job_id"][0])

    # Do an "intoN" then map to acsii

    output_objects.append(
        {
            "object_type": "html_form",
            "text": vms.popup_snippet()
            + vms.vnc_applet(configuration, vnc_display_width, vnc_display_height, password),
        }
    )

    return (output_objects, status)
Exemplo n.º 15
0
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, op_menu=False)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    oid_url = accepted['url'][-1]
    openid_status = {
        'object_type': 'openid_status',
        'server': None,
        'status': None,
        'error': ""
    }
    # IMPORTANT: we only allow ping of configured openid servers to avoid abuse
    # otherwise the urlopen could be tricked to use e.g. file:/etc/passwd or
    # be used to attack remote sites
    if oid_url in configuration.user_openid_providers:
        # TODO: build url from conf
        ping_url = oid_url.replace("/id/", "/ping")
        openid_status['server'] = ping_url
        try:
            # Never use proxies
            ping_status = urllib.urlopen(ping_url, proxies={})
            http_status = ping_status.getcode()
            data = ping_status.read()
            ping_status.close()
            if http_status == 200:
                # TODO: better parsing
                if "<h1>True</h1>" in data:
                    openid_status['status'] = "online"
                else:
                    openid_status['status'] = "down"
                    openid_status['error'] = data
            else:
                openid_status['status'] = "down"
                openid_status['error'] = "server returned error code %s" % \
                                         http_status
        except Exception, exc:
            openid_status['status'] = "down"
            openid_status['error'] = "unexpected server response (%s)" % exc
        if openid_status['status'] == "online":
            logger.info("%s on %s succeeded" % (op_name, oid_url))
        else:
            logger.error("%s against %s returned error: " % (op_name, oid_url) \
                         + " %(error)s (%(status)s)" % openid_status)
Exemplo n.º 16
0
def main(client_id, user_arguments_dict):
    """ main """

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)

    output_objects.append({'object_type': 'text', 'text'
                          : '--------- Trying to STOP frontend ----------'
                          })
    defaults = signature()[1]
    (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)

    unique_resource_name = accepted['unique_resource_name'][-1]

    logger.info('%s attempts to stop frontend at %s', client_id,
                unique_resource_name)

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of '
                               + unique_resource_name
                               + ' to stop the resource frontend!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    (status, msg) = stop_resource(unique_resource_name,
                                  configuration.resource_home, logger)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s. Error stopping resource' % msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # everything ok

    output_objects.append({'object_type': 'text', 'text': '%s' % msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 17
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)

    defaults = signature()[1]
    (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)

    unique_resource_name = accepted['unique_resource_name'][-1]

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'You must be an owner of %s to get the list of owners!' %
            unique_resource_name
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # is_owner incorporates unique_resource_name verification - no need to
    # specifically check for illegal directory traversal

    base_dir = os.path.abspath(
        os.path.join(configuration.resource_home,
                     unique_resource_name)) + os.sep
    owners_file = os.path.join(base_dir, 'owners')

    (list_status, msg) = list_items_in_pickled_list(owners_file, logger)
    if not list_status:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Could not get list of owners, reason: %s' % msg
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'list', 'list': msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 18
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (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)

    save_as_default = (accepted['save_as_default'][-1] != 'False')
    external_dict = get_keywords_dict(configuration)
    mrsl = fields_to_mrsl(configuration, user_arguments_dict, external_dict)

    tmpfile = None

    # 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

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    # save to temporary file

    try:
        (filehandle, real_path) = tempfile.mkstemp(text=True)
        relative_path = os.path.basename(real_path)
        os.write(filehandle, mrsl)
        os.close(filehandle)
    except Exception, err:
        output_objects.append({'object_type': 'error_text',
                               'text':
                               'Failed to write temporary mRSL file: %s' % \
                               err})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 19
0
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, op_title=False,
                                  op_menu=client_id)

    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    iosessionid = accepted['iosessionid'][-1]
    sandboxkey = accepted['sandboxkey'][-1]
    exe_name = accepted['exe_name'][-1]

    status = returnvalues.OK

    # Web format for cert access and no header for SID access
    if client_id:
        output_objects.append({'object_type': 'title', 'text'
                               : 'SSS job activity checker'})
        output_objects.append({'object_type': 'header', 'text'
                               : 'SSS job activity checker'})
    else:
        output_objects.append({'object_type': 'start'})

    # check that the job exists, iosessionid is ok (does symlink exist?)

    if iosessionid and os.path.islink(configuration.webserver_home
                                      + iosessionid):
        msg = 'jobactive'
    else:
        if sandboxkey and exe_name:
            (result, msg) = \
                     get_sandbox_exe_stop_command(configuration.sandbox_home,
                                                  sandboxkey, exe_name, logger)
            if result:
                msg = 'stop_command: %s' % msg
        else:
            msg = 'jobinactive'
        status = returnvalues.ERROR

    # Status code line followed by raw output
    if not client_id:
        output_objects.append({'object_type': 'script_status', 'text': ''})
        output_objects.append({'object_type': 'binary', 'data': '%s' % status[0]})
    output_objects.append({'object_type': 'binary', 'data': msg})
    return (output_objects, status)
Exemplo n.º 20
0
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, op_title=False)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)
    job_id_list = accepted['job_id']
    external_dict = mrslkeywords.get_keywords_dict(configuration)

    # 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

    base_dir = \
        os.path.abspath(os.path.join(configuration.mrsl_files_dir,
                        client_dir)) + os.sep

    status = returnvalues.OK
    for job_id in job_id_list:

        # job = Job()

        filepath = os.path.join(base_dir, job_id)
        filepath += '.mRSL'

        (new_job_obj_status, new_job_obj) = \
            create_job_object_from_pickled_mrsl(filepath, logger,
                external_dict)
        if not new_job_obj_status:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : new_job_obj})
            status = returnvalues.CLIENT_ERROR
        else:

            # return new_job_obj

            output_objects.append({'object_type': 'jobobj', 'jobobj'
                                  : new_job_obj})
    return (output_objects, status)
Exemplo n.º 21
0
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,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox FAQ' % \
                            configuration.short_title })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    language = accepted['language'][-1]

    if not configuration.site_enable_sandboxes:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Sandbox resources are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    if not language in html.keys():
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Unsupported language: %s, defaulting to %s' %
            (language, default_language)
        })
        language = default_language

        # print "<a href='ssslogin.py'>Default language</a>"
        # sys.exit(1)
# output_objects.append({"object_type":"html_form", "text":html[language]})

    output_objects.append({'object_type': 'html_form', 'text'
                          : html[language] % \
                           {'site': configuration.short_title}})
    return (output_objects, returnvalues.OK)
Exemplo n.º 22
0
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]
    (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)

    user_dir = os.path.join(configuration.user_home, 
                            client_id_dir(client_id))

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'ARC Queues'
    output_objects.append({'object_type': 'header', 'text'
                          : 'Available ARC queues'})

    if not configuration.site_enable_griddk:
        output_objects.append({'object_type': 'text', 'text':
                               '''Grid.dk features are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    # could factor out from here, to be usable from outside
    if not configuration.arc_clusters:
        output_objects.append({'object_type': 'error_text', 'text':
                               'No ARC support!'})
        return (output_objects, returnvalues.ERROR)
    try:
        session = arc.Ui(user_dir)
        queues = session.getQueues()

    except arc.NoProxyError, err:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Error while retrieving: %s' % err.what()
                              })
        output_objects += arc.askProxy()
        return (output_objects, returnvalues.ERROR)
Exemplo n.º 23
0
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'
                          : 'Show runtime environment details'})
    (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)
    re_name = accepted['re_name'][-1]

    if not valid_dir_input(configuration.re_home, re_name):
        logger.warning(
            "possible illegal directory traversal attempt re_name '%s'"
            % re_name)
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Illegal runtime environment name: "%s"'
                               % re_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not is_runtime_environment(re_name, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                               : "'%s' is not an existing runtime environment!"
                               % re_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Runtime environment details'

    (re_dict, msg) = get_re_dict(re_name, configuration)
    if not re_dict:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Could not read details for "%s"' % msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append(build_reitem_object(configuration, re_dict))

    return (output_objects, returnvalues.OK) 
Exemplo n.º 24
0
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, op_menu=False)
    logger = configuration.logger
    logger.info('oiddiscover: %s' % user_arguments_dict)
    output_objects.append({
        'object_type':
        'header',
        'text':
        'OpenID Discovery for %s' % configuration.short_title
    })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    # Force to raw file output unless something else is explicitly requested.
    # Relies on delay_format option in run_cgi_script_possibly_with_cert
    if not user_arguments_dict.get('output_format', []):
        user_arguments_dict['output_format'] = ['file']

    discovery_doc = generate_openid_discovery_doc(configuration)
    output_objects.append({
        'object_type': 'text',
        'text': 'Advertising valid OpenID endpoints:'
    })
    # make sure we always have at least one output_format entry
    output_format = user_arguments_dict.get('output_format', []) + ['file']
    if output_format[0] == 'file':
        headers = [('Content-Type', 'application/xrds+xml'),
                   ('Content-Disposition', 'attachment; filename=oid.xrds'),
                   ('Content-Length', '%s' % len(discovery_doc))]
        start_entry = find_entry(output_objects, 'start')
        start_entry['headers'] = headers
        # output discovery_doc as raw xrds doc in any case
        output_objects.append({
            'object_type': 'file_output',
            'lines': [discovery_doc]
        })
    else:
        output_objects.append({'object_type': 'binary', 'data': discovery_doc})
    return (output_objects, returnvalues.OK)
Exemplo n.º 25
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)

    output_objects.append({'object_type': 'text', 'text'
                          : '--------- Trying to get STATUS for frontend ----------'
                          })

    defaults = signature()[1]
    (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)
    unique_resource_name = accepted['unique_resource_name'][-1]

    logger.info('%s attempts to get status for frontend at %s',
                client_id, unique_resource_name)

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of '
                               + unique_resource_name
                               + ' to get status for the resource frontend!'
                              })
        return (output_objects, returnvalues.CLIENT_ERROR)

    (status, msg) = status_resource(unique_resource_name,
                                    configuration.resource_home, logger)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s. Error getting resource status.'
                               % msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # everything ok

    output_objects.append({'object_type': 'text', 'text': '%s' % msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 26
0
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,
                                  op_menu=client_id)
    defaults = signature()[1]
    (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)

    # output_objects.append({'object_type': 'header', 'text': 'Welcome to %s!' %
    #                       configuration.short_title})

    # Generate and insert the page HTML
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s Home' % configuration.short_title

    # jquery support for AJAX saving

    (add_import, add_init, add_ready) = save_settings_js(configuration)
    add_init += '''
    function addApp() {
        $("#app-nav-container").hide();
        $("#add-app__window").show();
    }
    function closeAddApp() {
        console.log("close add app");
        $("#app-nav-container").show();
        $("#add-app__window").hide();
    }
    '''
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready

    html = html_tmpl(configuration, client_id, title_entry)
    output_objects.append({'object_type': 'html_form', 'text': html})

    return (output_objects, returnvalues.OK)
Exemplo n.º 27
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)
    
    status = returnvalues.OK

    all_paths = accepted['path']
    entry_path = all_paths[-1]
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'File Manager'
    title_entry['style'] = css_tmpl(configuration)
    if 'submitjob' in extract_menu(configuration, title_entry):
        enable_submit = 'true'
    else:
        enable_submit = 'false'
    title_entry['javascript'] = js_tmpl(entry_path, enable_submit,
                                        str(configuration.site_enable_preview))
    
    output_objects.append({'object_type': 'header', 'text': 'File Manager' })
    output_objects.append({'object_type': 'html_form', 'text':
                           html_tmpl(configuration, title_entry)})

    if len(all_paths) > 1:
        output_objects.append({'object_type': 'sectionheader', 'text':
                               'All requested paths:'})
        for path in all_paths:
            output_objects.append({'object_type': 'link', 'text': path,
                                   'destination': 'fileman.py?path=%s' % path})
            output_objects.append({'object_type': 'text', 'text': ''})

    return (output_objects, status)
Exemplo n.º 28
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, _) = \
        initialize_main_variables(client_id, op_header=False,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : 'Personal Sandbox Administration and Monitor'})
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        output_objects.append({'object_type': 'link', 'destination'
                              : 'ssslogin.py', 'text': 'Retry login'})
        return (accepted, returnvalues.CLIENT_ERROR)

    username = accepted['username'][-1].strip()
    password = accepted['password'][-1].strip()
    newuser = accepted['newuser'][-1].strip()
    expert_string = accepted['expert'][-1].strip()
    expert = False
    if 'true' == expert_string.lower():
        expert = True
    admin_email = configuration.admin_email

    if not configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'text', 'text':
                               '''Sandbox resources are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    # Load the user DB

    try:
        userdb = load_sandbox_db(configuration)
    except IOError:

        # First time - create empty dict

        userdb = {}
    except Exception, exc:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Could not read sandbox database! %s'
                               % exc})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 29
0
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, op_menu=False)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    oid_url = accepted['url'][-1]
    openid_status = {'object_type': 'openid_status', 'server': None,
                     'status': None, 'error': ""}
    # IMPORTANT: we only allow ping of configured openid servers to avoid abuse
    # otherwise the urlopen could be tricked to use e.g. file:/etc/passwd or
    # be used to attack remote sites
    if oid_url in configuration.user_openid_providers:
        # TODO: build url from conf
        ping_url = oid_url.replace("/id/", "/ping")
        openid_status['server'] = ping_url
        try:
            ping_status = urllib.urlopen(ping_url)
            http_status = ping_status.getcode()
            data = ping_status.read()
            ping_status.close()
            if http_status == 200:
                # TODO: better parsing
                if "<h1>True</h1>" in data:
                    openid_status['status'] = "online"
                else:
                    openid_status['status'] = "down"
                    openid_status['error'] = data
            else:
                openid_status['status'] = "down"
                openid_status['error'] = "server returned error code %s" % \
                                         http_status
        except Exception, exc:
            openid_status['status'] = "down"
            openid_status['error'] = "unexpected server response (%s)" % exc
        if openid_status['status'] == "online":
            logger.info("%s on %s succeeded" % (op_name, oid_url))
        else:
            logger.error("%s against %s returned error: " % (op_name, oid_url) \
                         + " %(error)s (%(status)s)" % openid_status)
Exemplo n.º 30
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    defaults = signature()[1]
    (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]

    # 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,
     ret_variables) = init_vgrid_script_list(vgrid_name, client_id,
                                             configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # list

    (list_status, msg) = vgrid_list(vgrid_name,
                                    'triggers',
                                    configuration,
                                    allow_missing=True)
    if not list_status:
        output_objects.append({
            'object_type': 'error_text',
            'text': '%s' % msg
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'list', 'list': msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 31
0
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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Resource details'
    output_objects.append({'object_type': 'header', 'text'
                          : 'Show resource details'})

    defaults = signature()[1]
    (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)
    resource_list = accepted['unique_resource_name']
    status = returnvalues.OK
    visible_res = user_visible_res_confs(configuration, client_id)
    allowed_vgrids = user_allowed_vgrids(configuration, client_id)

    for visible_res_name in resource_list:
        if not visible_res_name in visible_res.keys():
            logger.warning('User %s not allowed to view %s (%s)' % \
                           (client_id, visible_res_name, visible_res.keys()))
            output_objects.append({'object_type': 'error_text',
                                   'text': 'invalid resource %s' % \
                                   visible_res_name})
            continue
        res_dict = visible_res[visible_res_name]
        res_item = build_resitem_object_from_res_dict(configuration,
                                                      visible_res_name,
                                                      res_dict,
                                                      allowed_vgrids)
        output_objects.append(res_item)
        
    return (output_objects, status)
Exemplo n.º 32
0
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,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox Monitor' % \
                            configuration.short_title
                          })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    show_all = accepted['show_all'][-1].lower()
    sort = accepted['sort'][-1]
    group_by = accepted['group_by'][-1].lower()

    if not configuration.site_enable_sandboxes:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Sandbox resources are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    # Load the user file

    try:
        userdb = load_sandbox_db(configuration)
    except Exception, exc:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Could not load any sandbox information'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 33
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)

    # 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

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    status = returnvalues.OK

    pid = 0
    pidfile = os.path.join(base_dir, '.Xvnc4.pid')
    try:
        fd = open(pidfile, 'r')
        pid = int(fd.readline())
        fd.close()
        os.remove(pidfile)
        os.kill(pid, 9)
        output_objects.append({'object_type': 'text', 'text'
                              : 'stopped vnc'})
    except Exception, err:
        logger.error('Unable to extract pid and kill vnc process: %s'
                      % err)
        status = returnvalues.CLIENT_ERROR
        output_objects.append({'object_type': 'text', 'text'
                              : 'failed to stop vnc'})
Exemplo n.º 34
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)

    # 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

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    status = returnvalues.OK

    pid = 0
    pidfile = os.path.join(base_dir, '.Xvnc4.pid')
    try:
        fd = open(pidfile, 'r')
        pid = int(fd.readline())
        fd.close()
        os.remove(pidfile)
        os.kill(pid, 9)
        output_objects.append({'object_type': 'text', 'text'
                              : 'stopped vnc'})
    except Exception, err:
        logger.error('Unable to extract pid and kill vnc process: %s'
                      % err)
        status = returnvalues.CLIENT_ERROR
        output_objects.append({'object_type': 'text', 'text'
                              : 'failed to stop vnc'})
Exemplo n.º 35
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    defaults = signature()[1]
    (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]

    # 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, ret_variables) = init_vgrid_script_list(vgrid_name,
            client_id, configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # list

    (status, msg) = vgrid_list(vgrid_name, 'triggers', configuration)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text': '%s'
                               % msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'list', 'list': msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 36
0
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,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox FAQ' % \
                            configuration.short_title })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    language = accepted['language'][-1]

    if not configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'text', 'text':
                               '''Sandbox resources are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    if not language in html.keys():
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Unsupported language: %s, defaulting to %s'
                               % (language, default_language)})
        language = default_language

        # print "<a href='ssslogin.py'>Default language</a>"
        # sys.exit(1)
   # output_objects.append({"object_type":"html_form", "text":html[language]})

    output_objects.append({'object_type': 'html_form', 'text'
                          : html[language] % \
                           {'site': configuration.short_title}})
    return (output_objects, returnvalues.OK)
Exemplo n.º 37
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = initialize_main_variables(client_id)

    defaults = signature()[1]
    (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)

    unique_resource_name = accepted["unique_resource_name"][-1]

    if not is_owner(client_id, unique_resource_name, configuration.resource_home, logger):
        output_objects.append(
            {
                "object_type": "error_text",
                "text": "You must be an owner of %s to get the list of owners!" % unique_resource_name,
            }
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    # is_owner incorporates unique_resource_name verification - no need to
    # specifically check for illegal directory traversal

    base_dir = os.path.abspath(os.path.join(configuration.resource_home, unique_resource_name)) + os.sep
    owners_file = os.path.join(base_dir, "owners")

    (status, msg) = list_items_in_pickled_list(owners_file, logger)
    if not status:
        output_objects.append({"object_type": "error_text", "text": "Could not get list of owners, reason: %s" % msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({"object_type": "list", "list": msg})
    return (output_objects, returnvalues.OK)
Exemplo n.º 38
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    stats = accepted['stats']

    status = returnvalues.OK

    user_stats = {
        'object_type': 'user_stats',
        'disk': None,
        'jobs': None,
        'resources': None,
        'certificate': None
    }
    if 'disk' in stats:
        disk_stats = refresh_disk_stats(configuration, client_id)
        total_disk = {
            'own_files': disk_stats[OWN][FILES],
            'own_directories': disk_stats[OWN][DIRECTORIES],
            'own_megabytes': format_bytes(disk_stats[OWN][BYTES], 'mega'),
            'vgrid_files': disk_stats[VGRID][FILES],
            'vgrid_directories': disk_stats[VGRID][DIRECTORIES],
            'vgrid_megabytes': format_bytes(disk_stats[VGRID][BYTES], 'mega')
        }
        user_stats['disk'] = total_disk
    if 'jobs' in stats:
        job_stats = refresh_job_stats(configuration, client_id)
        total_jobs = {
            'total': sum(job_stats[JOBS].values()),
            'parse': job_stats[JOBS][PARSE],
            'queued': job_stats[JOBS][QUEUED],
            'executing': job_stats[JOBS][EXECUTING],
            'finished': job_stats[JOBS][FINISHED],
            'retry': job_stats[JOBS][RETRY],
            'canceled': job_stats[JOBS][CANCELED],
            'expired': job_stats[JOBS][EXPIRED],
            'failed': job_stats[JOBS][FAILED],
            'frozen': job_stats[JOBS][FROZEN],
        }
        user_stats['jobs'] = total_jobs
    if 'resources' in stats:
        allowed_res = user_allowed_res_exes(configuration, client_id)
        # allowed_res is dictionary of res ID and list of attached exe names
        resource_count = len(allowed_res.keys())
        exe_count = 0
        for exes in allowed_res.values():
            exe_count += len(exes)
        total_res = {'resources': resource_count, 'exes': exe_count}
        user_stats['resources'] = total_res
    if 'certificate' in stats:
        if os.environ.has_key('SSL_CLIENT_V_END'):
            expire = os.environ['SSL_CLIENT_V_END']
        else:
            expire = -1
        total_cert = {'client_id': client_id, 'expire': expire}
        # Server may not want to reveal too much, but we want to provide
        # easy access to all safe SSL_* environment fields. This list of
        # environment prefixes are used to expose any such fields.
        # These env names are from Apache but can be safely extended to
        # include similar envs from other web servers if needed.
        # Please be careful not to make it too general, though.
        expose_env_prefixes = ('SSL_SERVER_S_DN', 'SSL_SERVER_V_',
                               'SSL_SERVER_I_DN', 'SSL_CLIENT_S_DN',
                               'SSL_CLIENT_V_', 'SSL_CLIENT_I_DN')
        for field in os.environ:
            for expose in expose_env_prefixes:
                if field.startswith(expose):
                    total_cert[field] = os.environ.get(field, "unknown")

        user_stats['certificate'] = total_cert

    output_objects.append(user_stats)

    return (output_objects, status)
Exemplo n.º 39
0
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'] = '%s Workflows' % label
    # NOTE: Delay header entry here to include vgrid_name
    (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]
    operation = accepted['operation'][-1]
    flags = ''.join(accepted['flags'][-1])

    if not vgrid_is_owner_or_member(vgrid_name, client_id, configuration):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''You must be an owner or member of %s vgrid to
access the workflows.''' % vgrid_name
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not operation in allowed_operations:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Operation must be one of %s.''' % ', '.join(allowed_operations)
        })
        return (output_objects, returnvalues.OK)

    if operation in show_operations:

        # jquery support for tablesorter (and unused confirmation dialog)
        # table initially sorted by 0 (last update / date)

        refresh_call = 'ajax_workflowjobs("%s", "%s")' % (vgrid_name, flags)
        table_spec = {
            'table_id': 'workflowstable',
            'sort_order': '[[0,1]]',
            'refresh_call': refresh_call
        }
        (add_import, add_init,
         add_ready) = man_base_js(configuration, [table_spec])
        if operation == "show":
            add_ready += '%s;' % refresh_call
        add_ready += '''
              /* Init variables helper as foldable but closed and with individual
              heights */
              $(".variables-accordion").accordion({
                                           collapsible: true,
                                           active: false,
                                           heightStyle: "content"
                                          });
              /* fix and reduce accordion spacing */
              $(".ui-accordion-header").css("padding-top", 0)
                                       .css("padding-bottom", 0).css("margin", 0);
              /* NOTE: requires managers CSS fix for proper tab bar height */
              $(".workflow-tabs").tabs();
              $("#logarea").scrollTop($("#logarea")[0].scrollHeight);
        '''
        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready
        output_objects.append({
            'object_type': 'html_form',
            'text': man_base_html(configuration)
        })

        output_objects.append({
            'object_type':
            'header',
            'text':
            '%s Workflows for %s' % (label, vgrid_name)
        })

    logger.info('vgridworkflows %s %s' % (vgrid_name, operation))

    # Iterate through jobs and list details for each

    trigger_jobs = []
    log_content = ''

    if operation in list_operations:
        trigger_job_dir = os.path.join(
            configuration.vgrid_home,
            os.path.join(vgrid_name,
                         '.%s.jobs' % configuration.vgrid_triggers))
        trigger_job_pending_dir = os.path.join(trigger_job_dir,
                                               'pending_states')
        trigger_job_final_dir = os.path.join(trigger_job_dir, 'final_states')

        if makedirs_rec(trigger_job_pending_dir, configuration) \
                and makedirs_rec(trigger_job_final_dir, configuration):
            abs_vgrid_dir = '%s/' \
                % os.path.abspath(os.path.join(configuration.vgrid_files_home,
                                               vgrid_name))
            for filename in os.listdir(trigger_job_pending_dir):
                trigger_job_filepath = \
                    os.path.join(trigger_job_pending_dir, filename)
                trigger_job = unpickle(trigger_job_filepath, logger)
                serverjob_filepath = \
                    os.path.join(configuration.mrsl_files_dir,
                                 os.path.join(
                                     client_id_dir(trigger_job['owner']),
                                     '%s.mRSL' % trigger_job['jobid']))
                serverjob = unpickle(serverjob_filepath, logger)
                if serverjob:
                    if serverjob['STATUS'] in pending_states:
                        trigger_event = trigger_job['event']
                        trigger_rule = trigger_job['rule']
                        trigger_action = trigger_event['event_type']
                        trigger_time = time.ctime(trigger_event['time_stamp'])
                        trigger_path = '%s %s' % \
                                       (trigger_event['src_path'].replace(
                                        abs_vgrid_dir, ''),
                                           trigger_event['dest_path'].replace(
                                        abs_vgrid_dir, ''))
                        job = {
                            'object_type': 'trigger_job',
                            'job_id': trigger_job['jobid'],
                            'rule_id': trigger_rule['rule_id'],
                            'path': trigger_path,
                            'action': trigger_action,
                            'time': trigger_time,
                            'status': serverjob['STATUS']
                        }
                        if not job['rule_id'].startswith(img_trigger_prefix) \
                                or verbose(flags):
                            trigger_jobs.append(job)
                    elif serverjob['STATUS'] in final_states:
                        src_path = os.path.join(trigger_job_pending_dir,
                                                filename)
                        dest_path = os.path.join(trigger_job_final_dir,
                                                 filename)
                        move_file(src_path, dest_path, configuration)
                    else:
                        logger.error(
                            'Trigger job: %s, unknown state: %s' %
                            (trigger_job['jobid'], serverjob['STATUS']))

        log_content = read_trigger_log(configuration, vgrid_name, flags)

    if operation in show_operations:

        # Always run as rule creator to avoid users being able to act on behalf
        # of ANY other user using triggers (=exploit)

        extra_fields = [
            ('path', None),
            ('match_dirs', ['False', 'True']),
            ('match_recursive', ['False', 'True']),
            ('changes', [keyword_all] + valid_trigger_changes),
            ('action', [keyword_auto] + valid_trigger_actions),
            ('arguments', None),
            ('run_as', client_id),
        ]

        # NOTE: we do NOT show saved template contents - see addvgridtriggers

        optional_fields = [('rate_limit', None), ('settle_time', None)]

        # Only include system triggers in verbose mode
        if verbose(flags):
            system_filter = []
        else:
            system_filter = [('rule_id', '%s_.*' % img_trigger_prefix)]
        (init_status,
         oobjs) = vgrid_add_remove_table(client_id,
                                         vgrid_name,
                                         'trigger',
                                         'vgridtrigger',
                                         configuration,
                                         extra_fields + optional_fields,
                                         filter_items=system_filter)
        if not init_status:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'failed to load triggers: %s' % oobjs
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        # Generate variable helper values for a few concrete samples for help
        # text
        vars_html = ''
        dummy_rule = {'run_as': client_id, 'vgrid_name': vgrid_name}
        samples = [('input.txt', 'modified'), ('input/image42.raw', 'changed')]
        for (path, change) in samples:
            vgrid_path = os.path.join(vgrid_name, path)
            vars_html += "<b>Expanded variables when %s is %s:</b><br/>" % \
                (vgrid_path, change)
            expanded = get_path_expand_map(vgrid_path, dummy_rule, change)
            for (key, val) in expanded.items():
                vars_html += "    %s: %s<br/>" % (key, val)
        commands_html = ''
        commands = get_usage_map(configuration)
        for usage in commands.values():
            commands_html += "    %s<br/>" % usage

        helper_html = """
<div class='variables-accordion'>
<h4>Help on available trigger variable names and values</h4>
<p>
Triggers can use a number of helper variables on the form +TRIGGERXYZ+ to
dynamically act on targets. Some of the values are bound to the rule owner the
%s while the remaining ones are automatically expanded for the particular
trigger target as shown in the following examples:<br/>
%s
</p>
<h4>Help on available trigger commands and arguments</h4>
<p>
It is possible to set up trigger rules that basically run any operation with a
side effect you could manually do on %s. I.e. like submitting/cancelling
a job, creating/moving/deleting a file or directory and so on. When you select
'command' as the action for a trigger rule, you have the following commands at
your disposal:<br/>
%s
</p>
</div>
""" % (label, vars_html, configuration.short_title, commands_html)

        # Make page with manage triggers tab and active jobs and log tab

        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
    <div id="wrap-tabs" class="workflow-tabs">
<ul>
<li><a href="#manage-tab">Manage Triggers</a></li>
<li><a href="#jobs-tab">Active Trigger Jobs</a></li>
</ul>
'''
        })

        # Display existing triggers and form to add new ones

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
<div id="manage-tab">
'''
        })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Manage Triggers'
        })
        output_objects.extend(oobjs)
        output_objects.append({
            'object_type': 'html_form',
            'text': helper_html
        })

        if configuration.site_enable_crontab:
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '''
<p>You can combine these workflows with the personal '''
            })
            output_objects.append({
                'object_type': 'link',
                'destination': 'crontab.py',
                'class': 'crontablink iconspace',
                'text': 'schedule task'
            })
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '''
facilities in case you want to trigger flows at given times rather than only
in reaction to file system events.</p>
'''
            })
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
</div>
'''
        })

        # Display active trigger jobs and recent logs for this vgrid

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
    <div id="jobs-tab">
    '''
        })
        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Active Trigger Jobs'
        })
        output_objects.append({
            'object_type': 'table_pager',
            'entry_name': 'job',
            'default_entries': default_pager_entries
        })

    output_objects.append({
        'object_type': 'trigger_job_list',
        'trigger_jobs': trigger_jobs
    })

    if operation in show_operations:
        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Trigger Log'
        })

    output_objects.append({
        'object_type': 'trigger_log',
        'log_content': log_content
    })
    if operation in show_operations:
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
</div>
'''
        })

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
</div>
'''
        })
    return (output_objects, returnvalues.OK)
Exemplo n.º 40
0
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, op_title=False,
                                  op_menu=client_id)

    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    remote_ip = str(os.getenv('REMOTE_ADDR'))

    res_type = accepted['type'][-1]
    unique_resource_name = accepted['unique_resource_name'][-1]
    exe_name = accepted['exe_name'][-1]
    pgid = accepted['pgid'][-1]

    status = returnvalues.OK

    # Web format for cert access and no header for SID access
    if client_id:
        output_objects.append({
            'object_type': 'title',
            'text': 'Load resource script PGID'
        })
        output_objects.append({
            'object_type': 'header',
            'text': 'Load resource script PGID'
        })
    else:
        output_objects.append({'object_type': 'start'})

    # Please note that base_dir must end in slash to avoid access to other
    # resource dirs when own name is a prefix of another resource name

    base_dir = os.path.abspath(
        os.path.join(configuration.resource_home,
                     unique_resource_name)) + os.sep

    # We do not have a trusted base dir here since there's no certificate data.
    # Manually check input variables

    if not valid_dir_input(configuration.resource_home, unique_resource_name):

        # out of bounds - rogue resource!?!?

        msg = 'invalid unique_resource_name! %s' % unique_resource_name
        logger.error('putrespgid FE called with illegal parameter(s) in what appears to be an illegal directory traversal attempt!: unique_resource_name %s, exe %s, client_id %s' \
                     % (unique_resource_name, exe_name, client_id))
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not valid_dir_input(base_dir, 'EXE_%s.PGID' % exe_name):

        # out of bounds - rogue resource!?!?

        msg = 'invalid unique_resource_name / exe_name! %s / %s' \
              % (unique_resource_name, exe_name)
        logger.error('putrespgid EXE called with illegal parameter(s) in what appears to be an illegal directory traversal attempt!: unique_resource_name %s, exe %s, client_id %s' \
                                        % (unique_resource_name, exe_name, client_id))
        return (output_objects, returnvalues.CLIENT_ERROR)

    (load_status, resource_conf) = \
                  get_resource_configuration(configuration.resource_home,
                                             unique_resource_name, logger)
    if not load_status:
        logger.error("Invalid putrespgid - no resouce_conf for: %s : %s" % \
                     (unique_resource_name, resource_conf))
        output_objects.append({
            'object_type': 'error_text',
            'text': 'invalid request: no such resource!'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Check that resource address matches request source to make DoS harder
    proxy_fqdn = resource_conf.get('FRONTENDPROXY', None)
    try:
        check_source_ip(remote_ip, unique_resource_name, proxy_fqdn)
    except ValueError, vae:
        logger.error("Invalid put pgid: %s" % vae)
        output_objects.append({
            'object_type': 'error_text',
            'text': 'invalid request: %s' % vae
        })
        return (output_objects, returnvalues.CLIENT_ERROR)
Exemplo n.º 41
0
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'] = "%s Details" % label
    output_objects.append({'object_type': 'header', 'text':
                           'Show %s Details' % 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)
    vgrid_list = accepted['vgrid_name']
    status = returnvalues.OK
    vgrid_access = user_vgrid_access(configuration, client_id)

    for vgrid_name in vgrid_list:
        vgrid_dict = {'vgrid_name': vgrid_name}
        (settings_status, settings_dict) = vgrid_settings(vgrid_name,
                                                          configuration,
                                                          recursive=True,
                                                          as_dict=True)
        if not settings_status:
            settings_dict = {}
        logger.info("loaded vgrid %s settings: %s" %
                    (vgrid_name, settings_dict))
        vgrid_dict.update(settings_dict)
        if user_view_access(configuration, vgrid_name, client_id, settings_dict,
                            'visible_owners'):
            (owners_status, owners) = vgrid_owners(vgrid_name, configuration)
            if owners_status:
                vgrid_dict['owners'] = owners
        if user_view_access(configuration, vgrid_name, client_id, settings_dict,
                            'visible_members'):
            (members_status, members) = vgrid_members(vgrid_name, configuration)
            if members_status:
                vgrid_dict['members'] = members
        if user_view_access(configuration, vgrid_name, client_id, settings_dict,
                            'visible_resources'):
            (res_status, resources) = vgrid_resources(vgrid_name, configuration)
            if res_status:
                vgrid_dict['resources'] = resources

        if user_view_access(configuration, vgrid_name, client_id, settings_dict,
                            'create_sharelink'):
            vgrid_dict['sharelink'] = settings_dict.get('create_sharelink',
                                                        keyword_owners)

        # Report no such vgrid if hidden

        if settings_dict.get('hidden', False) and \
                not client_id in vgrid_dict.get('owners', []):
            output_objects.append({'object_type': 'error_text', 'text':
                                   'No such %s: %s' % (label, vgrid_name)})
            status = returnvalues.CLIENT_ERROR
            continue

        # Show vgrid details based on participation and visibility settings

        vgrid_item = build_vgriditem_object_from_vgrid_dict(configuration,
                                                            vgrid_name,
                                                            vgrid_dict,
                                                            vgrid_access)
        output_objects.append(vgrid_item)

        if client_id in vgrid_dict.get('owners', []):
            output_objects.append({'object_type': 'sectionheader',
                                   'text': 'Administrate'})
            output_objects.append({'object_type': 'link',
                                   'destination':
                                   'adminvgrid.py?vgrid_name=%s'
                                   % vgrid_name,
                                   'class': 'adminlink iconspace',
                                   'title': 'Administrate %s' % vgrid_name,
                                   'text': 'Administrate %s' % vgrid_name,
                                   })

    return (output_objects, status)
Exemplo n.º 42
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)

    flags = ''.join(accepted['flags'])
    lines = int(accepted['lines'][-1])
    pattern_list = accepted['path']

    # 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

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    status = returnvalues.OK

    if verbose(flags):
        for flag in flags:
            output_objects.append({'object_type': 'text', 'text'
                                  : '%s using flag: %s' % (op_name,
                                  flag)})

    for pattern in pattern_list:

        # Check directory traversal attempts before actual handling to avoid
        # leaking information about file system layout while allowing
        # consistent error messages

        unfiltered_match = glob.glob(base_dir + pattern)
        match = []
        for server_path in unfiltered_match:
            real_path = os.path.abspath(server_path)
            if not valid_user_path(real_path, base_dir, True):

                # out of bounds - save user warning for later to allow
                # partial match:
                # ../*/* is technically allowed to match own files.

                logger.warning('%s tried to %s restricted path %s ! (%s)'
                               % (client_id, op_name, real_path, pattern))
                continue
            match.append(real_path)

        # Now actually treat list of allowed matchings and notify if no
        # (allowed) match

        if not match:
            output_objects.append({'object_type': 'file_not_found',
                                  'name': pattern})
            status = returnvalues.FILE_NOT_FOUND

        for real_path in match:
            relative_path = real_path.replace(base_dir, '')
            output_lines = []
            try:
                filedes = open(real_path, 'r')
                i = 0
                for line in filedes:
                    if i >= lines:
                        break
                    output_lines.append(line)
                    i += 1
                filedes.close()
            except Exception, exc:
                output_objects.append({'object_type': 'error_text',
                        'text': "%s: '%s': %s" % (op_name,
                        relative_path, exc)})
                logger.error("%s: failed on '%s': %s" % (op_name,
                             relative_path, exc))
                status = returnvalues.SYSTEM_ERROR
                continue
            entry = {'object_type': 'file_output',
                       'lines': output_lines,
                       'wrap_binary': binary(flags),
                       'wrap_targets': ['lines']}
            if verbose(flags):
                entry['path'] = relative_path
            output_objects.append(entry)
Exemplo n.º 43
0
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'] = "Remove %s Owner" % label
    output_objects.append({'object_type': 'header', 'text':
                           'Remove %s Owner' % 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)

    vgrid_name = accepted['vgrid_name'][-1]
    flags = ''.join(accepted['flags'])
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)
    # inherited vgrid membership
    inherit_vgrid_member = False

    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)

    # always allow owner to remove self
    if client_id != cert_id:

        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 other owners
        (allow_status, allow_msg) = allow_owners_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)

    # 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 remove if not already an owner

    if not vgrid_is_owner(vgrid_name, cert_id, configuration):
        logger.warning('%s is not allowed to remove owner %s from %s' %
                       (client_id, cert_id, vgrid_name))
        output_objects.append({'object_type': 'error_text', 'text':
                               '%s is not an owner of %s or a parent %s.' %
                               (cert_id, vgrid_name, label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # we need the local owners file to detect inherited ownerships

    (owners_status, owners_direct) = vgrid_owners(vgrid_name, configuration,
                                                  False)
    (all_status, owners) = vgrid_owners(vgrid_name, configuration, True)
    if not owners_status or not all_status:
        logger.error('Error loading owners for %s: %s / %s'
                     % (vgrid_name, owners_direct, owners))
        output_objects.append(
            {'object_type': 'error_text', 'text':
             'An internal error occurred, error conditions have been logged.'})
        output_objects.append({'object_type': 'text', 'text': '''
         You can help us fix the problem by notifying the administrators
         via mail about what you wanted to do when the error happened.'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    logger.info('%s removing owner %s from %s' % (client_id, cert_id,
                                                  vgrid_name))

    # find out whether to just remove an owner or delete the whole thing.
    # ask about delete if last or no direct owners.

    if len(owners_direct) > 1:

        logger.debug('Removing %s, one of several owners, from %s.' %
                     (cert_id, vgrid_name))

        if not (cert_id in owners_direct):

            # the owner owns an upper vgrid, ownership is inherited
            # cannot remove, not last (inherited) owner

            logger.warning('Cannot delete: Inherited ownership.' +
                           '\n Owners: %s,\n Direct owners: %s.'
                           % (owners, owners_direct))
            output_objects.append({'object_type': 'error_text', 'text':
                                   '''%s is owner of a parent %s. 
Owner removal has to be performed at the topmost vgrid''' %
                                   (cert_id, label)})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove any tracker admin rights

            if configuration.trac_admin_path:
                public_tracker_dir = \
                    os.path.abspath(os.path.join(
                        configuration.vgrid_public_base, vgrid_name,
                        '.vgridtracker'))
                private_tracker_dir = \
                    os.path.abspath(os.path.join(
                        configuration.vgrid_private_base, vgrid_name,
                        '.vgridtracker'))
                vgrid_tracker_dir = \
                    os.path.abspath(os.path.join(
                        configuration.vgrid_files_home, vgrid_name,
                        '.vgridtracker'))
                for tracker_dir in [public_tracker_dir, private_tracker_dir,
                                    vgrid_tracker_dir]:
                    if not rm_tracker_admin(configuration, cert_id,
                                            vgrid_name, tracker_dir,
                                            output_objects):
                        return (output_objects, returnvalues.SYSTEM_ERROR)

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep

            # Do not touch vgrid share if still a member of a parent vgrid

            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 still a member of parent %s %s.
Preserving access to corresponding %s.''' % (cert_id, label,
                                             inherit_vgrid_member, label)})
            else:
                (success, msg) = unlink_share(user_dir, vgrid_name)
                if not success:
                    logger.error('Could not remove share link: %s.' % msg)
                    output_objects.append({'object_type': 'error_text', 'text':
                                           'Could not remove share links: %s.'
                                           % msg})
                    return (output_objects, returnvalues.SYSTEM_ERROR)

            # unlink shared web folders

            (success, msg) = unlink_web_folders(user_dir, vgrid_name)
            if not success:
                logger.error('Could not remove web links: %s.' % msg)
                output_objects.append({'object_type': 'error_text', 'text':
                                       'Could not remove web links: %s.'
                                       % msg})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # remove user from saved owners list
            (rm_status, rm_msg) = vgrid_remove_owners(configuration, vgrid_name,
                                                      [cert_id])
            if not rm_status:
                output_objects.append({'object_type': 'error_text', 'text':
                                       '%s of owners of %s'
                                       % (rm_msg, vgrid_name)})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # Any parent vgrid membership is left untouched here as we only
            # force a normal refresh in unmap_inheritance
            unmap_inheritance(configuration, vgrid_name, cert_id)

            output_objects.append({'object_type': 'text', 'text':
                                   '%s successfully removed as owner of %s!'
                                   % (cert_id, vgrid_name)})
            output_objects.append({'object_type': 'link', 'destination':
                                   'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text':
                                   'Back to administration for %s' % vgrid_name})
            return (output_objects, returnvalues.OK)

    else:

        # no more direct owners - we try to remove this VGrid

        logger.debug('Leave %s from %s with no more direct owners: delete' %
                     (vgrid_name, cert_id))

        if not force(flags):
            output_objects.append({'object_type': 'text', 'text': '''
No more direct owners of %s - leaving will result in the %s getting
deleted. Please use either of the links below to confirm or cancel.
''' % (vgrid_name, label)})
            # Reuse csrf token from this request
            target_op = 'rmvgridowner'
            js_name = target_op
            csrf_token = accepted[csrf_field][-1]
            helper = html_post_helper(js_name, '%s.py' % target_op,
                                      {'vgrid_name': vgrid_name,
                                       'cert_id': cert_id, 'flags': 'f',
                                       csrf_field: csrf_token})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            output_objects.append({'object_type': 'link', 'destination':
                                   "javascript: %s();" % js_name, 'class':
                                   'removelink iconspace', 'text':
                                   'Really leave and delete %s' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text': ''})
            output_objects.append({'object_type': 'link', 'destination':
                                   'adminvgrid.py?vgrid_name=%s' % vgrid_name,
                                   'text': 'Back to administration for %s'
                                   % vgrid_name})
            return (output_objects, returnvalues.OK)

        # check if any resources participate or sub-vgrids depend on this one

        (list_status, subs) = vgrid_list_subvgrids(vgrid_name, configuration)

        if not list_status:
            logger.error('Error loading sub-vgrid for %s: %s)' % (vgrid_name,
                                                                  subs))
            output_objects.append({'object_type': 'error_text', 'text': '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text': '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(subs) > 0:
            logger.debug('Cannot delete: still has sub-vgrids: %s' % subs)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s has one or more child %ss and cannot be deleted.' %
                 (vgrid_name, label)})
            output_objects.append(
                {'object_type': 'text', 'text': '''To leave (and delete) %s
first remove all its children: %s.''' % (vgrid_name, ', '.join(subs))})
            return (output_objects, returnvalues.CLIENT_ERROR)

        # we consider the local members and resources here, not inherited ones

        (member_status, members_direct) = vgrid_members(vgrid_name,
                                                        configuration,
                                                        False)
        (resource_status, resources_direct) = vgrid_resources(vgrid_name,
                                                              configuration,
                                                              False)
        if not member_status or not resource_status:
            logger.warning('failed to load %s members or resources: %s %s'
                           % (vgrid_name, members_direct, resources_direct))
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 'could not load %s members or resources for %s.' %
                 (label, vgrid_name)})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        if len(resources_direct) > 0:
            logger.debug('Cannot delete: still has direct resources %s.'
                         % resources_direct)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s still has resources and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text': '''
To leave (and delete) %s, first remove the participating resources.'''
                                   % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(members_direct) > 0:

            logger.debug('Cannot delete: still has direct members %s.'
                         % members_direct)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s still has members and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text': '''
To leave (and delete) %s, first remove all members.'''
                                   % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        # Deleting write restricted VGrid is not allowed

        (load_status, saved_settings) = vgrid_settings(vgrid_name,
                                                       configuration,
                                                       recursive=True,
                                                       as_dict=True)
        if not load_status:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 'failed to load saved %s settings' % vgrid_name})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        if saved_settings.get('write_shared_files', keyword_members) != \
                keyword_members:
            logger.warning("%s can't delete vgrid %s - write limited!"
                           % (client_id, vgrid_name))
            output_objects.append(
                {'object_type': 'error_text', 'text': """You can't delete
write-restricted %ss - first remove any write restrictions for shared files
on the admin page and then try again.""" % label})
            return (output_objects, returnvalues.CLIENT_ERROR)

        # When reaching here, OK to remove the VGrid.
        #   if top-level: unlink, remove all files and directories,
        #   in all cases: remove configuration entry for the VGrid
        #   unlink and move new-style vgrid sub dir to parent

        logger.info('Deleting %s and all related data as requested by %s' %
                    (vgrid_name, cert_id))

        if (cert_id in owners_direct):

            # owner owns this vgrid, direct ownership

            logger.debug('%s looks like a top-level vgrid.' % vgrid_name)
            logger.debug('Deleting all related files.')

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep
            (share_lnk, share_msg) = unlink_share(user_dir, vgrid_name)
            (web_lnk, web_msg) = unlink_web_folders(user_dir, vgrid_name)
            (files_act, files_msg) = abandon_vgrid_files(vgrid_name,
                                                         configuration)
        else:

            # owner owns some parent vgrid - ownership is only inherited

            logger.debug('%s looks like a sub-vgrid, ownership inherited.' %
                         vgrid_name)
            logger.debug('Only removing entry, leaving files in place.')
            share_lnk, share_msg = True, ''
            web_lnk, web_msg = True, ''
            (files_act, files_msg) = inherit_vgrid_files(vgrid_name,
                                                         configuration)

        (removed, entry_msg) = remove_vgrid_entry(vgrid_name, configuration)

        output_objects.append({'object_type': 'text', 'text':
                               '%s has been removed with last owner.'
                               % vgrid_name})

        output_objects.append({'object_type': 'link',
                               'destination': 'vgridman.py',
                               'text': 'Back to the overview.'})

        if not share_lnk or not web_lnk or not files_act or not removed:
            err = '\n'.join([share_msg, web_msg, files_msg, entry_msg])
            logger.error('Errors while removing %s:\n%s.' % (vgrid_name, err))

            output_objects.append({'object_type': 'error_text', 'text': '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text': '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove vgrid from vgrid cache (after deleting all)
            unmap_vgrid(configuration, vgrid_name)
            return (output_objects, returnvalues.OK)
Exemplo n.º 44
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)

    logger.debug("User: %s executing %s" % (client_id, op_name))
    if not configuration.site_enable_jupyter:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'The Jupyter service is not enabled on the system'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    if not configuration.site_enable_sftp_subsys and not \
            configuration.site_enable_sftp:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'The required sftp service is not enabled on the system'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    if configuration.site_enable_sftp:
        sftp_port = configuration.user_sftp_port

    if configuration.site_enable_sftp_subsys:
        sftp_port = configuration.user_sftp_subsys_port

    requested_service = accepted['service'][-1]
    service = {
        k: v
        for options in configuration.jupyter_services
        for k, v in options.items()
        if options['service_name'] == requested_service
    }

    if not service:
        valid_services = [
            options['name'] for options in configuration.jupyter_services
        ]
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s is not a valid jupyter service, '
            'allowed include %s' % (requested_service, valid_services)
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    valid_service = valid_jupyter_service(configuration, service)
    if not valid_service:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'The service %s appears to be misconfigured, '
            'please contact a system administrator about this issue' %
            requested_service
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    host = get_host_from_service(configuration, service)
    # Get an active jupyterhost
    if host is None:
        logger.error("No active jupyterhub host could be found")
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Failed to establish connection to the %s Jupyter service' %
            service['service_name']
        })
        output_objects.append({
            'object_type': 'link',
            'destination': 'jupyter.py',
            'text': 'Back to Jupyter services overview'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    remote_user = unescape(os.environ.get('REMOTE_USER', '')).strip()
    if not remote_user:
        logger.error("Can't connect to jupyter with an empty REMOTE_USER "
                     "environment variable")
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Failed to establish connection to the Jupyter service'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)
    # Ensure the remote_user dict can be http posted
    remote_user = str(remote_user)

    # TODO, activate admin info
    # remote_user = {'USER': username, 'IS_ADMIN': is_admin(client_id,
    #                                                      configuration,
    # logger)}

    # Regular sftp path
    mnt_path = os.path.join(configuration.jupyter_mount_files_dir, client_dir)
    # Subsys sftp path
    subsys_path = os.path.join(configuration.mig_system_files, 'jupyter_mount')
    # sftp session path
    link_home = configuration.sessid_to_jupyter_mount_link_home

    user_home_dir = os.path.join(configuration.user_home, client_dir)

    # Preparing prerequisites
    if not os.path.exists(mnt_path):
        os.makedirs(mnt_path)

    if not os.path.exists(link_home):
        os.makedirs(link_home)

    if configuration.site_enable_sftp_subsys:
        if not os.path.exists(subsys_path):
            os.makedirs(subsys_path)

    # Make sure ssh daemon does not complain
    tighten_key_perms(configuration, client_id)

    url_base = '/' + service['service_name']
    url_home = url_base + '/home'
    url_auth = host + url_base + '/hub/login'
    url_data = host + url_base + '/hub/user-data'

    # Does the client home dir contain an active mount key
    # If so just keep on using it.
    jupyter_mount_files = [
        os.path.join(mnt_path, jfile) for jfile in os.listdir(mnt_path)
        if jfile.endswith('.jupyter_mount')
    ]

    logger.info("User: %s mount files: %s" %
                (client_id, "\n".join(jupyter_mount_files)))
    logger.debug("Remote-User %s" % remote_user)
    active_mounts = []
    for jfile in jupyter_mount_files:
        jupyter_dict = unpickle(jfile, logger)
        if not jupyter_dict:
            # Remove failed unpickle
            logger.error("Failed to unpickle %s removing it" % jfile)
            remove_jupyter_mount(jfile, configuration)
        else:
            # Mount has been timed out
            if not is_active(jupyter_dict):
                remove_jupyter_mount(jfile, configuration)
            else:
                # Valid mount
                active_mounts.append({'path': jfile, 'state': jupyter_dict})

    logger.debug(
        "User: %s active keys: %s" %
        (client_id, "\n".join([mount['path'] for mount in active_mounts])))

    # If multiple are active, remove oldest
    active_mount, old_mounts = get_newest_mount(active_mounts)
    for mount in old_mounts:
        remove_jupyter_mount(mount['path'], configuration)

    # A valid active key is already present redirect straight to the jupyter
    # service, pass most recent mount information
    if active_mount is not None:
        mount_dict = mig_to_mount_adapt(active_mount['state'])
        user_dict = mig_to_user_adapt(active_mount['state'])
        logger.debug("Existing header values, Mount: %s User: %s" %
                     (mount_dict, user_dict))

        auth_header = {'Remote-User': remote_user}
        json_data = {'data': {'Mount': mount_dict, 'User': user_dict}}

        if configuration.site_enable_workflows:
            workflows_dict = mig_to_workflows_adapt(active_mount['state'])
            if not workflows_dict:
                # No cached workflows session could be found -> refresh with a
                # one
                workflow_session_id = get_workflow_session_id(
                    configuration, client_id)
                if not workflow_session_id:
                    workflow_session_id = create_workflow_session_id(
                        configuration, client_id)
                # TODO get this dynamically
                url = configuration.migserver_https_sid_url + \
                    '/cgi-sid/workflowsjsoninterface.py?output_format=json'
                workflows_dict = {
                    'WORKFLOWS_URL': url,
                    'WORKFLOWS_SESSION_ID': workflow_session_id
                }

            logger.debug("Existing header values, Workflows: %s" %
                         workflows_dict)
            json_data['workflows_data'] = {'Session': workflows_dict}

        with requests.session() as session:
            # Authenticate and submit data
            response = session.post(url_auth, headers=auth_header)
            if response.status_code == 200:
                response = session.post(url_data, json=json_data)
                if response.status_code != 200:
                    logger.error(
                        "Jupyter: User %s failed to submit data %s to %s" %
                        (client_id, json_data, url_data))
            else:
                logger.error(
                    "Jupyter: User %s failed to authenticate against %s" %
                    (client_id, url_auth))

        # Redirect client to jupyterhub
        return jupyter_host(configuration, output_objects, remote_user,
                            url_home)

    # Create a new keyset
    # Create login session id
    session_id = generate_random_ascii(2 * session_id_bytes,
                                       charset='0123456789abcdef')

    # Generate private/public keys
    (mount_private_key,
     mount_public_key) = generate_ssh_rsa_key_pair(encode_utf8=True)

    # Known hosts
    sftp_addresses = socket.gethostbyname_ex(
        configuration.user_sftp_show_address or socket.getfqdn())

    # Subsys sftp support
    if configuration.site_enable_sftp_subsys:
        # Restrict possible mount agent
        auth_content = []
        restrict_opts = 'no-agent-forwarding,no-port-forwarding,no-pty,'
        restrict_opts += 'no-user-rc,no-X11-forwarding'
        restrictions = '%s' % restrict_opts
        auth_content.append('%s %s\n' % (restrictions, mount_public_key))
        # Write auth file
        write_file('\n'.join(auth_content),
                   os.path.join(subsys_path, session_id + '.authorized_keys'),
                   logger,
                   umask=027)

    logger.debug("User: %s - Creating a new jupyter mount keyset - "
                 "private_key: %s public_key: %s " %
                 (client_id, mount_private_key, mount_public_key))

    jupyter_dict = {
        'MOUNT_HOST': configuration.short_title,
        'SESSIONID': session_id,
        'USER_CERT': client_id,
        # don't need fraction precision, also not all systems provide fraction
        # precision.
        'CREATED_TIMESTAMP': int(time.time()),
        'MOUNTSSHPRIVATEKEY': mount_private_key,
        'MOUNTSSHPUBLICKEY': mount_public_key,
        # Used by the jupyterhub to know which host to mount against
        'TARGET_MOUNT_ADDR': "@" + sftp_addresses[0] + ":",
        'PORT': sftp_port
    }
    client_email = extract_field(client_id, 'email')
    if client_email:
        jupyter_dict.update({'USER_EMAIL': client_email})

    if configuration.site_enable_workflows:
        workflow_session_id = get_workflow_session_id(configuration, client_id)
        if not workflow_session_id:
            workflow_session_id = create_workflow_session_id(
                configuration, client_id)
        # TODO get this dynamically
        url = configuration.migserver_https_sid_url + \
            '/cgi-sid/workflowsjsoninterface.py?output_format=json'
        jupyter_dict.update({
            'WORKFLOWS_URL': url,
            'WORKFLOWS_SESSION_ID': workflow_session_id
        })

    # Only post the required keys, adapt to API expectations
    mount_dict = mig_to_mount_adapt(jupyter_dict)
    user_dict = mig_to_user_adapt(jupyter_dict)
    workflows_dict = mig_to_workflows_adapt(jupyter_dict)
    logger.debug("User: %s Mount header: %s" % (client_id, mount_dict))
    logger.debug("User: %s User header: %s" % (client_id, user_dict))
    if workflows_dict:
        logger.debug("User: %s Workflows header: %s" %
                     (client_id, workflows_dict))

    # Auth and pass a new set of valid mount keys
    auth_header = {'Remote-User': remote_user}
    json_data = {'data': {'Mount': mount_dict, 'User': user_dict}}
    if workflows_dict:
        json_data['workflows_data'] = {'Session': workflows_dict}

    # First login
    with requests.session() as session:
        # Authenticate
        response = session.post(url_auth, headers=auth_header)
        if response.status_code == 200:
            response = session.post(url_data, json=json_data)
            if response.status_code != 200:
                logger.error(
                    "Jupyter: User %s failed to submit data %s to %s" %
                    (client_id, json_data, url_data))
        else:
            logger.error("Jupyter: User %s failed to authenticate against %s" %
                         (client_id, url_auth))

    # Update pickle with the new valid key
    jupyter_mount_state_path = os.path.join(mnt_path,
                                            session_id + '.jupyter_mount')

    pickle(jupyter_dict, jupyter_mount_state_path, logger)

    # Link jupyter pickle state file
    linkdest_new_jupyter_mount = os.path.join(mnt_path,
                                              session_id + '.jupyter_mount')

    linkloc_new_jupyter_mount = os.path.join(link_home,
                                             session_id + '.jupyter_mount')
    make_symlink(linkdest_new_jupyter_mount, linkloc_new_jupyter_mount, logger)

    # Link userhome
    linkloc_user_home = os.path.join(link_home, session_id)
    make_symlink(user_home_dir, linkloc_user_home, logger)

    return jupyter_host(configuration, output_objects, remote_user, url_home)
Exemplo n.º 45
0
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'] = "Remove %s Resource" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Remove %s Resource' % 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)

    vgrid_name = accepted['vgrid_name'][-1]
    unique_resource_name = accepted['unique_resource_name'][-1].lower()

    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 resources

    (allow_status, allow_msg) = allow_resources_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)

    # 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, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id,
                                  unique_resource_name, 'resource',
                                  configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

        # In case of warnings, msg is non-empty while ret_val remains True

        output_objects.append({'object_type': 'warning', 'text': msg})

    if not vgrid_is_owner(vgrid_name, client_id, configuration):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''You must be an owner of the %s to
remove a resource!''' % label
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not a participant

    if not vgrid_is_resource(vgrid_name, unique_resource_name, configuration):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s is not a resource in %s or a parent %s.' %
            (unique_resource_name, vgrid_name, label)
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # remove

    (rm_status, rm_msg) = vgrid_remove_resources(configuration, vgrid_name,
                                                 [unique_resource_name])
    if not rm_status:
        output_objects.append({'object_type': 'error_text', 'text': rm_msg})
        output_objects.append({
            'object_type': 'error_text',
            'text': '''%(res_name)s might be listed as a resource
of this %(vgrid_label)s because it is a resource of a parent %(vgrid_label)s.
Removal must be performed from the most significant %(vgrid_label)s possible.
''' % {
                'res_name': unique_resource_name,
                'vgrid_label': label
            }
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({
        'object_type':
        'text',
        'text':
        'Resource %s successfully removed from %s %s!' %
        (unique_resource_name, vgrid_name, label)
    })
    output_objects.append({
        'object_type': 'link',
        'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name,
        'text': 'Back to administration for %s' % vgrid_name
    })
    return (output_objects, returnvalues.OK)
Exemplo n.º 46
0
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]
    (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)

    flavor = accepted['flavor'][-1].strip()
    freeze_id = accepted['freeze_id'][-1].strip()

    if not flavor in freeze_flavors.keys():
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Invalid freeze flavor: %s' % flavor
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    title = freeze_flavors[flavor]['adminfreeze_title']
    output_objects.append({'object_type': 'header', 'text': title})
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = title

    if not configuration.site_enable_freeze:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Freezing archives is disabled on this site.
Please contact the site admins %s if you think it should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    # Load existing freeze for stepwise construction if requested
    freeze_dict = {'ID': freeze_id, 'FLAVOR': flavor}
    if freeze_id != keyword_auto:
        (load_status, freeze_dict) = get_frozen_archive(client_id,
                                                        freeze_id,
                                                        configuration,
                                                        checksum_list=[])
        if not load_status:
            logger.error("%s: load failed for '%s': %s" %
                         (op_name, freeze_id, brief_freeze(freeze_dict)))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not read details for "%s"' % freeze_id
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        logger.debug("%s: loaded freeze: %s" %
                     (op_name, brief_freeze(freeze_dict)))

        # Preserve already saved flavor
        flavor = freeze_dict.get('FLAVOR', 'freeze')

        freeze_state = freeze_dict.get('STATE', keyword_final)
        if freeze_state == keyword_final:
            logger.error("%s tried to edit finalized %s archive %s" %
                         (client_id, flavor, freeze_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'You cannot edit finalized %s archive %s' % (flavor, freeze_id)
            })
            output_objects.append({
                'object_type':
                'link',
                'destination':
                'showfreeze.py?freeze_id=%s;flavor=%s' % (freeze_id, flavor),
                'class':
                'viewarchivelink iconspace genericbutton',
                'title':
                'View details about your %s archive' % flavor,
                'text':
                'View details',
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        elif freeze_state == keyword_updating:
            logger.error("%s tried to edit %s archive %s under update" %
                         (client_id, flavor, freeze_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'You cannot edit %s archive %s until active update completes' %
                (flavor, freeze_id)
            })
            output_objects.append({
                'object_type':
                'link',
                'destination':
                'showfreeze.py?freeze_id=%s;flavor=%s' % (freeze_id, flavor),
                'class':
                'viewarchivelink iconspace genericbutton',
                'title':
                'View details about your %s archive' % flavor,
                'text':
                'View details',
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'flavor': flavor,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    target_op = 'uploadchunked'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token})
    lookup_map = {
        'freeze_id': 'ID',
        'freeze_name': 'NAME',
        'freeze_author': 'AUTHOR',
        'freeze_description': 'DESCRIPTION'
    }
    for (key, val) in lookup_map.items():
        fill_helpers[key] = freeze_dict.get(val, '')
    fill_helpers['publish_value'] = 'no'
    if freeze_dict.get('PUBLISH', False):
        fill_helpers['publish_value'] = 'yes'

    # jquery fancy upload

    (add_import, add_init, add_ready) = fancy_upload_js(configuration,
                                                        csrf_token=csrf_token)

    # We need filechooser deps and dynamic addition of copy/upload fields

    add_import += '''
<script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="/images/js/jquery.prettyprint.js"></script>
<script type="text/javascript" src="/images/js/jquery.contextmenu.js"></script>
<script type="text/javascript" src="/images/js/jquery.xbreadcrumbs.js"></script>
<!-- The preview image plugin -->
<script type="text/javascript" src="/images/js/preview.js"></script>
<!-- The image manipulation CamanJS plugin used by the preview image plugin -->
<script type="text/javascript" src="/images/lib/CamanJS/dist/caman.full.js"></script>
<!-- The nouislider plugin used by the preview image plugin -->
<script type="text/javascript" src="/images/lib/noUiSlider/jquery.nouislider.all.js"></script>
    '''
    add_init += '''
Caman.DEBUG = false

var copy_fields = 0;
var upload_fields = 0;
var open_file_chooser;
var open_upload_dialog;
/* default upload destination */
var remote_path = "%s";
var trash_linkname = "%s";
var copy_div_id = "copyfiles";
var upload_div_id = "uploadfiles";
/* for upload_callback */
var field_id, field_name, wrap_id, upload_path, on_remove;

function add_copy() {
    var div_id = copy_div_id;
    var field_id = "freeze_copy_"+copy_fields;
    var field_name = "freeze_copy_"+copy_fields;
    var wrap_id = field_id+"_wrap";
    var browse_id = field_id+"_browse";
    copy_entry = "<span id=\'"+wrap_id+"\'>";
    copy_entry += "<input type=\'button\' value=\'Remove\' ";
    copy_entry += " onClick=\'remove_field(\"+wrap_id+\");\'/>";
    // add browse button to mimic upload field
    copy_entry += "<input type=\'button\' id=\'"+browse_id+"\' ";
    copy_entry += " value=\'Browse...\' />";
    copy_entry += "<input type=\'text\' id=\'"+field_id+"\' ";
    copy_entry += " name=\'" + field_name + "\' size=80 /><br / >";
    copy_entry += "</span>";

    $("#"+div_id).append(copy_entry);
    $("#"+field_id).click(function() {
        open_file_chooser("Add file or directory (right click to select)",
            function(file) {
                $("#"+field_id).val(file);
            });
    });
    $("#"+browse_id).click(function() {
         $("#"+field_id).click();
    });
    $("#"+field_id).click();
    copy_fields += 1;
}

function upload_callback() {
    var div_id = upload_div_id;
    console.log("in upload callback");
    $(".uploadfileslist > tr > td > p.name > a").each(
        function(index) {
            console.log("callback for upload item no. "+index);
            upload_path = $(this).text();
            if ($(this).attr("href") == "") {
                console.log("skipping empty (error) upload: "+upload_path);
                // Continue to next iteration on errors
                return true;
            }
            console.log("callback for upload path "+upload_path);
            field_id = "freeze_move_"+upload_fields;
            field_name = "freeze_move_"+upload_fields;
            wrap_id = field_id+"_wrap";
            if ($("#"+div_id+" > span > input[value=\\""+upload_path+"\\"]").length) {
                console.log("skipping duplicate path: "+upload_path);
                // Continue to next iteration on errors
                return true;
            } else {
                console.log("adding new path: "+upload_path);
            }
            on_remove = "";
            on_remove += "remove_field("+wrap_id+");";
            on_remove += "$.fn.delete_upload(\\""+upload_path+"\\");";
            upload_entry = "<span id=\'"+wrap_id+"\'>";
            upload_entry += "<input type=\'button\' value=\'Remove\' ";
            upload_entry += " onClick=\'"+on_remove+"\'/>";
            upload_entry += "<input type=\'text\' id=\'"+field_id+"\' ";
            upload_entry += " name=\'" + field_name + "\' size=50 ";
            upload_entry += "value=\\""+upload_path+"\\" /><br / >";
            upload_entry += "</span>";
            $("#"+div_id).append(upload_entry);
            console.log("callback added upload: "+upload_entry);
            upload_fields += 1;
        });
    console.log("callback done");
}

function add_upload() {
    openFancyUpload("Upload Files", upload_callback, "", remote_path, true,
                    "", "%s");
}

function remove_field(field_id) {
    $(field_id).remove();
}

// init file chooser dialogs with directory selection support
function init_dialogs() {
    open_file_chooser = mig_filechooser_init("fm_filechooser",
        function(file) {
            return;
        }, false, "/");
    /* We reuse shared init function but use custom actual opener above
    to mangle resulting files into archive form. */
    initFancyUpload();
    /* Alias open_dialog to open_upload_dialog for clarity */
    open_upload_dialog = open_dialog;

    $("#addfilebutton").click(function() { add_copy(); });
    $("#adduploadbutton").click(function() { add_upload(); });
}

function init_page() {
    init_dialogs();
}

    ''' % (upload_tmp_dir, trash_linkname, csrf_token)
    add_ready += '''
         // do sequenced initialisation (separate function)
         init_page();
    '''

    # TODO: can we update style inline to avoid explicit themed_styles?
    title_entry['style'] = themed_styles(
        configuration,
        base=[
            'jquery.contextmenu.css', 'jquery.managers.contextmenu.css',
            'jquery.xbreadcrumbs.css', 'jquery.fmbreadcrumbs.css',
            'jquery.fileupload.css', 'jquery.fileupload-ui.css'
        ],
        skin=['fileupload-ui.custom.css', 'xbreadcrumbs.custom.css'],
        user_settings=title_entry.get('user_settings', {}))
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready

    if flavor == 'freeze':
        fill_helpers['freeze_name'] = fill_helpers.get('freeze_name', '')
        fill_helpers["archive_header"] = "Freeze Archive Files"
        fill_helpers["button_label"] = "Save and Preview"
        intro_text = """
Please enter your archive details below and select any files to be included in
the archive.
"""
    elif flavor == 'phd':
        fill_helpers['freeze_name'] = fill_helpers.get('freeze_name', '')
        fill_helpers[
            "archive_header"] = "Thesis and Associated Files to Archive"
        fill_helpers["button_label"] = "Save and Preview"
        intro_text = """
Please enter your PhD details below and select any files associated with your
thesis.
"""
    elif flavor == 'backup':
        fill_helpers['freeze_name'] = fill_helpers.get('freeze_name', '')
        if not fill_helpers['freeze_name']:
            now = datetime.datetime.now().isoformat().replace(':', '')
            fill_helpers['freeze_name'] = 'backup-%s' % now
        fill_helpers["archive_header"] = "Files and folders to Archive"
        fill_helpers["button_label"] = "Save and Preview"
        intro_text = """
Please select the files and folders to backup below.
"""
    else:
        output_objects.append({
            'object_type': 'error_text',
            'text': "unknown flavor: %s" % flavor
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # Only warn here if default state is final and persistent
    if freeze_flavors[flavor]['states'][0] == keyword_final and \
            flavor in configuration.site_permanent_freeze:
        intro_text += """
<p class='warn_message'>Note that frozen archives <em>cannot</em> be changed
after final creation and then they can only be manually removed by management,
so please be careful when filling in the details.
</p>
"""

    fill_helpers["fancy_dialog"] = fancy_upload_html(configuration)

    files_form = """
<!-- and now this... we do not want to see it, except in a dialog: -->
<div id='fm_filechooser' style='display:none'>
    <div class='tree-container container-fluid'>
        <div class='tree-row row'>
            <div class='tree-header col-3'></div>
            <div class='fm_path_breadcrumbs col-6'>
                <ul id='fm_xbreadcrumbs' class='xbreadcrumbs'><!-- dynamic --></ul>
            </div>
            <div class='fm_buttonbar col-3 d-none d-lg-block'>
                <ul id='fm_buttons' class='buttonbar'>
                    <!-- dynamically modified by js to show optional buttons -->
                    <li class='datatransfersbutton hidden' title='Manage Data Transfers'>&nbsp;</li>
                    <li class='sharelinksbutton hidden' title='Manage Share Links'>&nbsp;</li>
                    <li class='parentdirbutton' title='Open Parent Directory'>&nbsp;</li>
                    <li class='refreshbutton' title='Refresh'>&nbsp;</li>
                </ul>
            </div>
            <div class='fm_buttonbar-big col-6 d-block d-lg-none hidden'>
                <ul id='fm_buttons' class='buttonbar'>
                    <!-- dynamically modified by js to show optional buttons -->
                    <li class='datatransfersbutton hidden' title='Manage Data Transfers'>&nbsp;</li>
                    <li class='sharelinksbutton hidden' title='Manage Share Links'>&nbsp;</li>
                    <li class='parentdirbutton' title='Open Parent Directory'>&nbsp;</li>
                    <li class='refreshbutton' title='Refresh'>&nbsp;</li>
                </ul>
            </div>
        </div>
    </div>
    <div class='fm_addressbar'>
        <input type='hidden' value='/' name='fm_current_path' />
    </div>
    <div class='fm_folders'>
        <ul class='jqueryFileTree'>
            <li class='directory expanded'>
                <a>...</a>
            </li>
        </ul>
    </div>
    <div class='fm_files'>
        <table id='fm_filelisting' style='font-size:13px; border-spacing=0;'>
            <thead>
                <tr>
                    <th class='fm_name'>Name</th>
                    <th class='fm_size'>Size</th>
                    <th class='fm_type'>Type</th>
                    <th class='fm_date'>Date Modified</th>
                    <th class='fm_toolbox'>...</th>
                </tr>
            </thead>
            <tbody>
                <!-- this is a placeholder for contents: do not remove! -->
            </tbody>
         </table>
    </div>
    <div id='fm_statusbar' class='col-lg-12'>
        <div id='fm_statusprogress' class=' col-lg-3'>
            <div class='progress-label'>Loading...</div>
        </div>
        <div id='fm_statusinfo' class='col-lg-9'>&nbsp;</div>
    </div>
</div>
<div id='cmd_dialog' title='Command output' style='display: none;'></div>

%(fancy_dialog)s
    """ % fill_helpers

    target_op = 'createfreeze'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token})

    freeze_form = """
<form enctype='multipart/form-data' method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type='hidden' name='flavor' value='%(flavor)s' />
<input type='hidden' name='freeze_id' value='%(freeze_id)s' />
<b>Name:</b><br />
<input class='fillwidth padspace' type='text' name='freeze_name'
    value='%(freeze_name)s' autofocus required pattern='[a-zA-Z0-9_. -]+'
    title='unique name for the freeze archive. I.e. letters and digits separated only by spaces, underscores, periods and hyphens' />
"""
    if flavor != 'backup':
        # TODO: do these make sense to have here or just forced in backend?
        freeze_form += """
<input type='hidden' name='freeze_department' value='' />
<input type='hidden' name='freeze_organization' value='' />
<br><b>Author(s):</b><br />
<input class='fillwidth padspace' type='text' name='freeze_author'
    value='%(freeze_author)s' title='optional archive author(s) in case archive is created on behalf of one or more people' />
<br /><b>Description:</b><br />
<textarea class='fillwidth padspace' rows='20' name='freeze_description'>%(freeze_description)s</textarea>
<br />
"""
    freeze_form += """
<br />
<div id='freezefiles'>
<b>%(archive_header)s:</b><br/>
"""
    freeze_form += """
<input type='button' id='addfilebutton' value='Add file/directory' />
"""
    if flavor != 'backup':
        freeze_form += """
<input type='button' id='adduploadbutton' value='Add upload' />
"""
    freeze_form += """
<div id='copyfiles'>
<!-- Dynamically filled -->
</div>
"""
    if flavor != 'backup':
        freeze_form += """
<div id='uploadfiles'>
<!-- Dynamically filled -->
</div>
"""
    freeze_form += """
</div>
<br />
"""
    if flavor != 'backup':
        freeze_form += """
<div id='freezepublish'>
<b>Make Dataset Publicly Available</b>
"""
        for val in ('yes', 'no'):
            checked = ''
            if fill_helpers['publish_value'] == val:
                checked = 'checked="checked"'
            freeze_form += """
<input type='radio' name='freeze_publish' value='%s' %s />%s
""" % (val, checked, val)
        freeze_form += """
</div>
<br />
"""
    freeze_form += """
<input type='submit' value='%(button_label)s' />
</form>
"""

    # TODO: consider in-lining showfreeze file table for direct modify instead
    #       probably requires more AJAX handling of actions.

    # for rel_path in frozen_files:
    #    freeze_form += """%s<br/>""" % rel_path

    output_objects.append({'object_type': 'html_form', 'text': intro_text})
    output_objects.append({'object_type': 'html_form', 'text': files_form})
    output_objects.append({
        'object_type': 'html_form',
        'text': freeze_form % fill_helpers
    })

    # Link to view if archive already exists
    if freeze_id != keyword_auto:
        frozen_files = [
            i['name'] for i in freeze_dict.get('FILES', [])
            if i['name'] != public_archive_index
        ]
        # Info about contents and spacing before view button otherwise
        if frozen_files:
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """
<h3>Previously Added Files</h3>
<p>There are already %d file(s) saved in the archive and you can view and
manage those through the link below e.g. in case you change your mind
about including any of them.
</p>""" % len(frozen_files)
            })
        else:
            output_objects.append({'object_type': 'text', 'text': ''})

        output_objects.append({
            'object_type':
            'link',
            'destination':
            'showfreeze.py?freeze_id=%s;flavor=%s' % (freeze_id, flavor),
            'class':
            'viewarchivelink iconspace genericbutton',
            'title':
            'View details about your %s archive' % flavor,
            'text':
            'View details',
            'target':
            '_blank',
        })

    # Spacing
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
            <div class="vertical-spacer"></div>
    '''
    })

    return (output_objects, returnvalues.OK)
Exemplo n.º 47
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (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)

    flags = ''.join(accepted['flags'])
    patterns = accepted['path']
    current_dir = accepted['current_dir']

    # 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

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    if verbose(flags):
        for flag in flags:
            output_objects.append({'object_type': 'text', 'text'
                                  : '%s using flag: %s' % (op_name,
                                  flag)})

    for pattern in patterns:

        # Check directory traversal attempts before actual handling to avoid
        # leaking information about file system layout while allowing
        # consistent error messages
        # NB: Globbing disabled on purpose here

        unfiltered_match = [base_dir + pattern]
        match = []
        for server_path in unfiltered_match:
            real_path = os.path.abspath(server_path)
            if not valid_user_path(real_path, base_dir, True):

                # out of bounds - save user warning for later to allow
                # partial match:
                # ../*/* is technically allowed to match own files.

                logger.warning('%s tried to %s restricted path %s ! (%s)'
                               % (client_id, op_name, real_path, pattern))
                continue
            match.append(real_path)

        # Now actually treat list of allowed matchings and notify if no
        # (allowed) match

        if not match:
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : "%s: cannot remove directory '%s': Permission denied"
                 % (op_name, pattern)})
            status = returnvalues.CLIENT_ERROR

        for real_path in match:
            relative_path = real_path.replace(base_dir, '')
            if verbose(flags):
                output_objects.append({'object_type': 'file', 'name'
                        : relative_path})
            if not os.path.exists(real_path):
                output_objects.append({'object_type': 'file_not_found',
                        'name': relative_path})
                continue
            try:
                if parents(flags):

                    # Please note that 'rmdir -p X' should give error if X
                    #  doesn't exist contrary to 'mkdir -p X' not giving error
                    # if X exists.

                    os.removedirs(real_path)
                else:
                    os.rmdir(real_path)
            except Exception, exc:
                output_objects.append({'object_type': 'error_text',
                        'text': "%s failed on '%s'" % (op_name,
                        relative_path)})
                logger.error("%s: failed on '%s': %s" % (op_name,
                             relative_path, exc))
                status = returnvalues.SYSTEM_ERROR
                continue
Exemplo n.º 48
0
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, op_menu=False)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s certificate request' % configuration.short_title
    title_entry['skipmenu'] = True
    output_objects.append({'object_type': 'header', 'text'
                          : '%s certificate request' % \
                            configuration.short_title 
                           })

    admin_email = configuration.admin_email
    smtp_server = configuration.smtp_server
    user_pending = os.path.abspath(configuration.user_pending)

    # force name to capitalized form (henrik karlsen -> Henrik Karlsen)
    # please note that we get utf8 coded bytes here and title() treats such
    # chars as word termination. Temporarily force to unicode.

    raw_name = accepted['cert_name'][-1].strip() 
    try:
        cert_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        cert_name = raw_name.title()
    country = accepted['country'][-1].strip().upper()
    state = accepted['state'][-1].strip().title()
    org = accepted['org'][-1].strip()

    # lower case email address

    email = accepted['email'][-1].strip().lower()
    password = accepted['password'][-1]
    verifypassword = accepted['verifypassword'][-1]

    # keep comment to a single line

    comment = accepted['comment'][-1].replace('\n', '   ')

    # single quotes break command line format - remove

    comment = comment.replace("'", ' ')

    if password != verifypassword:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Password and verify password are not identical!'
                              })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # TODO: move this check to conf?

    if not forced_org_email_match(org, email, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''Illegal email and organization combination:
Please read and follow the instructions in red on the request page!
If you are a student with only a @*.ku.dk address please just use KU as
organization. As long as you state that you want the certificate for course
purposes in the comment field, you will be given access to the necessary
resources anyway.
'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_dict = {
        'full_name': cert_name,
        'organization': org,
        'state': state,
        'country': country,
        'email': email,
        'comment': comment,
        'password': base64.b64encode(password),
        'expire': int(time.time() + cert_valid_days * 24 * 60 * 60),
        'openid_names': [],
        }
    fill_distinguished_name(user_dict)
    user_id = user_dict['distinguished_name']
    user_dict['authorized'] = (user_id == client_id)
    if configuration.user_openid_providers and configuration.user_openid_alias:
        user_dict['openid_names'] += \
                                  [user_dict[configuration.user_openid_alias]]
    logger.info('got reqcert request: %s' % user_dict)

    # For testing only
    
    if cert_name.upper().find('DO NOT SEND') != -1:
        output_objects.append({'object_type': 'text', 'text'
                          : "Test request ignored!"})
        return (output_objects, returnvalues.OK)

    req_path = None
    try:
        (os_fd, req_path) = tempfile.mkstemp(dir=user_pending)
        os.write(os_fd, dumps(user_dict))
        os.close(os_fd)
    except Exception, err:
        logger.error('Failed to write certificate request to %s: %s'
                      % (req_path, err))
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Request could not be sent to grid administrators. Please contact them manually on %s if this error persists.'
                               % admin_email})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Exemplo n.º 49
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    output_objects.append({
        'object_type': 'text',
        'text': '--------- Trying to STOP store ----------'
    })

    defaults = signature()[1]
    (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)

    unique_resource_name = accepted['unique_resource_name'][-1]
    store_name_list = accepted['store_name']
    all = accepted['all'][-1].lower() == 'true'
    parallel = accepted['parallel'][-1].lower() == 'true'

    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)

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Failure: You must be an owner of ' + unique_resource_name +
            ' to stop the store!'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    exit_status = returnvalues.OK

    if all:
        store_name_list = get_all_store_names(unique_resource_name)

    # take action based on supplied list of stores

    if len(store_name_list) == 0:
        output_objects.append({
            'object_type':
            'text',
            'text':
            "No stores specified and 'all' argument not set to true: Nothing to do!"
        })

    workers = []
    for store_name in store_name_list:
        task = Worker(target=stop_resource_store,
                      args=(unique_resource_name, store_name,
                            configuration.resource_home, logger))
        workers.append((store_name, [task]))
        task.start()
        if not parallel:
            task.join()

    for (store_name, task_list) in workers:
        (status, msg) = task_list[0].finish()
        output_objects.append({'object_type': 'header', 'text': 'Stop store'})
        if not status:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'Problems stopping store: %s' % msg
            })
            exit_status = returnvalues.SYSTEM_ERROR
        else:
            output_objects.append({
                'object_type': 'text',
                'text': 'Stop store success: %s' % msg
            })
    return (output_objects, exit_status)
Exemplo n.º 50
0
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'
                          : 'Remove %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]
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)

    # 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 remove if not a member

    if not vgrid_is_member(vgrid_name, cert_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not a member of %s or a parent %s.'
                               % (cert_id, vgrid_name,
                                  configuration.site_vgrid_label)})
        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)

    # 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 removing 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)

    # 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

    # remove symlink from users home directory to vgrid directory

    # 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

    dst = user_dir + vgrid_name
    try:
        os.remove(dst)
    except Exception, exc:

        # ouch, not good. Email admin?

        pass
Exemplo n.º 51
0
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, op_menu=False)
    logger = configuration.logger
    logger.info('oiddiscover: %s' % user_arguments_dict)    
    output_objects.append({'object_type': 'header', 'text'
                          : 'OpenID Discovery for %s' % \
                           configuration.short_title})
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    # Force to raw file output unless something else is explicitly requested
    raw_output = False
    if os.environ['QUERY_STRING'].find('output_format') == -1:
        raw_output = True
        user_arguments_dict['output_format'] = ['file']

    discovery_doc = '''<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
    <XRD>
        <Service priority="1">
            <Type>http://specs.openid.net/auth/2.0/return_to</Type>
            %s
        </Service>
    </XRD>
</xrds:XRDS>
'''

    if configuration.site_enable_openid:
        # TMP! add own openid server realm as well
        sid_url = configuration.migserver_https_sid_url
        oid_url = configuration.migserver_https_oid_url
        helper_urls = {
            'migoid_entry_url': os.path.join(sid_url),
            'migoid_signup_url': os.path.join(sid_url, 'cgi-sid', 'signup.py'),
            'migoid_login_url': os.path.join(sid_url, 'cgi-sid', 'login.py'),
            'migoid_create_url': os.path.join(sid_url, 'wsgi-bin',
                                              'autocreate.py'),
            'migoid_dash_url': os.path.join(sid_url, 'wsgi-bin',
                                            'dashboard.py'),
            'migoid_files_url': os.path.join(sid_url, 'wsgi-bin',
                                             'fileman.py'),
            'kitoid_entry_url': os.path.join(oid_url),
            'kitoid_signup_url': os.path.join(oid_url, 'cgi-sid', 'signup.py'),
            'kitoid_login_url': os.path.join(oid_url, 'cgi-sid', 'login.py'),
            'kitoid_create_url': os.path.join(oid_url, 'cgi-sid',
                                              'autocreate.py'),
            'kitoid_dash_url': os.path.join(oid_url, 'wsgi-bin',
                                            'dashboard.py'),
            'kitoid_files_url': os.path.join(oid_url, 'wsgi-bin',
                                             'fileman.py')}
        discovery_uris = '''<URI>%(kitoid_entry_url)s</URI>
            <URI>%(kitoid_signup_url)s</URI>
            <URI>%(kitoid_login_url)s</URI>
            <URI>%(kitoid_create_url)s</URI>
            <URI>%(kitoid_dash_url)s</URI>
            <URI>%(kitoid_files_url)s</URI>
            <URI>%(migoid_entry_url)s</URI>
            <URI>%(migoid_signup_url)s</URI>
            <URI>%(migoid_login_url)s</URI>
            <URI>%(migoid_create_url)s</URI>
            <URI>%(migoid_dash_url)s</URI>
            <URI>%(migoid_files_url)s</URI>
''' % helper_urls
    else:
        discovery_uris = ''

    output_objects.append({'object_type': 'text', 'text':
                           'Advertising valid OpenID endpoints:'})

    discovery_doc = discovery_doc % discovery_uris
    if raw_output:
        headers = [('Content-Type', 'application/xrds+xml'),
                   ('Content-Disposition', 'attachment; filename=oid.xrds'),
                   ('Content-Length', '%s' % len(discovery_doc))]
        output_objects = [{'object_type': 'start', 'headers': headers}]
        output_objects.append({'object_type': 'binary', 'data': discovery_doc})
        return (output_objects, returnvalues.OK)
    else:
        # output discovery_doc as raw xrds doc in any case
        output_objects.append({'object_type': 'file_output', 'lines':
                               [discovery_doc]})
    return (output_objects, returnvalues.OK)
Exemplo n.º 52
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (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)

    flags = ''.join(accepted['flags'])
    lines = int(accepted['lines'][-1])
    pattern_list = accepted['path']

    # 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

    base_dir = os.path.abspath(
        os.path.join(configuration.user_home, client_dir)) + os.sep

    if verbose(flags):
        for flag in flags:
            output_objects.append({
                'object_type': 'text',
                'text': '%s using flag: %s' % (op_name, flag)
            })

    for pattern in pattern_list:

        # Check directory traversal attempts before actual handling to avoid
        # leaking information about file system layout while allowing
        # consistent error messages

        unfiltered_match = glob.glob(base_dir + pattern)
        match = []
        for server_path in unfiltered_match:
            # IMPORTANT: path must be expanded to abs for proper chrooting
            abs_path = os.path.abspath(server_path)
            if not valid_user_path(configuration, abs_path, base_dir, True):

                # out of bounds - save user warning for later to allow
                # partial match:
                # ../*/* is technically allowed to match own files.

                logger.warning('%s tried to %s restricted path %s ! (%s)' %
                               (client_id, op_name, abs_path, pattern))
                continue
            match.append(abs_path)

        # Now actually treat list of allowed matchings and notify if no
        # (allowed) match

        if not match:
            output_objects.append({
                'object_type': 'file_not_found',
                'name': pattern
            })
            status = returnvalues.FILE_NOT_FOUND

        for abs_path in match:
            relative_path = abs_path.replace(base_dir, '')
            output_lines = []

            # We search for the last 'lines' lines by beginning from the end of
            # the file and exponetially backtracking until the backtrack
            # contains at least 'lines' lines or we're back to the beginning of
            # the file.
            # At that point we skip any extra lines before printing.

            try:
                filedes = open(abs_path, 'r')

                # Go to end of file and backtrack

                backstep = 1
                newlines = 0
                filedes.seek(0, 2)
                length = filedes.tell()
                while backstep < length and newlines <= lines:
                    backstep *= 2
                    if backstep > length:
                        backstep = length
                    filedes.seek(-backstep, 2)
                    newlines = len(filedes.readlines())
                if length:

                    # Go back after reading to end of file

                    filedes.seek(-backstep, 2)

                # Skip any extra lines caused by the exponential backtracking.
                # We could probably speed up convergence with binary search...

                while newlines > lines:
                    dummy = filedes.readline()
                    newlines -= 1
                backstep = length - filedes.tell()

                # Now we're at the wanted spot - print rest of file

                for _ in range(newlines):
                    output_lines.append(filedes.readline())
                filedes.close()
            except Exception, exc:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    "%s: '%s': %s" % (op_name, relative_path, exc)
                })
                logger.error("%s: failed on '%s': %s" %
                             (op_name, relative_path, exc))
                status = returnvalues.SYSTEM_ERROR
                continue
            entry = {
                'object_type': 'file_output',
                'lines': output_lines,
                'wrap_binary': binary(flags),
                'wrap_targets': ['lines']
            }
            if verbose(flags):
                entry['path'] = relative_path
            output_objects.append(entry)
Exemplo n.º 53
0
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)
Exemplo n.º 54
0
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,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                        : '%s One-click resource' % configuration.short_title
                          })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    debug = ('true' == accepted['debug'][0].lower())
    console = ('true' == accepted['console'][0].lower())

    if not configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'text', 'text':
                               '''Sandbox resources are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)


    (status, result) = get_resource(client_id, configuration, logger)
    if not status:
        output_objects.append({'object_type': 'html_form', 'text'
                              : result})
        return (output_objects, returnvalues.CLIENT_ERROR)

    fields = {
        'sandboxkey': result[0],
        'resource_name': result[1],
        'cookie': result[2],
        'cputime': result[3],
        'codebase': '%s/sid_redirect/%s.oneclick/'\
             % (configuration.migserver_https_sid_url, result[0]),
        'oneclick_code': 'MiG.oneclick.Applet.class',
        'resource_code': 'MiG.oneclick.Resource.class',
        'oneclick_archive': 'MiGOneClickCodebase.jar',
        'info_code': 'JavaInfoApplet.class',
        'info_archive': '',
        'server': configuration.migserver_https_sid_url,
        'site' : configuration.short_title,
        }

    if debug:
        body = """
DEBUG input vars:
%s
""" % fields
        output_objects.append({'object_type': 'text', 'text': body})

    elif console:
        body = \
                 """
codebase: %(codebase)s
code: %(resource_code)s
archive: %(oneclick_archive)s
server: %(server)s
sandboxkey: %(sandboxkey)s
resource_name: %(resource_name)s
cputime: %(cputime)s
        """ % fields
        output_objects.append({'object_type': 'text', 'text'
                                   : body})
    else:
        body = """
        <object type='application/x-java-applet' height='600' width='800'>
        <param name='codebase' value='%(codebase)s' />
        <param name='code' value='%(oneclick_code)s' />
        <param name='archive' value='%(oneclick_archive)s' />
        <param name='server' value='%(server)s'>
        <param name='sandboxkey' value='%(sandboxkey)s'>
        <param name='resource_name' value='%(resource_name)s'>
        <param name='cputime' value='%(cputime)s'>
        OneClick applet failed to run (requires Java plug-in).
        </object>
        <p>
        Your computer will act as a %(site)s One-click resource as long as this browser
        window/tab remains open.
        </p>
        <h3>Java requirements and background</h3>
        Please note that if you get no applet picture above with status text,
        it is a likely indicator that you do not have the required Java plugin installed in your
        browser. You can download and install it from
        <a class='urllink' href='http://www.java.com/en/download/manual.jsp'>Sun Java Downloads</a>. The browser
        probably needs to be restarted after the installation before the plugin will be enabled.<br />
        Other Java implementations may <i>appear</i> to work but not really deliver job results correctly, so if you want to be sure, please install the Sun Java plugin.
        <br />
        Your browser provides the following Java information:<br />
        <object type='application/x-java-applet' height='60' width='400'>
        <param name='codebase' value='%(codebase)s' />
        <param name='code' value='%(info_code)s' />
        Java plugin not installed or disabled.
        </object>
        """ % fields
        output_objects.append({'object_type': 'html_form', 'text'
                               : body})

    return (output_objects, returnvalues.OK)
Exemplo n.º 55
0
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)
    output_objects.append({
        'object_type':
        'header',
        'text':
        '%s Virtual Desktop' % configuration.short_title
    })
    status = returnvalues.OK
    defaults = signature()[1]
    (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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Virtual Machines'

    if not configuration.site_enable_vmachines:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Virtual machines are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    settings_dict = load_settings(client_id, configuration)
    if not settings_dict or not settings_dict.has_key('VNCDISPLAY'):
        logger.info(
            'Settings dict does not have VNCDISPLAY key - using default')
        (vnc_display_width, vnc_display_height) = (1024, 768)
    else:
        (vnc_display_width, vnc_display_height) = settings_dict['VNCDISPLAY']

    # Make room for vnc control menu

    vnc_menu_height = 24
    vnc_display_height += vnc_menu_height
    password = vms.vnc_jobid(accepted['job_id'][0])
    mig_cert_base = configuration.migserver_https_mig_cert_url
    ext_cert_base = configuration.migserver_https_ext_cert_url
    mig_oid_base = configuration.migserver_https_mig_oid_url
    ext_oid_base = configuration.migserver_https_ext_oid_url
    if os.environ['REQUEST_URI'].startswith(mig_cert_base):
        https_base = mig_cert_base
    elif os.environ['REQUEST_URI'].startswith(ext_cert_base):
        https_base = ext_cert_base
    elif os.environ['REQUEST_URI'].startswith(mig_oid_base):
        https_base = mig_oid_base
    elif os.environ['REQUEST_URI'].startswith(ext_oid_base):
        https_base = ext_oid_base
    else:
        logger.warning("unexpected REQUEST_URI: %(REQUEST_URI)s" % os.environ)
        https_base = mig_cert_base

    # Do an "intoN" then map to acsii

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        vms.popup_snippet() + vms.vnc_applet(
            configuration,
            vnc_display_width,
            vnc_display_height,
            password,
            https_base,
        )
    })
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<p>You can access your virtual machine with the Java applet above if
your browser supports it, or by using a stand-alone VNC client and the following
connection details:<br />
VNC server: %s<br />
VNC port: %s<br />
VNC password: %s<br/>
as an example if you use the xtightvnc client the command line would be
<br/>
<tt>
xtightvncviewer %s::%d
</tt>
<br/>
using the password above when prompted.<br/>
VNC does not use encryption so please be careful where you use it from and
preferably use an SSH tunnel to at least encrypt the connection if accessing
this site over the Internet.<br/>
Please refer to the documentation on the <em>-via</em> VNC option for details.
</p>
""" % (configuration.server_fqdn, configuration.vm_client_port, password,
       configuration.server_fqdn, configuration.vm_client_port)
    })

    return (output_objects, status)
Exemplo n.º 56
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Add/Update %s Trigger" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Add/Update %s Trigger' % 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)

    # NOTE: strip leftmost slashes from all fields used in file paths to avoid
    # interference with os.path.join calls. Furthermore we strip and normalize
    # the path variable first to make sure it does not point outside the vgrid.
    # In practice any such directory traversal attempts will generally be moot
    # since the grid_events daemon only starts a listener for each top-level
    # vgrid and in there only reacts to events that match trigger rules from
    # that particular vgrid. Thus only subvgrid access to parent vgrids might
    # be a concern and still of limited consequence.
    # NOTE: merge multi args into one string and split again to get flat array
    rule_id = accepted['rule_id'][-1].strip()
    vgrid_name = accepted['vgrid_name'][-1].strip().lstrip(os.sep)
    path = os.path.normpath(accepted['path'][-1].strip()).lstrip(os.sep)
    changes = [i.strip() for i in ' '.join(accepted['changes']).split()]
    action = accepted['action'][-1].strip()
    arguments = [
        i.strip() for i in shlex.split(' '.join(accepted['arguments']))
    ]
    rate_limit = accepted['rate_limit'][-1].strip()
    settle_time = accepted['settle_time'][-1].strip()
    match_files = accepted['match_files'][-1].strip() == 'True'
    match_dirs = accepted['match_dirs'][-1].strip() == 'True'
    match_recursive = accepted['match_recursive'][-1].strip() == 'True'
    rank_str = accepted['rank'][-1]
    try:
        rank = int(rank_str)
    except ValueError:
        rank = None

    logger.debug("addvgridtrigger with args: %s" % user_arguments_dict)

    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)

    # 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

    base_dir = os.path.abspath(
        os.path.join(configuration.user_home, client_dir)) + os.sep

    # we just use a high res timestamp as automatic rule_id

    if rule_id == keyword_auto:
        rule_id = "%d" % (time.time() * 1E8)

    if action == keyword_auto:
        action = valid_trigger_actions[0]

    if any_state in changes:
        changes = valid_trigger_changes

    logger.info("addvgridtrigger %s" % vgrid_name)

    # 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, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id,
                                  rule_id, 'trigger',
                                  configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

        # In case of warnings, msg is non-empty while ret_val remains True

        output_objects.append({'object_type': 'warning', 'text': msg})

    # if we get here user is either vgrid owner or allowed to add rule

    # don't add if already in vgrid or parent vgrid - but update if owner

    update_id = None
    if vgrid_is_trigger(vgrid_name, rule_id, configuration):
        if vgrid_is_trigger_owner(vgrid_name, rule_id, client_id,
                                  configuration):
            update_id = 'rule_id'
        else:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is already a trigger owned by somebody else in the %s' %
                (rule_id, label)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # don't add if already in 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)
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)
    for subvgrid in subvgrids:
        if vgrid_is_trigger(subvgrid, rule_id, configuration, recursive=False):
            output_objects.append({
                'object_type': 'error_text',
                'text': '''%(rule_id)s is already in a
sub-%(vgrid_label)s (%(subvgrid)s). Please remove the trigger from the
sub-%(vgrid_label)s and try again''' % {
                    'rule_id': rule_id,
                    'subvgrid': subvgrid,
                    'vgrid_label': label
                }
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    if not action in valid_trigger_actions:
        output_objects.append({
            'object_type': 'error_text',
            'text': "invalid action value %s" % action
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if keyword_all in changes:
        changes = valid_trigger_changes
    for change in changes:
        if not change in valid_trigger_changes:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "found invalid change value %s" % change
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # Check if we should load saved trigger for rank change or update

    rule_dict = None
    if rank is not None or update_id is not None:
        (load_status, all_triggers) = vgrid_triggers(vgrid_name, configuration)
        if not load_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to load triggers for %s: %s' %
                (vgrid_name, all_triggers)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
        for saved_dict in all_triggers:
            if saved_dict['rule_id'] == rule_id:
                rule_dict = saved_dict
                break
        if rule_dict is None:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No such trigger %s for %s: %s' %
                (rule_id, vgrid_name, all_triggers)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
    elif not path:
        # New trigger with missing path
        output_objects.append({
            'object_type': 'error_text',
            'text': '''Either path or rank must
be set.'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif action == "submit" and not arguments:
        # New submit trigger with missing mrsl arguments
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Submit triggers must give
a job description file path as argument.'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Handle create and update (i.e. new, update all or just refresh mRSL)

    if rank is None:

        # IMPORTANT: we save the job template contents to avoid potential abuse
        # Otherwise someone else in the VGrid could tamper with the template
        # and make the next trigger execute arbitrary code on behalf of the
        # rule owner.

        templates = []

        # Merge current and saved values

        req_dict = {
            'rule_id': rule_id,
            'vgrid_name': vgrid_name,
            'path': path,
            'changes': changes,
            'run_as': client_id,
            'action': action,
            'arguments': arguments,
            'rate_limit': rate_limit,
            'settle_time': settle_time,
            'match_files': match_files,
            'match_dirs': match_dirs,
            'match_recursive': match_recursive,
            'templates': templates
        }
        if rule_dict is None:
            rule_dict = req_dict
        else:
            for field in user_arguments_dict:
                if req_dict.has_key(field):
                    rule_dict[field] = req_dict[field]

        # Now refresh template contents

        if rule_dict['action'] == "submit":
            for rel_path in rule_dict['arguments']:
                # IMPORTANT: path must be expanded to abs for proper chrooting
                abs_path = os.path.abspath(os.path.join(base_dir, rel_path))
                try:
                    if not valid_user_path(configuration, abs_path, base_dir,
                                           True):
                        logger.warning(
                            '%s tried to %s restricted path %s ! (%s)' %
                            (client_id, op_name, abs_path, rel_path))
                        raise ValueError('invalid submit path argument: %s' %
                                         rel_path)
                    temp_fd = open(abs_path)
                    templates.append(temp_fd.read())
                    temp_fd.close()
                except Exception, err:
                    logger.error("read submit argument file failed: %s" % err)
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        'failed to read submit argument file "%s"' % rel_path
                    })
                    return (output_objects, returnvalues.CLIENT_ERROR)

        # Save updated template contents here
        rule_dict['templates'] = templates
Exemplo n.º 57
0
def main(client_id, user_arguments_dict, environ=None):
    """Main function used by front end"""

    (configuration, logger, output_objects,
     op_name) = initialize_main_variables(client_id,
                                          op_header=False,
                                          op_title=False,
                                          op_menu=client_id)

    # Extract raw data first
    if environ is None:
        environ = os.environ
    request_url = environ.get('REQUEST_URI', '/')
    user_agent = environ.get('HTTP_USER_AGENT', '')
    user_addr = environ.get('REMOTE_ADDR', '')
    user_id = environ.get('REMOTE_USER', '')

    # IMPORTANT: use all actual args as base and override with real signature
    all_args = query_args(environ)
    defaults = signature()[1]
    all_args.update(defaults)
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 all_args,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    token = accepted['token'][-1]
    redirect_url = accepted['redirect_url'][-1]
    check_only = False

    # logger.debug("User: %s executing %s with redirect url %s" %
    #             (client_id, op_name, redirect_url))
    # logger.debug("env: %s" % environ)

    if not configuration.site_enable_twofactor:
        output_objects.append({
            'object_type': 'error_text',
            'text': '''2FA is not enabled on the system'''
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    if configuration.site_twofactor_strict_address \
            and not expire_twofactor_session(configuration,
                                             client_id,
                                             environ,
                                             allow_missing=True,
                                             not_user_addr=user_addr):
        logger.error("could not expire old 2FA sessions for %s" % client_id)
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            "Internal error: could not expire old 2FA sessions!"
        })

        return (output_objects, returnvalues.ERROR)

    status = returnvalues.OK

    # check that the user is already authenticated (does state file exist?)
    # or run through validation of provided time-based one-time password

    if redirect_url:
        # Build forward query string from any real non-local args
        forward_args = {}
        for (key, val) in accepted.items():
            if key not in defaults.keys() and val != ['AllowMe']:
                forward_args[key] = val
        redirect_location = redirect_url
        if forward_args:
            redirect_location += '?%s' % urllib.urlencode(forward_args, True)
        # Manual url decoding required for e.g. slashes
        redirect_location = urllib.unquote(redirect_location)
        headers = [('Status', '302 Moved'), ('Location', redirect_location)]
        logger.debug("redirect_url %s and args %s gave %s" %
                     (redirect_url, forward_args, redirect_location))
    else:
        headers = []
    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.warning("fall back to twofactor defaults for %s" % client_id)
        twofactor_dict = dict([
            (i, j['Value'])
            for (i, j) in twofactor_defaults(configuration).items()
        ])

    # NOTE: twofactor_defaults field availability depends on configuration
    if not redirect_url:
        # This is the 2FA setup check mode
        check_only = True
        require_twofactor = True
    elif user_id.startswith(configuration.user_mig_oid_provider) and \
            twofactor_dict.get('MIG_OID_TWOFACTOR', False):
        require_twofactor = True
    elif user_id.startswith(configuration.user_ext_oid_provider) \
            and twofactor_dict.get('EXT_OID_TWOFACTOR', False):
        require_twofactor = True
    else:
        require_twofactor = False

    # Fail gently if twofactor dependencies are unavailable
    if require_twofactor and not twofactor_available(configuration):
        logger.error("Required dependencies are missing for 2FA support")
        require_twofactor = False

    if require_twofactor:
        logger.info("detected 2FA requirement for %s on %s" %
                    (client_id, request_url))
        b32_secret = None
        if token:
            b32_secret = load_twofactor_key(client_id, configuration)
            if not b32_secret:
                logger.warning("found no saved 2FA secret for %s" % client_id)
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    "Please contact the %s admins to get your 2FA secret" %
                    configuration.short_title
                })
                return (output_objects, returnvalues.ERROR)
        # Check that user provided matching token and set cookie on success
        if token and b32_secret and verify_twofactor_token(
                configuration, client_id, b32_secret, token):
            logger.info('Accepted valid auth token from %s' % client_id)
        else:
            styles = themed_styles(configuration)
            output_objects.append({
                'object_type': 'title',
                'text': '2-Factor Authentication',
                'skipmenu': True,
                'style': styles
            })
            output_objects.append({
                'object_type': 'html_form',
                'text': twofactor_token_html(configuration)
            })
            if token:
                logger.warning('Invalid token for %s (%s vs %s) - try again' %
                               (client_id, token,
                                get_twofactor_token(configuration, client_id,
                                                    b32_secret)))
                # NOTE: we keep actual result in plain text for json extract
                output_objects.append({
                    'object_type':
                    'html_form',
                    'text':
                    '''
<div class="twofactorstatus">
<div class="error leftpad errortext">
'''
                })
                output_objects.append({
                    'object_type':
                    'text',
                    'text':
                    'Incorrect token provided - please try again'
                })
                output_objects.append({
                    'object_type': 'html_form',
                    'text': '''
</div>
</div>'''
                })
                # TODO: proper rate limit source / user here?
                time.sleep(3)
            return (output_objects, status)
    else:
        logger.info("no 2FA requirement for %s on %s" %
                    (client_id, request_url))

    # If we get here we either got correct token or verified 2FA to be disabled

    if check_only:
        logger.info("skip session init in setup check for %s" % client_id)
    else:
        cookie = Cookie.SimpleCookie()
        # TODO: reuse any existing session?
        # create a secure session cookie
        session_key = generate_session_key(configuration, client_id)
        session_start = time.time()
        cookie['2FA_Auth'] = session_key
        cookie['2FA_Auth']['path'] = '/'
        # NOTE: SimpleCookie translates expires ttl to actual date from now
        cookie['2FA_Auth']['expires'] = twofactor_cookie_ttl
        cookie['2FA_Auth']['secure'] = True
        cookie['2FA_Auth']['httponly'] = True

        # GDP only allow one active 2FA-session
        if configuration.site_enable_gdp:
            if not expire_twofactor_session(
                    configuration, client_id, environ, allow_missing=True):
                logger.error("could not expire old 2FA sessions for %s" %
                             client_id)
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    "Internal error: could not expire old 2FA sessions!"
                })
                return (output_objects, returnvalues.ERROR)

        # Create the state file to inform apache (rewrite) about auth
        # We save user info to be able to monitor and expire active sessions
        if not save_twofactor_session(configuration, client_id, session_key,
                                      user_addr, user_agent, session_start):
            logger.error("could not create 2FA session for %s" % client_id)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "Internal error: could not create 2FA session!"
            })
            return (output_objects, returnvalues.ERROR)

        logger.info("saved 2FA session for %s in %s" %
                    (client_id, session_key))

    if redirect_url:
        headers.append(tuple(str(cookie).split(': ', 1)))
        output_objects.append({'object_type': 'start', 'headers': headers})
        output_objects.append({'object_type': 'script_status'})
    else:
        output_objects.append({
            'object_type': 'title',
            'text': '2FA',
            'skipmenu': True
        })
        # NOTE: we keep actual result in plain text for json extract
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
<!-- Keep similar spacing -->
<div class="twofactorbg">
<div class="twofactorstatus">
<div class="ok leftpad">
'''
        })
        output_objects.append({
            'object_type': 'text',
            'text': 'Correct token provided!'
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
</div>
<p>
<a href="">Test again</a> or <a href="javascript:close();">close</a> this
tab/window and proceed.
</p>
</div>
</div>'''
        })
    # logger.debug("return from %s for %s with headers: %s" %
    #             (op_name, client_id, headers))
    return (output_objects, status)
Exemplo n.º 58
0
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'People'

    # jquery support for confirmation-style popup:
    (add_import, add_init, add_ready) = confirm_js(configuration)

    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    output_objects.append({
        'object_type': 'html_form',
        'text': confirm_html(configuration)
    })

    user_list = accepted['cert_id']

    # 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

    base_dir = os.path.abspath(
        os.path.join(configuration.user_home, client_dir)) + os.sep
    status = returnvalues.OK

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'User details'
    output_objects.append({
        'object_type': 'header',
        'text': 'Show user details'
    })

    visible_user = user_visible_user_confs(configuration, client_id)
    vgrid_access = user_vgrid_access(configuration, client_id)

    for visible_user_name in user_list:
        if not visible_user_name in visible_user.keys():
            logger.error("invalid user %s (%s)" %
                         (visible_user_name, visible_user))
            output_objects.append({
                'object_type': 'error_text',
                'text': 'invalid user %s' % visible_user_name
            })
            continue
        user_dict = visible_user[visible_user_name]
        user_item = build_useritem_object_from_user_dict(
            configuration, client_id, visible_user_name, base_dir, user_dict,
            vgrid_access)
        output_objects.append(user_item)

    return (output_objects, status)