Ejemplo 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)
    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)
Ejemplo 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,
                                  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)
Ejemplo n.º 3
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)
Ejemplo 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, 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)
Ejemplo 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=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)
Ejemplo 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_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)
Ejemplo 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, 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)
Ejemplo 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, 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)
Ejemplo n.º 9
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)
Ejemplo 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, 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)
Ejemplo 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_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)
Ejemplo 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,
                                  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)
Ejemplo 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, op_menu=False)
    defaults = signature(configuration)[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    valid_show = get_valid_topics(configuration)
    if keyword_all in accepted['show']:
        show = valid_show.keys()
    else:
        show = list(set([i.lower() for i in accepted['show']]))
    show = [i for i in show if i in valid_show and valid_show[i]['url']]
    if not show:
        logger.info('%s showing default topics' % op_name)
        show = defaults['show']

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s account sign up' % configuration.short_title
    add_import = '''
<script type="text/javascript" src="/images/js/jquery.ajaxhelpers.js"></script>
    '''
    add_init = ''
    add_ready = '''
        var action = "sign up", oid_title, oid_url, tag_prefix;
        oid_title = "%s";
        oid_url = "%s";
        tag_prefix = "extoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
        oid_title = "%s";
        var oid_url = "%s";
        tag_prefix = "migoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
''' % (configuration.user_ext_oid_title, configuration.user_ext_oid_provider,
       configuration.user_mig_oid_title, configuration.user_mig_oid_provider)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    title_entry['skipmenu'] = True
    # NOTE: keep empty header for narrow page layout
    header_entry = {'object_type': 'header', 'text':
                    # 'Welcome to the %s account sign up page' % \
                    # configuration.short_title
                    ''}
    output_objects.append(header_entry)

    html = """
    <h2>Signup for %s</h2>
<p>
Before you can use this site you need a user account. You can sign up for one
here as described below.
</p>
""" % configuration.short_title
    if configuration.user_openid_providers and 'extoid' in show or \
            'migoid' in show:
        html += """<h2>OpenID Login</h2>
The simplest sign up method is to use an existing OpenID login if you have one.
"""
        for method in show:
            if method == 'migoid':
                html += """
<p>
%(migoid_title)s users can sign up for an account with OpenID access here.
</p>
<div id='migoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='migoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(migoid_url)s'>
<!-- NOTE: we can't request field here as there is no account yet! -->
<input id='migoid_button' type='submit' value='%(migoid_title)s User OpenID Signup' />
</form>
</div>
<p>
When you click the Signup button you will be taken to a registration page where
you need to enter your details to get both an OpenID account <em>and</em> an
account on %(short_title)s with that OpenID login associated.
</p>
"""
            if method == 'extoid':
                html += """
<p>
%(extoid_title)s users can sign up for an account here using their existing
OpenID credentials.
</p>
<div id='extoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='extoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(extoid_url)s'>
<input type='hidden' name='openid.ns' value='http://specs.openid.net/auth/2.0' />
<input type='hidden' name='openid.ns.sreg' value='http://openid.net/extensions/sreg/1.1' />
<input type='hidden' name='openid.sreg.required' value='nickname,fullname,email,o,ou,country,state,role' />
<input id='extoid_button' type='submit' value='%(extoid_title)s User OpenID Signup' />
</form>
</div>
<p>
When you click the Signup button you will be taken to a login page where you
need to enter your credentials and accept that your identity is used for
%(short_title)s OpenID login.
</p>
"""

    if 'migcert' in show or 'extcert' in show:
        html += """
<h2>Client Certificate</h2>
<p>
We provide high security access control with client certificates, like the ones
you may know from digital signature providers. It is a bit cumbersome to get
and install such a client certificate, so if you want to keep it simple and
have other access options, you may want to use those instead.
</p>
"""
        for method in show:
            if method == 'migcert':
                html += """
<p>
You can sign up for an account with an associated x509 user certificate here.
</p>
<div class='form_container'>
<form method='get' action='%(migcert_url)s'>
<input id='reqcert_button' type='submit' value='%(migcert_title)s User Certificate Signup' />
</form>
</div>
<p>
When you click the Signup button you will be taken to a registration page where
you need to enter your details to get both a user certificate <em>and</em> an
account on %(short_title)s with that user certificate associated for login.
</p>
"""
            if method == 'extcert':
                html += """
<p>
%(extcert_title)s users can sign up for an %(short_title)s account here using
their existing x509 user certificate.
</p>
<div class='form_container'>
<form method='get' action='%(extcert_url)s'>
<input id='extcert_button' type='submit' value='%(extcert_title)s User Certificate Signup' />
</form>
</div>
<p>
When you click the Signup button you will be taken to a registration page where
the fields will mostly be pre-filled based on your certificate. You just need
to accept that your certificate is used for %(short_title)s login.
</p>

"""

    var_map = {'migoid_url': valid_show['migoid']['url'],
               'migoid_title': configuration.user_mig_oid_title,
               'extoid_url': valid_show['extoid']['url'],
               'extoid_title': configuration.user_ext_oid_title,
               'migcert_url': valid_show['migcert']['url'],
               'migcert_title': configuration.user_mig_cert_title,
               'extcert_url': valid_show['extcert']['url'],
               'extcert_title': configuration.user_ext_cert_title,
               'short_title': configuration.short_title}
    output_objects.append({'object_type': 'html_form', 'text': html % var_map})
    if set(configuration.site_signup_methods) != set(show):
        output_objects.append({'object_type': 'link',
                               'destination': 'signup.py',
                               'class': 'infolink iconspace',
                               'title': 'View all sign up methods',
                               'text': 'View all sign up methods'})
    return (output_objects, returnvalues.OK)
Ejemplo 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, 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]

    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

    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 '%s' to get the PGID!" % \
             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 on that variable.
    # exe_name is not automatically checked however - do it manually

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

        # out of bounds - rogue resource!?!?

        output_objects.append({'object_type': 'error_text', 'text': 
                               'invalid exe_name! %s' % exe_name})
        logger.error('''getrespgid 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)

    # Check that resource address matches request source to make DoS harder
    try:
        check_source_ip(remote_ip, unique_resource_name)
    except ValueError, vae:
        output_objects.append({'object_type': 'error_text', 'text':
                               'invalid request: %s' % vae})
        logger.error("Invalid put pgid: %s" % vae)
        return (output_objects, returnvalues.CLIENT_ERROR)
Ejemplo 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]
    logger.debug("in extoidaction: %s" % user_arguments_dict)
    (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    # Unfortunately OpenID does not use POST
    # if not correct_handler('GET'):
    #    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 OpenID sign up" % configuration.short_title
    title_entry["skipmenu"] = True
    output_objects.append({"object_type": "header", "text": "%s OpenID sign up" % 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)

    id_url = os.environ["REMOTE_USER"].strip()
    openid_prefix = configuration.user_openid_providers[0].rstrip("/") + "/"
    raw_login = id_url.replace(openid_prefix, "")
    full_name = accepted["openid.sreg.full_name"][-1].strip().title()
    country = accepted["openid.sreg.country"][-1].strip().upper()
    state = accepted["state"][-1].strip().title()
    organization = accepted["openid.sreg.organization"][-1].strip()
    organizational_unit = accepted["openid.sreg.organizational_unit"][-1].strip()
    locality = accepted["openid.sreg.locality"][-1].strip()

    # lower case email address

    email = accepted["openid.sreg.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("'", " ")

    user_dict = {
        "full_name": full_name,
        "organization": organization,
        "organizational_unit": organizational_unit,
        "locality": locality,
        "state": state,
        "country": country,
        "email": email,
        "password": password,
        "comment": comment,
        "expire": int(time.time() + oid_valid_days * 24 * 60 * 60),
        "openid_names": [raw_login],
    }
    fill_distinguished_name(user_dict)
    user_id = user_dict["distinguished_name"]
    if configuration.user_openid_providers and configuration.user_openid_alias:
        user_dict["openid_names"].append(user_dict[configuration.user_openid_alias])

    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)
Ejemplo n.º 16
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 site 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 iconspace' 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)
Ejemplo n.º 17
0
Archivo: rm.py Proyecto: heromod/migrid
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(user_arguments_dict,
            defaults, output_objects, 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'])
    pattern_list = accepted['path']
    iosessionid = accepted['iosessionid'][-1]

    if not client_id:
        if not iosessionid.strip() or not iosessionid.isalnum():

            # deny

            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'No sessionid or invalid sessionid supplied!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        base_dir_no_sessionid = \
            os.path.realpath(configuration.webserver_home) + os.sep

        base_dir = \
            os.path.realpath(os.path.join(configuration.webserver_home,
                             iosessionid)) + os.sep
        if not os.path.isdir(base_dir):

            # deny

            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Invalid sessionid!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        if not valid_user_path(base_dir, base_dir_no_sessionid, True):

            # deny

            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Invalid sessionid!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
    else:

        # TODO: this is a hack to allow truncate - fix 'put' empty files

        # 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:
            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, '')
            if verbose(flags):
                output_objects.append({'object_type': 'file', 'name'
                        : relative_path})

            # Make it harder to accidentially delete too much - e.g. do not delete
            # VGrid files without explicit selection of subdir contents

            if real_path == os.path.abspath(base_dir):
                output_objects.append({'object_type': 'warning', 'text'
                        : "You're not allowed to delete your entire home directory!"
                        })
                status = returnvalues.CLIENT_ERROR
                continue
            if os.path.islink(real_path):
                output_objects.append({'object_type': 'warning', 'text'
                        : "You're not allowed to delete entire %s shared dirs!"
                                       % configuration.site_vgrid_label
                        })
                status = returnvalues.CLIENT_ERROR
                continue
            if os.path.isdir(real_path) and recursive(flags):

                # bottom up traversal of the file tree since rmdir is limited to
                # empty dirs

                for (root, dirs, files) in os.walk(real_path,
                        topdown=False):
                    for name in files:
                        path = os.path.join(root, name)
                        relative_path = path.replace(base_dir, '')
                        # Traversal may find additional invisible files to skip
                        if invisible_file(name):
                            continue
                        if verbose(flags):
                            output_objects.append({'object_type': 'file'
                                    , 'name': relative_path})
                        try:
                            os.remove(path)
                        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

                    for name in dirs:
                        path = os.path.join(root, name)
                        relative_path = path.replace(base_dir, '')
                        if verbose(flags):
                            output_objects.append({'object_type': 'file'
                                    , 'name': relative_path})
                        try:
                            os.rmdir(path)
                        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

                # Finally remove base directory

                relative_path = real_path.replace(base_dir, '')
                try:
                    os.rmdir(real_path)
                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
Ejemplo 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, op_header=False,
                                  op_menu=client_id)
    client_dir = client_id_dir(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)

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

    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)

    # Either authenticated user client_id set or sharelink ID
    if client_id:
        user_id = client_id
        target_dir = client_id_dir(client_id)
        base_dir = configuration.user_home
        id_query = ''
        page_title = 'Remove User Directory'
        userstyle = True
        widgets = True
    elif share_id:
        try:
            (share_mode, _) = extract_mode_id(configuration, share_id)
        except ValueError, err:
            logger.error('%s called with invalid share_id %s: %s' % \
                         (op_name, share_id, err))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Invalid sharelink ID: %s' % share_id})
            return (output_objects, returnvalues.CLIENT_ERROR)
        # TODO: load and check sharelink pickle (currently requires client_id)
        user_id = 'anonymous user through share ID %s' % share_id
        if share_mode == 'read-only':
            logger.error('%s called without write access: %s' % \
                         (op_name, accepted))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'No write access!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_dir = os.path.join(share_mode, share_id)
        base_dir = configuration.sharelink_home
        id_query = '?share_id=%s' % share_id
        page_title = 'Remove Shared Directory'
        userstyle = False
        widgets = False
Ejemplo 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_menu=False)
    defaults = signature()[1]
    logger.debug('in extoidaction: %s' % user_arguments_dict)
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    # Unfortunately OpenID does not use POST
    #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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s OpenID account sign up' % configuration.short_title
    title_entry['skipmenu'] = True
    output_objects.append({'object_type': 'header', 'text'
                          : '%s OpenID account sign up' % \
                            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)

    id_url = os.environ['REMOTE_USER'].strip()
    openid_prefix = configuration.user_ext_oid_provider.rstrip('/') + '/'
    raw_login = id_url.replace(openid_prefix, '')
    full_name = accepted['openid.sreg.full_name'][-1].strip().title()
    country = accepted['openid.sreg.country'][-1].strip().upper()
    state = accepted['state'][-1].strip().title()
    organization = accepted['openid.sreg.organization'][-1].strip()
    organizational_unit = accepted['openid.sreg.organizational_unit'][-1].strip()
    locality = accepted['openid.sreg.locality'][-1].strip()

    # lower case email address

    email = accepted['openid.sreg.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("'", ' ')

    user_dict = {
        'full_name': full_name,
        'organization': organization,
        'organizational_unit': organizational_unit,
        'locality': locality,
        'state': state,
        'country': country,
        'email': email,
        'password': password,
        'comment': comment,
        'expire': int(time.time() + oid_valid_days * 24 * 60 * 60),
        'openid_names': [raw_login],
        'auth': ['extoid'],
        }
    fill_distinguished_name(user_dict)
    user_id = user_dict['distinguished_name']
    if configuration.user_openid_providers and configuration.user_openid_alias:
        user_dict['openid_names'].append(
            user_dict[configuration.user_openid_alias])

    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 OpenID account 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)
Ejemplo 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_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 configuration.site_enable_openid or \
            not 'migoid' in configuration.site_signup_methods:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             '''Local OpenID login is not enabled on this site'''})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s OpenID account request' % \
                          configuration.short_title
    title_entry['skipmenu'] = True
    output_objects.append({'object_type': 'header', 'text':
                           '%s OpenID account 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]
    # The checkbox typically returns value 'on' if selected
    passwordrecovery = (accepted['passwordrecovery'][-1].strip().lower() in
                        ('1', 'o', 'y', 't', 'on', 'yes', 'true'))

    # keep comment to a single line

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

    # single quotes break command line format - remove

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

    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 password != verifypassword:
        output_objects.append({'object_type': 'error_text', 'text':
                               'Password and verify password are not identical!'
                               })
        output_objects.append(
            {'object_type': 'link', 'destination': 'javascript:history.back();',
             'class': 'genericbutton', 'text': "Try again"})
        return (output_objects, returnvalues.CLIENT_ERROR)

    try:
        assure_password_strength(configuration, password)
    except Exception, exc:
        logger.warning(
            "%s invalid password for '%s' (policy %s): %s" %
            (op_name, cert_name, configuration.site_password_policy, exc))
        output_objects.append({'object_type': 'error_text', 'text':
                               'Invalid password requested: %s.'
                               % exc
                               })
        output_objects.append(
            {'object_type': 'link', 'destination': 'javascript:history.back();',
             'class': 'genericbutton', 'text': "Try again"})
        return (output_objects, returnvalues.CLIENT_ERROR)
Ejemplo 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)
    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)
Ejemplo n.º 22
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)
    logger = configuration.logger
    logger.info('%s: args: %s' % (op_name, user_arguments_dict))
    prefilter_map = {}

    output_objects.append({
        'object_type':
        'header',
        'text':
        'Automatic %s sign up' % configuration.short_title
    })
    (_, identity) = extract_client_openid(configuration,
                                          environ,
                                          lookup_dn=False)
    req_url = environ['SCRIPT_URI']
    if client_id and client_id == identity:
        login_type = 'cert'
        if req_url.startswith(configuration.migserver_https_mig_cert_url):
            base_url = configuration.migserver_https_mig_cert_url
        elif req_url.startswith(configuration.migserver_https_ext_cert_url):
            base_url = configuration.migserver_https_ext_cert_url
        else:
            logger.warning('no match for cert request URL: %s' % req_url)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No matching request URL: %s' % req_url
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
    elif identity:
        login_type = 'oid'
        if req_url.startswith(configuration.migserver_https_mig_oid_url):
            base_url = configuration.migserver_https_mig_oid_url
        elif req_url.startswith(configuration.migserver_https_ext_oid_url):
            base_url = configuration.migserver_https_ext_oid_url
        else:
            logger.warning('no match for oid request URL: %s' % req_url)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No matching request URL: %s' % req_url
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
        for name in ('openid.sreg.cn', 'openid.sreg.fullname',
                     'openid.sreg.full_name'):
            prefilter_map[name] = filter_commonname
    else:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Missing user credentials'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)
    defaults = signature(login_type)[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False,
                                                 prefilter_map=prefilter_map)
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

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

    # Unfortunately OpenID redirect does not use POST

    if login_type != 'oid' and 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)

    admin_email = configuration.admin_email
    (openid_names, oid_extras) = ([], {})

    # Extract raw values

    if login_type == 'cert':
        uniq_id = accepted['cert_id'][-1].strip()
        raw_name = accepted['cert_name'][-1].strip()
        country = accepted['country'][-1].strip()
        state = accepted['state'][-1].strip()
        org = accepted['org'][-1].strip()
        org_unit = ''
        role = ','.join([i for i in accepted['role'] if i])
        association = ','.join([i for i in accepted['association'] if i])
        locality = ''
        timezone = ''
        email = accepted['email'][-1].strip()
        raw_login = None
    elif login_type == 'oid':
        uniq_id = accepted['openid.sreg.nickname'][-1].strip() \
            or accepted['openid.sreg.short_id'][-1].strip()
        raw_name = accepted['openid.sreg.fullname'][-1].strip() \
            or accepted['openid.sreg.full_name'][-1].strip()
        country = accepted['openid.sreg.country'][-1].strip()
        state = accepted['openid.sreg.state'][-1].strip()
        org = accepted['openid.sreg.o'][-1].strip() \
            or accepted['openid.sreg.organization'][-1].strip()
        org_unit = accepted['openid.sreg.ou'][-1].strip() \
            or accepted['openid.sreg.organizational_unit'][-1].strip()

        # We may receive multiple roles and associations

        role = ','.join([i for i in accepted['openid.sreg.role'] if i])
        association = ','.join(
            [i for i in accepted['openid.sreg.association'] if i])
        locality = accepted['openid.sreg.locality'][-1].strip()
        timezone = accepted['openid.sreg.timezone'][-1].strip()

        # We may encounter results without an email, fall back to uniq_id then

        email = accepted['openid.sreg.email'][-1].strip() or uniq_id

    # Fix case of values:
    # 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.

    try:
        full_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        logger.warning('could not use unicode form to capitalize full name')
        full_name = raw_name.title()
    country = country.upper()
    state = state.upper()
    email = email.lower()

    if login_type == 'oid':

        # Remap some oid attributes if on KIT format with faculty in
        # organization and institute in organizational_unit. We can add them
        # as different fields as long as we make sure the x509 fields are
        # preserved.
        # Additionally in the special case with unknown institute (ou=ukendt)
        # we force organization to KU to align with cert policies.
        # We do that to allow autocreate updating existing cert users.

        if org_unit not in ('', 'NA'):
            org_unit = org_unit.upper()
            oid_extras['faculty'] = org
            oid_extras['institute'] = org_unit
            org = org_unit.upper()
            org_unit = 'NA'
            if org == 'UKENDT':
                org = 'KU'
                logger.info('unknown affilition, set organization to %s' % org)

        # Stay on virtual host - extra useful while we test dual OpenID

        if configuration.site_enable_gdp:
            base_url = environ.get('REQUEST_URI',
                                   base_url).split('?')[0].replace(
                                       'autocreate', 'gdpman')
        else:
            base_url = environ.get('REQUEST_URI',
                                   base_url).split('?')[0].replace(
                                       'autocreate', 'fileman')
        raw_login = None
        for oid_provider in configuration.user_openid_providers:
            openid_prefix = oid_provider.rstrip('/') + '/'
            if identity.startswith(openid_prefix):
                raw_login = identity.replace(openid_prefix, '')
                break

    if raw_login:
        openid_names.append(raw_login)

    # we should have the proxy file read...

    proxy_content = accepted['proxy_upload'][-1]

    # keep comment to a single line

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

    # single quotes break command line format - remove

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

    user_dict = {
        'short_id': uniq_id,
        'full_name': full_name,
        'organization': org,
        'organizational_unit': org_unit,
        'locality': locality,
        'state': state,
        'country': country,
        'email': email,
        'role': role,
        'association': association,
        'timezone': timezone,
        'password': '',
        'comment': '%s: %s' % ('Existing certificate', comment),
        'openid_names': openid_names,
    }
    user_dict.update(oid_extras)

    # We must receive some ID from the provider

    if not uniq_id and not email:
        if accepted.get('openid.sreg.required', '') and identity:
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '''<p class="spinner iconleftpad">
Auto log out first to avoid sign up problems ...
</p>'''
            })
            html = \
                """
            <a id='autologout' href='%s'></a>
            <script type='text/javascript'>
                document.getElementById('autologout').click();
            </script>""" \
                % openid_autologout_url(configuration, identity,
                    client_id, req_url, user_arguments_dict)
            output_objects.append({'object_type': 'html_form', 'text': html})
        return (output_objects, returnvalues.CLIENT_ERROR)

    auth = 'unknown'
    if login_type == 'cert':
        auth = 'extcert'
        user_dict['expire'] = int(time.time() + cert_valid_days * 24 * 60 * 60)
        try:
            distinguished_name_to_user(uniq_id)
            user_dict['distinguished_name'] = uniq_id
        except:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Illegal Distinguished name:
Please note that the distinguished name must be a valid certificate DN with
multiple "key=val" fields separated by "/".
'''
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
    elif login_type == 'oid':
        auth = 'extoid'
        user_dict['expire'] = int(time.time() + oid_valid_days * 24 * 60 * 60)
        fill_distinguished_name(user_dict)
        uniq_id = user_dict['distinguished_name']

    # Save auth access method

    user_dict['auth'] = [auth]

    # If server allows automatic addition of users with a CA validated cert
    # we create the user immediately and skip mail

    if login_type == 'cert' and configuration.auto_add_cert_user \
        or login_type == 'oid' and configuration.auto_add_oid_user:
        fill_user(user_dict)

        logger.info('create user: %s' % user_dict)

        # Now all user fields are set and we can begin adding the user

        db_path = os.path.join(configuration.mig_server_home, user_db_filename)
        try:
            create_user(user_dict,
                        configuration.config_file,
                        db_path,
                        ask_renew=False,
                        default_renew=True)
            if configuration.site_enable_griddk \
                and accepted['proxy_upload'] != ['']:

                # save the file, display expiration date

                proxy_out = handle_proxy(proxy_content, uniq_id, configuration)
                output_objects.extend(proxy_out)
        except Exception, err:
            logger.error('create failed for %s: %s' % (uniq_id, err))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Could not create the user account for you:
Please report this problem to the grid administrators (%s).''' % admin_email
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        logger.info('created user account for %s' % uniq_id)
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''Created the user account for you -
please open <a href="%s">your personal page</a> to proceed using it.
''' % base_url
        })
        return (output_objects, returnvalues.OK)
Ejemplo 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,
                                  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)
    queue = accepted['queue'][-1]
    action = accepted['action'][-1]
    iosessionid = accepted['iosessionid'][-1]
    msg = accepted['msg'][-1]
    msg_id = accepted['msg_id'][-1]

    # Web format for cert access and no header for SID access

    if client_id:
        output_objects.append({'object_type': 'header', 'text'
                               : 'Message queue %s' % action})
    else:
        output_objects.append({'object_type': 'start'})

    # Always return at least a basic file_output entry

    file_entry = {'object_type': 'file_output',
                  'lines': [],
                  'wrap_binary': True,
                  'wrap_targets': ['lines']}

    if not action in valid_actions:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid action "%s" (supported: %s)' % \
                               (action, ', '.join(valid_actions))})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    if action in post_actions:
        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)

    # Find user home from session or certificate

    if iosessionid:
        client_home = os.path.realpath(os.path.join(configuration.webserver_home,
                                                  iosessionid))
        client_dir = os.path.basename(client_home)
    elif client_id:
        client_dir = client_id_dir(client_id)
    else:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Either certificate or session ID is required'
                               })
        output_objects.append(file_entry)
        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

    if not os.path.isdir(base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'No matching session or user home!'})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    mqueue_base = os.path.join(base_dir, mqueue_prefix) + os.sep

    default_queue_dir = os.path.join(mqueue_base, default_mqueue)

    # Create mqueue base and default queue dir if missing

    if not os.path.exists(default_queue_dir):
        try:
            os.makedirs(default_queue_dir)
        except:
            pass

    # IMPORTANT: path must be expanded to abs for proper chrooting
    queue_path = os.path.abspath(os.path.join(mqueue_base, queue))
    if not valid_user_path(configuration, queue_path, mqueue_base):
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid queue name: "%s"' % queue})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    lock_path = os.path.join(mqueue_base, lock_name)
    lock_handle = open(lock_path, 'a')
    fcntl.flock(lock_handle.fileno(), fcntl.LOCK_EX)

    status = returnvalues.OK
    if action == "interactive":
        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers =  {'queue': queue,
                         'msg': msg,
                         'form_method': form_method,
                         'csrf_field': csrf_field,
                         'csrf_limit': csrf_limit, }
        target_op = 'mqueue'
        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})
        
        output_objects.append({'object_type': 'text', 'text': '''
Fill in the fields below to control and access your personal message queues.
Jobs can receive from and send to the message queues during execution, and use
them as a means of job inter-communication. Expect message queue operations to
take several seconds on the resources, however. That is, use it for tasks like
orchestrating long running jobs, and not for low latency communication.
'''})
        html = '''
<form name="mqueueform" method="%(form_method)s" action="%(target_op)s.py">
<table class="mqueue">
<tr><td class=centertext>
</td></tr>
<tr><td>
Action:<br />
<input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
<input type=radio name=action value="create" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />create queue
<input type=radio name=action checked value="send" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=false;" />send message to queue
<input type=radio name=action value="receive" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />receive message from queue
<input type=radio name=action value="remove" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />remove queue
<input type=radio name=action value="listqueues" onclick="javascript: document.mqueueform.queue.disabled=true; document.mqueueform.msg.disabled=true;" />list queues
<input type=radio name=action value="listmessages" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />list messages
<input type=radio name=action value="show" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />show message
</td></tr>
<tr><td>
Queue:<br />
<input class="fillwidth" type=text name=queue value="%(queue)s" />
</td></tr>
<tr><td>
<div id="msgfieldf">
<input class="fillwidth" type=text name=msg value="%(msg)s" /><br />
</div>
</td></tr>
<tr><td>
<input type="submit" value="Apply" />
</td></tr>
</table>
</form>
''' % fill_helpers
        output_objects.append({'object_type': 'html_form', 'text'
                               : html})
        output_objects.append({'object_type': 'text', 'text': '''
Further live job control is avalable through the live I/O interface.
They provide a basic interface for centrally managing input and output files
for active jobs.
'''
                               })
        output_objects.append({'object_type': 'link', 'destination':
                               'liveio.py',
                               'text': 'Live I/O interface'})
        return (output_objects, returnvalues.OK)
    elif action == 'create':
        try:
            os.mkdir(queue_path)
            output_objects.append({'object_type': 'text', 'text':
                                   'New "%s" queue created' % queue})
        except Exception, err:
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Could not create "%s" queue: "%s"' % \
                                   (queue, err)})
            status = returnvalues.CLIENT_ERROR
Ejemplo 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=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox Download' % \
                            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)

    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)

    username = accepted['username'][-1]
    password = accepted['password'][-1]
    hd_size = accepted['hd_size'][-1]
    image_format = accepted['image_format'][-1]
    net_bw = accepted['net_bw'][-1]
    memory = accepted['memory'][-1]
    operating_system = accepted['operating_system'][-1]
    win_solution = accepted['win_solution'][-1]
    vgrid_list = accepted['vgrid']
    cputime = 1000000
    sandboxkey = hexlify(open('/dev/urandom').read(32))
    ip_address = 'UNKNOWN'
    if os.environ.has_key('REMOTE_ADDR'):
        ip_address = os.environ['REMOTE_ADDR']

    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)

    # check that requested image format is valid

    if not image_format in ['raw', 'qcow', 'cow', 'qcow2', 'vmdk']:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Unsupported image format: %s'
                               % image_format})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # check that requested vgrids are valid - anybody can offer their sandbox
    # for a vgrid but it is still left to the vgrid owners to explicitly
    # accept all resources

    (vg_status, all_vgrids) = vgrid_list_vgrids(configuration)
    for vgrid in vgrid_list:
        if not vg_status or not vgrid in all_vgrids:
            output_objects.append({'object_type': 'error_text', 'text'
                              : 'Failed to validate %s %s: %s'
                               % (configuration.site_vgrid_label, vgrid,
                                  all_vgrids)})
            return (output_objects, returnvalues.SYSTEM_ERROR)

    # Load the user file

    try:
        userdb = load_sandbox_db(configuration)
    except Exception, exc:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Failed to read login info: %s'
                               % exc})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Ejemplo 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, op_header=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)

    flags = ''.join(accepted['flags'])
    pattern_list = accepted['path']
    current_dir = accepted['current_dir'][-1].lstrip('/')
    share_id = accepted['share_id'][-1]
    show_dest = accepted['with_dest'][0].lower() == 'true'

    status = returnvalues.OK

    # NOTE: in contrast to 'ls' we never include write operations here
    read_mode, write_mode = True, False
    visibility_mods = '''
            .%(main_class)s .enable_write { display: none; }
            .%(main_class)s .disable_read { display: none; }
            .%(main_class)s .if_full { display: none; }
    '''
    # Either authenticated user client_id set or sharelink ID
    if client_id:
        user_id = client_id
        target_dir = client_id_dir(client_id)
        base_dir = configuration.user_home
        redirect_name = configuration.site_user_redirect
        redirect_path = redirect_name
        id_args = ''
        root_link_name = 'USER HOME'
        main_class = "user_expand"
        page_title = 'User Files - Path Expansion'
        userstyle = True
        widgets = True
    elif share_id:
        try:
            (share_mode, _) = extract_mode_id(configuration, share_id)
        except ValueError, err:
            logger.error('%s called with invalid share_id %s: %s' %
                         (op_name, share_id, err))
            output_objects.append({
                'object_type': 'error_text',
                'text': 'Invalid sharelink ID: %s' % share_id
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        # TODO: load and check sharelink pickle (currently requires client_id)
        # then include shared by %(owner)s on page header
        user_id = 'anonymous user through share ID %s' % share_id
        target_dir = os.path.join(share_mode, share_id)
        base_dir = configuration.sharelink_home
        redirect_name = 'share_redirect'
        redirect_path = os.path.join(redirect_name, share_id)
        id_args = 'share_id=%s;' % share_id
        root_link_name = '%s' % share_id
        main_class = "sharelink_expand"
        page_title = 'Shared Files - Path Expansion'
        userstyle = False
        widgets = False
Ejemplo 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_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'))

    unique_resource_name = accepted['unique_resource_name'][-1]
    exe = accepted['exe'][-1]
    cputime = int(accepted['cputime'][-1])
    nodecount = int(accepted['nodecount'][-1])
    localjobname = accepted['localjobname'][-1]
    sandboxkey = accepted['sandboxkey'][-1]
    execution_delay = int(accepted['execution_delay'][-1])
    exe_pgid = int(accepted['exe_pgid'][-1])

    status = returnvalues.OK


    # No header and footer here
    output_objects.append({'object_type': 'start'})
    output_objects.append({'object_type': 'script_status', 'text': ''})
        
    # 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

    if not is_resource(unique_resource_name, configuration.resource_home):
        output_objects.append(
            {'object_type': 'error_text', 'text': 
             "Failure: You must be an owner of '%s' to get the PGID!" % \
             unique_resource_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # is_resource incorporates unique_resource_name verification - no need to
    # specifically check for illegal directory traversal on that variable.

    (load_status, resource_conf) = \
                  get_resource_configuration(configuration.resource_home,
                                             unique_resource_name, logger)
    if not load_status:
        logger.error("Invalid requestnewjob - 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 requestnewjob: %s (%s)" % (vae, accepted))
        output_objects.append({'object_type': 'error_text', 'text':
                               'invalid request: %s' % vae})
        return (output_objects, returnvalues.CLIENT_ERROR)
Ejemplo 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,
                                  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)
Ejemplo n.º 28
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)
Ejemplo 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=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox' % \
                            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 ("maintenance", "english", "danish"):
        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)

    html = {}
    html['maintenance'] = """
Sorry we are currently down for maintenance, we'll be back shortly
"""

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'site': configuration.short_title,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    target_op = 'sssadmin'
    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})

    html['english'] = """
<form method='%(form_method)s' action='%(target_op)s.py'> 
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />

<table class='sandboxlogintext'>
<tr><td><a class='danishlink iconspace' href='ssslogin.py?language=danish'>P&aring; dansk</a></td></tr>
<tr><td><h3>Intro</h3></td></tr>
<tr><td>Welcome to the %(site)s-SSS download site. By downloading and installing this software, your computer will be participating in solving scientific problems whenever the screen saver is on. All you have to do is log in below, download the sandbox, and follow the instructions during the install procedure.</td></tr>

<tr><td><h3>Why Login?</h3></td></tr>
<tr><td>Please note that we do not store any personal information. All you need is a login name which is solely used for identifying sandboxes so that you can keep track of how many jobs your PC has solved while it was idle.  </td></tr>
<tr><td></td></tr>

<tr><td><h3>What About Security?</h3></td></tr>
<tr><td>The applications that will be running on your PC when you leave it in screen saver mode are all executed in a so-called 'sandbox'. A sandbox provides a secure execution environment, in which untrusted programs can run. Programs running in the sandbox can neither compromise nor gain access to your PC.</td></tr>

<tr><td><h3>Sandbox monitor</h3></td></tr>
<tr><td>After logging in you will be presented with a list of statistics for your own sandboxes. In case you want to compare your donations to those from other sandbox resource owners, you can take a look at the <a class='monitorlink iconspace' href='sssmonitor.py'>overall sandbox monitor</a>.</td></tr>

<tr><td><h3>More Questions?</h3></td></tr>
<tr><td>Please check the <a class='infolink iconspace' href='sssfaq.py?language=english'>FAQ</a>, or send us an email.</td></tr>
</table>
<br />
<table class='sandboxlogin'>
<tr>
<td class='righttext'>Choose a user name:</td>
<td class='lefttext'><input type='text' name='username' size='10' /></td>
</tr>
<tr>
<td class='righttext'>Choose a password:</td>
<td class='lefttext'><input type='password' name='password' size='10' /></td>
</tr>
<tr>
<td class='righttext'>I'm a new user</td>
<td class='lefttext'><input type='checkbox' name='newuser' /></td>
</tr>
<tr>
<td class='centertext' colspan='2'><input type='submit' value='Send' /></td>
</tr>


</table></form>
""" % fill_helpers

    html['danish'] = """
<form method='%(form_method)s' action='%(target_op)s.py'> 
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />

<table class='sandboxlogintext'>
<tr><td><a class='englishlink iconspace' href='ssslogin.py?language=english'>In English</a></td></tr>
<tr><td><h3>Intro</h3></td></tr>
<tr><td>Velkommen til %(site)s-SSS. Ved at downloade og installere denne software vil din PC, n&aring;r den er i screen saver mode, donere den ubrugte CPU-tid til at bidrage med at l&oslash;se videnskabelige problemer. Det eneste, der kr&aelig;ves er, at man logger ind nedenfor, downloader softwaren og f&oslash;lger installationsproceduren.<td><tr>

<tr><td><h3>Brugernavn</h3></td></tr>
<tr><td>Der gemmes ikke nogen former for personlig information. Der skal blot v&aelig;lges et brugernavn, som udelukkende bruges til at identificere individuelle bidragsydere, s&aring; man kan f&oslash;lge med i hvor mange jobs ens PC har afviklet mens den har v&aelig;ret i screen saver mode.<td></tr>

<tr><td><h3>Hvad med sikkerhed?</h3></td></tr>
<tr><td>De programmer der kommer til at k&oslash;re n&aring;r din PC er i screen saver mode, vil alle blive afviklet i en s&aring;kaldt 'sandkasse'. En sandkasse stiller et sikkert milj&oslash; tilr&aring;dighed, hvori det er sikkert at k&oslash;re ukendte programmer. Programmer k&oslash;rende i sandkassen kan hverken kompromittere eller f&aring; tilgang til din PC.</td></tr>

<tr><td><h3>Installationsvejledning</h3></td></tr>
<tr><td>Programmet findes b&aring;de i en version til Windows XP og Linux. Windowsbrugere downloader en installationsfil, som g&oslash;r installationen meget simpel. En trin-for-trin guide kan findes her: <a class='infolink iconspace' href='http://www.migrid.org/MiG/MiG/Mig_danish/MiG-SSS installationsprocedure'>Installationsguide til Windows</a><td></tr>

<tr><td><h3>Job monitor</h3></td></tr>
<tr><td>N&aring;r du logger ind f&aring;r du en oversigt over jobs k&oslash;rt p&aring; dine sandkasse resurser. Hvis du gerne vil sammenligne med andres sandkasse donationer, kan du se p&aring; den <a class='monitorlink iconspace' href='sssmonitor.py'>samlede sandkasse monitor</a>.</td></tr>

<tr><td><h3>Flere sp&oslash;rgsm&aring;l?</h3></td></tr>
<tr><td>Check om det skulle findes i <a class='infolink iconspace' href='sssfaq.py?language=danish'>FAQ'en</a>, ellers send os en email.</td></tr>
</table>

<br />
<table class='sandboxlogin'>
<tr><td align='center' colspan='1'>V&aelig;lg et brugernavn:</td>
<td><input type='text' name='username' size='10' /></td></tr>

<tr><td align='center' colspan='1'>V&aelig;lg et password:</td>
<td><input type='password' name='password' size='10' /></td></tr>

<tr><td>Jeg er ny bruger</td><td align='left' colspan='1'><input type='checkbox' name='newuser' /></td></tr>

<tr><td align='center' colspan='2'><input type='submit' value='Send' /></td></tr>


</table></form>
""" % fill_helpers

    output_objects.append({'object_type': 'html_form', 'text': html[language]})
    return (output_objects, returnvalues.OK)
Ejemplo 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, op_header=False, op_menu=False)
    client_dir = client_id_dir(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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s certificate request' % configuration.short_title
    title_entry['skipmenu'] = True
    form_fields = ['full_name', 'organization', 'email', 'country', 'state',
                   'password', 'verifypassword', 'comment']
    title_entry['style'] = themed_styles(configuration)
    title_entry['javascript'] = cert_js_helpers(form_fields)
    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="contextual_help">
  <div class="help_gfx_bubble"><!-- graphically connect field with help text --></div>
  <div class="help_message"><!-- filled by js --></div>
 </div>
'''                       })
    header_entry = {'object_type': 'header', 'text'
                    : 'Welcome to the %s certificate request page' % \
                    configuration.short_title}
    output_objects.append(header_entry)
    
    # 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

    user_fields = {'full_name': '', 'organization': '', 'email': '',
                   'state': '', 'country': '', 'password': '',
                   'verifypassword': ''}
    if not os.path.isdir(base_dir) and client_id:

        # Redirect to extcert page with certificate requirement but without
        # changing access method (CGI vs. WSGI).

        extcert_url = os.environ['REQUEST_URI'].replace('-sid', '-bin')
        extcert_url = os.path.join(os.path.dirname(extcert_url), 'extcert.py')
        extcert_link = {'object_type': 'link', 'destination': extcert_url,
                        'text': 'Sign up with existing certificate (%s)' % client_id}
        output_objects.append({'object_type': 'warning', 'text'
                              : 'Apparently you already have a suitable %s certificate that you may sign up with:' % \
                                configuration.short_title
                              })
        output_objects.append(extcert_link)
        output_objects.append({'object_type': 'warning', 'text'
                              : 'However, if you want a dedicated %s certificate you can still request one below:' % \
                                configuration.short_title
                              })
    elif client_id:
        for entry in (title_entry, header_entry):
            entry['text'] = entry['text'].replace('request', 'request / renew')
        output_objects.append({'object_type': 'html_form', 'text'
                              : '''<p>
Apparently you already have a valid %s certificate, but if it is about to
expire you can renew it by posting the form below. Renewal with changed fields
is <span class=mandatory>not</span> supported, so all fields including your
original password must remain unchanged for renew to work. Otherwise it
results in a request for a new account and certificate without access to your
old files, jobs and privileges.</p>''' % \
                               configuration.short_title})
        user_fields.update(distinguished_name_to_user(client_id))

    user_fields.update({
        'valid_name_chars': html_escape(valid_name_chars),
        'valid_password_chars': html_escape(valid_password_chars),
        'password_min_len': password_min_len,
        'password_max_len': password_max_len,
        'site': configuration.short_title
        })

    output_objects.append({'object_type': 'html_form', 'text'
                          : """
Please enter your information in at least the <span class=mandatory>mandatory</span> fields below and press the Send button to submit the certificate request to the %(site)s administrators.
<p class='criticaltext highlight_message'>
IMPORTANT: Please help us verify your identity by providing Organization and Email data that we can easily validate!<br />
That is, if You're a student/employee at KU, please enter institute acronym (NBI, DIKU, etc.) in the Organization field and use your corresponding [email protected] or USER@*.ku.dk address in the Email field.
</p>
<hr />
<div class=form_container>
<!-- use post here to avoid field contents in URL -->
<form method=post action=reqcertaction.py onSubmit='return validate_form();'>
<table>
<tr><td class='mandatory label'>Full name</td><td><input id='full_name_field' type=text name=cert_name value='%(full_name)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=text name=email value='%(email)s' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(organization)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Two letter country-code</td><td><input id='country_field' type=text name=country maxlength=2 value='%(country)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='optional label'>State</td><td><input id='state_field' type=text name=state value='%(state)s' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Password</td><td><input id='password_field' type=password name=password maxlength=%(password_max_len)s value='%(password)s' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Verify password</td><td><input id='verifypassword_field' type=password name=verifypassword maxlength=%(password_max_len)s value='%(verifypassword)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='optional label'>Optional comment or reason why you should<br />be granted a %(site)s certificate:</td><td><textarea id='comment_field' rows=4 name=comment></textarea></td><td class=fill_space><br /></td></tr>
<tr><td class='label'><!-- empty area --></td><td><input id='submit_button' type=submit value=Send /></td><td class=fill_space><br /></td></tr>
</table>
</form>
</div>
<hr />
<br />
<div class='warn_message'>Please note that passwords may be accessible to the %(site)s administrators!</div>
<br />
<!-- Hidden help text -->
<div id='help_text'>
  <div id='full_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div>
  <div id='organization_help'>Organization name or acronym  matching email</div>
  <div id='email_help'>Email address associated with your organization if at all possible</div>
  <div id='country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.html'>help</a></div>
  <div id='state_help'>Optional state of your organization, please just leave empty unless it is in the US or similar</div>
  <div id='password_help'>Password is restricted to the characters in '%(valid_password_chars)s and must be %(password_min_len)s to %(password_max_len)s characters long'</div>
  <div id='verifypassword_help'>Please repeat password</div>
  <div id='comment_help'>Optional, but a short informative comment may help us verify your certificate needs and thus speed up our response.</div>
</div>
""" % user_fields})

    return (output_objects, returnvalues.OK)
Ejemplo 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,
                                  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)
    queue = accepted['queue'][-1]
    action = accepted['action'][-1]
    iosessionid = accepted['iosessionid'][-1]
    msg = accepted['msg'][-1]
    msg_id = accepted['msg_id'][-1]

    # Web format for cert access and no header for SID access

    if client_id:
        output_objects.append({'object_type': 'header', 'text'
                               : 'Message queue %s' % action})
    else:
        output_objects.append({'object_type': 'start'})

    # Always return at least a basic file_output entry

    file_entry = {'object_type': 'file_output',
                  'lines': [],
                  'wrap_binary': True,
                  'wrap_targets': ['lines']}

    if not action in valid_actions:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid action "%s" (supported: %s)' % \
                               (action, ', '.join(valid_actions))})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    if action in post_actions and 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)

    # Find user home from session or certificate

    if iosessionid:
        client_home = os.path.realpath(os.path.join(configuration.webserver_home,
                                                  iosessionid))
        client_dir = os.path.basename(client_home)
    elif client_id:
        client_dir = client_id_dir(client_id)
    else:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Either certificate or session ID is required'
                               })
        output_objects.append(file_entry)
        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

    if not os.path.isdir(base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'No matching session or user home!'})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    mqueue_base = os.path.join(base_dir, mqueue_prefix) + os.sep

    default_queue_dir = os.path.join(mqueue_base, default_mqueue)

    # Create mqueue base and default queue dir if missing

    if not os.path.exists(default_queue_dir):
        try:
            os.makedirs(default_queue_dir)
        except:
            pass

    queue_path = os.path.abspath(os.path.join(mqueue_base, queue))
    if not valid_user_path(queue_path, mqueue_base):
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid queue name: "%s"' % queue})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    lock_path = os.path.join(mqueue_base, lock_name)
    lock_handle = open(lock_path, 'a')
    fcntl.flock(lock_handle.fileno(), fcntl.LOCK_EX)

    status = returnvalues.OK
    if action == "interactive":
        output_objects.append({'object_type': 'text', 'text'
                               : '''
Fill in the fields below to control and access your personal message queues.
Jobs can receive from and send to the message queues during execution, and use
them as a means of job inter-communication. Expect message queue operations to
take several seconds on the resources, however. That is, use it for tasks like
orchestrating long running jobs, and not for low latency communication.
'''})
        html = '''
<form name="mqueueform" method="post" action="mqueue.py">
<table class="mqueue">
<tr><td class=centertext>
</td></tr>
<tr><td>
Action:<br />
<input type=radio name=action value="create" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />create queue
<input type=radio name=action checked value="send" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=false;" />send message to queue
<input type=radio name=action value="receive" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />receive message from queue
<input type=radio name=action value="remove" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />remove queue
<input type=radio name=action value="listqueues" onclick="javascript: document.mqueueform.queue.disabled=true; document.mqueueform.msg.disabled=true;" />list queues
<input type=radio name=action value="listmessages" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />list messages
<input type=radio name=action value="show" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />show message
</td></tr>
<tr><td>
Queue:<br />
<input type=text size=60 name=queue value="%s" />
</td></tr>
<tr><td>
<div id="msgfieldf">
<input type=text size=60 name=msg value="%s" /><br />
</div>
</td></tr>
<tr><td>
<input type="submit" value="Apply" />
</td></tr>
</table>
</form>
''' % (queue, msg)
        output_objects.append({'object_type': 'html_form', 'text'
                               : html})
        output_objects.append({'object_type': 'text', 'text': '''
Further live job control is avalable through the live I/O interface.
They provide a basic interface for centrally managing input and output files
for active jobs.
'''
                               })
        output_objects.append({'object_type': 'link', 'destination':
                               'liveio.py',
                               'text': 'Live I/O interface'})
        return (output_objects, returnvalues.OK)
    elif action == 'create':
        try:
            os.mkdir(queue_path)
            output_objects.append({'object_type': 'text', 'text':
                                   'New "%s" queue created' % queue})
        except Exception, err:
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Could not create "%s" queue: "%s"' % \
                                   (queue, err)})
            status = returnvalues.CLIENT_ERROR
Ejemplo 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)
    output_objects.append({
        'object_type': 'header',
        'text': 'Grid Usage Statistics'
    })
    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)

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

    # read view options
    group_in_time = accepted['group_in_time'][-1]  # day, week, month
    time_start = accepted['time_start'][-1]
    time_end = accepted['time_end'][-1]
    display = accepted['display'][-1]  # machine, user, vgrid, summary

    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)

    # check arguments against configured lists of valid inputs:
    reject = False

    # make sure: grouping in ['user','machine', 'vgrid']
    if not display in displays:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'invalid display grouping specified: %s' % display
        })
        display = displays[0]
        reject = True
    # make sure: group_in_time in ['all', 'month', 'day', 'week']
    if not group_in_time in time_groups:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'invalid time grouping specified: %s' % group_in_time
        })
        group_in_time = time_groups[0]
        reject = True
    # make sure: start and end match "20[0-9]{2}-[01][0-9]"
    if not re.match('20\d\d-[01]\d', time_start):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'invalid start time specified: %s' % time_start
        })
        time_start = '2009-09'
        reject = True

    if not re.match('20\d\d-[01]\d', time_end):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'invalid end time specified: %s' % time_end
        })
        time_end = time.strftime('%Y-%m')
        reject = True

    # always include a form to re-display with different values:
    updateform = '           <form action="%s" >' %  \
                 os.path.basename(requested_page())
    updateform += '''
                <table class="runtimeenventry">
                  <thead>
                    <tr>
                    <th>Grouping by time</th>
                    <th>Start (YYYY-MM)</th>
                    <th>End (YYYY-MM)</th>
                    <th>Category</th>
                    <th><!-- dummy for update button --></th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>
                        <select name="group_in_time">
'''
    #     updateform += \
    #      ''.join([ '\n<option value="' + t + '">' + t.title() + '</option>'
    #                for t in time_groups ])
    for t in time_groups:
        updateform += '<option '
        if group_in_time == t:
            updateform += 'selected '
        updateform += 'value="' + t + '">' + t.title() + '</option>\n'
    updateform += '''
                        </select>
                      </td>
                      <td><input type="text" name="time_start" value="%s"></td>
                      <td><input type="text" name="time_end" value="%s"></td>
''' % (time_start, time_end) + '''
                      <td><select name="display">
'''
    #     updateform += \
    #     ''.join([ '\n<option value="' + d + '">' + d.title() + '</option>'
    #                 for d in displays ])
    for d in displays:
        updateform += '<option '
        if display == d:
            updateform += 'selected '
        updateform += 'value="' + d + '">' + d.title() + '</option>\n'
    updateform += '''
                        </select>
                      </td>
                      <td><input type="submit" value="Update View"></td>
                    </tr>
                  </tbody>  
                </table>
            </form>
            <hr>
'''

    output_objects.append({'object_type': 'html_form', 'text': updateform})
    if reject:
        output_objects.append({
            'object_type': 'text',
            'text': 'Please check your view parameters.'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # else: all parameters OK, go:

    # determine the view and group level to use:

    # we use couchdb views with name convention <group-in-time>-<display>
    view = group_in_time + '-' + display

    # default group-level (max. 2 view components relevant)
    group_level = 2

    # could handle summary display specially, by setting group_level = 1
    # and using either <time>-machine or <time>-user view
    #    if display == 'summary':
    #        display = 'user'
    #        group_level = 1

    # construct start and end key.

    # machine and user cannot be filtered from the user, only
    # time can be specified, and as YYYY-MM only.
    # for view per week, we have to convert it to a week number
    # python starts by week 0, whereas javascript starts by week 1
    if group_in_time == 'week':
        t = time.strptime(time_start + '-07', "%Y-%m-%d")
        time_start = time.strftime("%Y,week%U", t)

    start_key = '["' + time_start.replace("-", " ") + '",null]'
    # 2nd component: user or machine
    # TODO allow only own user ID and only machines owned???
    # drawback: cannot restrict user/machine when requesting more than one time period
    # To restrict user/machine, views which have this as the first key part
    # have to be used. In which case only one user can be selected
    # to keep the time period selection valid.

    if group_in_time == 'week':
        # last week of the month = first week 1 month later
        # we better compute this instead of tweaking the input
        t = time.mktime(time.strptime(time_end + '-28', "%Y-%m-%d"))
        t += 7 * 24 * 3600
        end_key = '["' + \
            time.strftime("%Y,week%U", time.localtime(t)) + '",{}]'
    else:
        end_key = '["' + time_end.replace("-", " ") + ' 32' + '",{}]'
        # append last day, so inclusive end

    #  1. get json data from couchdb using the view
    #     group=true, group_level as calculated,
    #     start and end key as constructed

    # couchdb URL, default http://localhost:5984/
    # TODO use configuration.usagedb
    database = 'http://localhost:5984/usagerecords'

    [check, db_url, db_name] = database.rsplit('/', 2)
    if check and check != 'http:/':
        logger.debug('bad URL %s' % database)
        db_url = 'none'
        db_name = 'none'

    # views are organised in files per "timegrouping",
    # and contain views with names <category>-<timegrouping>
    query = '/'.join(['', db_name, '_design', group_in_time, '_view', view])
    query += '?'
    query += urllib.urlencode({
        'group': 'true',
        'group_level': group_level,
        'startkey': start_key,
        'endkey': end_key,
    })
    try:
        logger.debug("asking database at %s: %s" % (db_url, query))
        # Never use proxies
        res = urllib.urlopen('http://' + db_url + query, proxies={})
        jsonreply = res.read()
        res.close()
    except Exception, err:
        logger.error('Could not get data from database: %s' % err)
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Error accessing the database.'
        })
        jsonreply = '{"rows":[]}'
Ejemplo 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)
    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)
Ejemplo 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, op_header=False, op_menu=False)
    client_dir = client_id_dir(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)

    if not configuration.site_enable_openid or \
            not 'migoid' in configuration.site_signup_methods:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Local OpenID login is not enabled on this site'''
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s OpenID account request' % \
                          configuration.short_title
    title_entry['skipmenu'] = True
    form_fields = [
        'full_name', 'organization', 'email', 'country', 'state', 'password',
        'verifypassword', 'comment'
    ]
    title_entry['style']['advanced'] += account_css_helpers(configuration)
    add_import, add_init, add_ready = account_js_helpers(
        configuration, form_fields)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    title_entry['script']['body'] = "class='staticpage'"

    header_entry = {
        'object_type':
        'header',
        'text':
        'Welcome to the %s OpenID account request page' %
        configuration.short_title
    }
    output_objects.append(header_entry)

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
    <div id="contextual_help">

    </div>
'''
    })

    # 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

    user_fields = {
        'full_name': '',
        'organization': '',
        'email': '',
        'state': '',
        'country': '',
        'password': '',
        'verifypassword': ''
    }
    if not os.path.isdir(base_dir) and client_id:

        # Redirect to extcert page with certificate requirement but without
        # changing access method (CGI vs. WSGI).

        extcert_url = os.environ['REQUEST_URI'].replace('-sid', '-bin')
        extcert_url = os.path.join(os.path.dirname(extcert_url), 'extcert.py')
        extcert_link = {
            'object_type': 'link',
            'destination': extcert_url,
            'text': 'Sign up with existing certificate (%s)' % client_id
        }
        output_objects.append({
            'object_type':
            'warning',
            'text':
            '''Apparently
you already have a suitable %s certificate that you may sign up with:''' %
            configuration.short_title
        })
        output_objects.append(extcert_link)
        output_objects.append({
            'object_type':
            'warning',
            'text':
            '''However,
if you want a dedicated %s %s User OpenID you can still request one below:''' %
            (configuration.short_title, configuration.user_mig_oid_title)
        })
    elif client_id:
        for entry in (title_entry, header_entry):
            entry['text'] = entry['text'].replace('request', 'request / renew')
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''<p>
Apparently you already have valid %s credentials, but if you want to add %s
User OpenID access to the same account you can do so by posting the form below.
Changing fields is <span class="warningtext"> not </span> supported, so all fields
must remain unchanged for it to work.
Otherwise it results in a request for a new account and OpenID without access
to your old files, jobs and privileges. </p>''' %
            (configuration.short_title, configuration.user_mig_oid_title)
        })
        user_fields.update(distinguished_name_to_user(client_id))

    # Site policy dictates min length greater or equal than password_min_len
    policy_min_len, policy_min_classes = parse_password_policy(configuration)
    user_fields.update({
        'valid_name_chars':
        '%s (and common accents)' % html_escape(valid_name_chars),
        'valid_password_chars':
        html_escape(valid_password_chars),
        'password_min_len':
        max(policy_min_len, password_min_len),
        'password_max_len':
        password_max_len,
        'password_min_classes':
        max(policy_min_classes, 1),
        'site':
        configuration.short_title
    })
    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    target_op = 'reqoidaction'
    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})

    fill_helpers.update({'site_signup_hint': configuration.site_signup_hint})
    fill_helpers.update(user_fields)
    html = """
<p class="sub-title">Please enter your information in at least the <span>mandatory</span> fields below and press the Send button to submit the OpenID account request to the %(site)s administrators.</p>

%(site_signup_hint)s

<p class='criticaltext highlight_message'>
IMPORTANT: Please help us verify your identity by providing Organization and
Email data that we can easily validate!
</p>

<hr />

    """
    user_country = user_fields.get('country', '')
    html += account_request_template(configuration,
                                     default_country=user_country)

    # TODO: remove this legacy version?
    html += """
<div style="height: 0; visibility: hidden; display: none;">
<!--OLD FORM-->
<form method='%(form_method)s' action='%(target_op)s.py' onSubmit='return validate_form();'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />


<table>
<!-- NOTE: javascript support for unicode pattern matching is lacking so we
           only restrict e.g. Full Name to words separated by space here. The
           full check takes place in the backend, but users are better of with
           sane early warnings than the cryptic backend errors.
-->

<tr><td class='mandatory label'>Full name</td><td><input id='full_name_field' type=text name=cert_name value='%(full_name)s' required pattern='[^ ]+([ ][^ ]+)+' title='Your full name, i.e. two or more names separated by space' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=email name=email value='%(email)s' required title='A valid email address that you read' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(organization)s' required pattern='[^ ]+([ ][^ ]+)*' title='Name of your organisation: one or more abbreviations or words separated by space' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Two letter country-code</td><td><input id='country_field' type=text name=country minlength=2 maxlength=2 value='%(country)s' required pattern='[A-Z]{2}' title='The two capital letters used to abbreviate your country' /></td><td class=fill_space><br /></td></tr>
<tr><td class='optional label'>State</td><td><input id='state_field' type=text name=state value='%(state)s' pattern='([A-Z]{2})?' maxlength=2 title='Leave empty or enter the capital 2-letter abbreviation of your state if you are a US resident' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Password</td><td><input id='password_field' type=password name=password minlength=%(password_min_len)d maxlength=%(password_max_len)d value='%(password)s' required pattern='.{%(password_min_len)d,%(password_max_len)d}' title='Password of your choice, see help box for limitations' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Verify password</td><td><input id='verifypassword_field' type=password name=verifypassword minlength=%(password_min_len)d maxlength=%(password_max_len)d value='%(verifypassword)s' required pattern='.{%(password_min_len)d,%(password_max_len)d}' title='Repeat your chosen password' /></td><td class=fill_space><br /></td></tr>
<!-- NOTE: we technically allow saving the password on scrambled form hide it by default -->
<tr class='hidden'><td class='optional label'>Password recovery</td><td class=''><input id='passwordrecovery_checkbox' type=checkbox name=passwordrecovery></td>
</td><td class=fill_space><br/></td></tr>
<tr><td class='optional label'>Optional comment or reason why you should<br />be granted a %(site)s account:</td><td><textarea id='comment_field' rows=4 name=comment title='A free-form comment where you can explain what you need the account for' ></textarea></td><td class=fill_space><br /></td></tr>
<tr><td class='label'><!-- empty area --></td><td>

<input id='submit_button' type=submit value=Send /></td><td class=fill_space><br/></td></tr>
</table>
</form>
<hr />
<div class='warn_message'>Please note that if you enable password recovery your password will be saved on encoded format but recoverable by the %(site)s administrators</div>
</div>
<br />
<br />
<!-- Hidden help text -->
<div id='help_text'>
  <div id='1full_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div>
  <div id='1organization_help'>Organization name or acronym  matching email</div>
  <div id='1email_help'>Email address associated with your organization if at all possible</div>
  <div id='1country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='https://en.wikipedia.org/wiki/ISO_3166-1'>help</a></div>
  <div id='1state_help'>Optional 2-letter ANSI state code of your organization, please just leave empty unless it is in the US or similar, <a href='https://en.wikipedia.org/wiki/List_of_U.S._state_abbreviations'>help</a></div>
  <div id='1password_help'>Password is restricted to the characters:<br/><tt>%(valid_password_chars)s</tt><br/>Certain other complexity requirements apply for adequate strength. For example it must be %(password_min_len)s to %(password_max_len)s characters long and contain at least %(password_min_classes)d different character classes.</div>
  <div id='1verifypassword_help'>Please repeat password</div>
  <!--<div id='1comment_help'>Optional, but a short informative comment may help us verify your account needs and thus speed up our response. Typically the name of a local collaboration partner or project may be helpful.</div>-->
</div>

"""

    output_objects.append({
        'object_type': 'html_form',
        'text': html % fill_helpers
    })
    return (output_objects, returnvalues.OK)
Ejemplo 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, op_header=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)
    show = accepted['show'][-1].lower()
    search = accepted['search'][-1].lower()

    # Topic to generator-function mapping - add new topics here by adding an
    # anchor_name -> {'title': topic, 'generator': generator_function,
    #                 'arg': generator_args}
    # entry.

    default_args = (configuration, output_objects)
    all_docs = {
        'mrsl': {
            'title': 'Job description: mRSL',
            'generator': mrsl_keywords,
            'args': default_args
        },
        'resconf': {
            'title': 'Resource configuration',
            'generator': resconf_keywords,
            'args': default_args
        },
        'outformats': {
            'title': 'Valid outputformats',
            'generator': valid_outputformats,
            'args': default_args
        },
        'runtimeenv': {
            'title': 'Runtime Environments',
            'generator': runtime_environments,
            'args': default_args
        },
        'credits': {
            'title': 'License and Acknowledgements',
            'generator': license_information,
            'args': default_args
        },
    }

    output_objects.append({
        'object_type':
        'header',
        'text':
        '%s On-demand Documentation' % configuration.short_title
    })
    if not show:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''
This is the integrated help system for %s.
You can search for a documentation topic or select the particular
section directly.
Please note that the integrated help is rather limited to short overviews and
technical specifications.''' % configuration.short_title
        })

        output_objects.append({
            'object_type':
            'text',
            'text':
            '''
You can find more user friendly tutorials and examples on the
official site support pages:'''
        })
        output_objects.append({
            'object_type':
            'link',
            'destination':
            configuration.site_external_doc,
            'class':
            'urllink iconspace',
            'title':
            'external documentation',
            'text':
            'external %s documentation' % configuration.site_title,
            'plain_text':
            configuration.site_external_doc
        })

    html = '<br />Filter (using *,? etc.)'
    html += "<form method='get' action='docs.py'>"
    html += "<input type='hidden' name='show' value='' />"
    html += "<input type='text' name='search' value='' />"
    html += "<input type='submit' value='Filter' />"
    html += '</form><br />'
    output_objects.append({'object_type': 'html_form', 'text': html})

    # Fall back to show all topics

    if not search and not show:
        search = '*'

    if search:

        # Pattern matching: select all topics that _contain_ search pattern
        # i.e. like re.search rather than re.match

        search_keys = []
        for (key, val) in all_docs.items():

            # Match any prefix and suffix.
            # No problem with extra '*'s since'***' also matches 'a')

            topic = val['title']
            if fnmatch.fnmatch(topic.lower(), '*' + search + '*'):
                search_keys.append(key)

        output_objects.append({
            'object_type': 'header',
            'text': 'Documentation topics:'
        })
        for key in search_keys:
            display_topic(output_objects, key, all_docs)
        if not search_keys:
            output_objects.append({
                'object_type': 'text',
                'text': 'No topics matching %s' % search
            })

    if show:

        # Pattern matching: select all topics that _contain_ search pattern
        # i.e. like re.search rather than re.match

        show_keys = []
        for (key, val) in all_docs.items():

            # Match any prefix and suffix.
            # No problem with extra '*'s since'***' also matches 'a')

            topic = val['title']
            logger.info("match show %s vs %s or %s" % (show, topic, key))
            if fnmatch.fnmatch(topic.lower(), '*' + show + '*') or \
                    show == key:
                logger.info("found show match for %s" % show)
                show_keys.append(key)

        for key in show_keys:
            logger.info("show doc for %s" % key)
            display_doc(output_objects, key, all_docs)
        if not show_keys:
            output_objects.append({
                'object_type': 'text',
                'text': 'No topics matching %s' % show
            })

    return (output_objects, returnvalues.OK)
Ejemplo n.º 36
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)
    logger.info('Extracting input in %s' % op_name)
    status = returnvalues.OK
    defaults = signature()[1]

    logger.info('Extracted input in %s: %s' %
                (op_name, user_arguments_dict.keys()))

    # All non-file fields must be validated
    validate_args = dict([(key, user_arguments_dict.get(key, val))
                          for (key, val) in user_arguments_dict.items()
                          if not key in manual_validation])
    # IMPORTANT: we must explicitly inlude CSRF token
    validate_args[csrf_field] = user_arguments_dict.get(csrf_field, [''])
    (validate_status, accepted) = validate_input(
        validate_args,
        defaults,
        output_objects,
        allow_rejects=False,
    )
    if not validate_status:
        logger.error('%s validation failed: %s (%s)' %
                     (op_name, validate_status, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

    logger.info('validated input in %s: %s' % (op_name, validate_args.keys()))

    action = accepted['action'][-1]
    current_dir = os.path.normpath(accepted['current_dir'][-1].lstrip(os.sep))
    flags = ''.join(accepted['flags'])
    share_id = accepted['share_id'][-1]
    output_format = accepted['output_format'][-1]

    if action != "status":
        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)

    reject_write = False
    uploaded = []
    header_item = {'object_type': 'header', 'text': ''}
    # Always include a files reply even if empty
    output_objects.append(header_item)
    output_objects.append({'object_type': 'uploadfiles', 'files': uploaded})

    # Either authenticated user client_id set or sharelink ID
    if client_id:
        user_id = client_id
        target_dir = client_id_dir(client_id)
        base_dir = configuration.user_home
        redirect_name = configuration.site_user_redirect
        redirect_path = redirect_name
        id_args = ''
        page_title = 'Upload to User Directory: %s' % action
        userstyle = True
        widgets = True
    elif share_id:
        try:
            (share_mode, _) = extract_mode_id(configuration, share_id)
        except ValueError, err:
            logger.error('%s called with invalid share_id %s: %s' %
                         (op_name, share_id, err))
            output_objects.append({
                'object_type': 'error_text',
                'text': 'Invalid sharelink ID: %s' % share_id
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        # TODO: load and check sharelink pickle (currently requires client_id)
        user_id = 'anonymous user through share ID %s' % share_id
        # NOTE: we must return uploaded reply so we delay read-only failure
        if share_mode == 'read-only':
            logger.error('%s called without write access: %s' %
                         (op_name, accepted))
            reject_write = True
        target_dir = os.path.join(share_mode, share_id)
        base_dir = configuration.sharelink_home
        redirect_name = 'share_redirect'
        redirect_path = os.path.join(redirect_name, share_id)
        id_args = 'share_id=%s;' % share_id
        page_title = 'Upload to Shared Directory: %s' % action
        userstyle = False
        widgets = False
Ejemplo 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, op_header=False, op_menu=False)
    defaults = signature(configuration)[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    valid_show = get_valid_topics(configuration)
    if keyword_all in accepted['show']:
        show = valid_show.keys()
    else:
        show = [i.lower() for i in accepted['show'] if i.lower() in valid_show]
    if not show:
        logger.info('%s showing default topics' % op_name)
        show = defaults['show']
    openid_error = ', '.join(accepted['modauthopenid.error'])

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s login selector' % configuration.short_title
    # TODO: move ping to shared location for signup and login
    # TODO: wrap openid ping in function and split up for each oid
    title_entry['javascript'] = '''
<script type="text/javascript" src="/images/js/jquery.js"></script>
<script type="text/javascript" src="/images/js/jquery.migtools.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        var action = "login", oid_title, oid_url, tag_prefix;
        oid_title = "KIT";
        oid_url = "https://openid.ku.dk/id/";
        tag_prefix = "kitoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
        oid_title = "%s";
        var oid_url = "https://%s:%s/openid/id/";
        tag_prefix = "migoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
    });
</script>
''' % (configuration.short_title, configuration.user_openid_show_address,
       configuration.user_openid_show_port)
    title_entry['skipmenu'] = True
    header_entry = {'object_type': 'header', 'text'
                    : 'Welcome to the %s login selector page' % \
                    configuration.short_title}
    output_objects.append(header_entry)

    html = ""
    if openid_error:
        err_txt, report_txt = '', ''
        if 'no_idp_found' in openid_error:
            err_txt += "OpenID server did not respond!"
            report_txt += """It appears the requested OpenID login service is
offline"""
        else:
            err_txt += "OpenID server error!"
            report_txt += """It appears there's a problem with the requested
OpenID login service"""
        report_txt += """, so you cannot currently use it for login to %s.<br />
Please report the problem to your OpenID identity provider.
""" % configuration.short_title
        html += """<h2>OpenID Login to %s Failed!</h2>
<div class='errortext'>
%s (error code(s): %s)
</div>
<div class='warningtext'>
%s
</div>
""" % (configuration.short_title, err_txt, openid_error, report_txt)
    html += """<h2>Login to %s</h2>
<p>
There are multiple login methods as described below.
</p>
""" % configuration.short_title
    if configuration.user_openid_providers and 'kitoid' in show or \
           'migoid' in show:
        html += """<h2>OpenID</h2>
The simplest login method is to use an existing OpenID login if you have one.
"""
        if 'kitoid' in show:
            html += """
<p>
If you are a KU user, your usual login for KU Net and KU webmail works for
OpenID as well.
</p>
<div id='kitoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='kitoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(kitoid_url)s'>
<input id='kitoid_button' type='submit' value='Login with KU OpenID' />
</form>
</div>
"""
        if 'migoid' in show:
            html += """
<p>
If you already have a MiG OpenID account here you can login to the account
using the local MiG OpenID server.
<div id='migoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='migoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(migoid_url)s'>
<input id='migoid_button' type='submit' value='Login with MiG OpenID' />
</form>
</p>
</div>
"""
            
        html += """
<p>
When you click the Login with OpenID button you will be taken to a login
page, where you need to provide your credentials and accept that your identity
is used for login with this site.
</p>
"""

    if 'extcert' in show:
        html += """
<h2>Client Certificate</h2>
<p>
We provide high security access control with client certificates, like the ones
you may know from digital signature providers.
</p>
"""
        html += """
<p>
If you have an x509 user certificate associated with your account you can login
using it here.
Depending on your certificate installation you may be prompted for a password.
</p>
<div class='form_container'>
<form method='get' action='%(extcert_url)s'>
<input id='reqcert_button' type='submit' value='Login with Your User Certificate' />
</form>
</div>
"""
        html += """
"""
    var_map = {'kitoid_url': valid_show['kitoid']['url'],
               'migoid_url':valid_show['migoid']['url'],
               'extcert_url': valid_show['extcert']['url'],
               }
    output_objects.append({'object_type': 'html_form', 'text': html % var_map})
    return (output_objects, returnvalues.OK)
Ejemplo 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, 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]

    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

    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 '%s' to get the PGID!" % \
             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 on that variable.
    # exe_name is not automatically checked however - do it manually

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

        # out of bounds - rogue resource!?!?

        output_objects.append({
            'object_type': 'error_text',
            'text': 'invalid exe_name! %s' % exe_name
        })
        logger.error('''getrespgid 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)

    # Check that resource address matches request source to make DoS harder
    try:
        check_source_ip(remote_ip, unique_resource_name)
    except ValueError, vae:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'invalid request: %s' % vae
        })
        logger.error("Invalid put pgid: %s" % vae)
        return (output_objects, returnvalues.CLIENT_ERROR)
Ejemplo 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, 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)

    # Check that resource address matches request source to make DoS harder
    try:
        check_source_ip(remote_ip, unique_resource_name)
    except ValueError, vae:
        output_objects.append({'object_type': 'error_text', 'text':
                               'invalid request: %s' % vae})
        logger.error("Invalid put pgid: %s" % vae)
        return (output_objects, returnvalues.CLIENT_ERROR)
Ejemplo 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_menu=False)
    defaults = signature(configuration)[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
                                                 defaults,
                                                 output_objects,
                                                 allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    valid_show = get_valid_topics(configuration)
    if keyword_all in accepted['show']:
        show = valid_show.keys()
    else:
        show = [i.lower() for i in accepted['show']]
    show = [i for i in show if i in valid_show and valid_show[i]['url']]
    if not show:
        logger.info('%s showing default topics' % op_name)
        show = defaults['show']
    openid_error = ', '.join(accepted['modauthopenid.error'])
    # OpenID server errors may return here with redirect url set
    redirect_url = accepted['redirect_url'][-1]

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s login selector' % configuration.short_title
    add_import = '''
<script type="text/javascript" src="/images/js/jquery.ajaxhelpers.js"></script>
    '''
    add_init = ''
    add_ready = '''
        var action = "login", oid_title, oid_url, tag_prefix;
        oid_title = "%s";
        oid_url = "%s";
        tag_prefix = "extoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
        oid_title = "%s";
        var oid_url = "%s";
        tag_prefix = "migoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
''' % (configuration.user_ext_oid_title, configuration.user_ext_oid_provider,
       configuration.user_mig_oid_title, configuration.user_mig_oid_provider)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    title_entry['skipmenu'] = True
    # NOTE: keep empty header for narrow page layout
    header_entry = {
        'object_type': 'header',
        'text':
        # 'Welcome to the %s login selector page' % \
        #  configuration.short_title
        ''
    }
    output_objects.append(header_entry)

    html = ""
    if openid_error:
        err_txt, report_txt = '', ''
        report_fail = """, so you cannot currently use it for login to %s.
<br />
Please report the problem to your OpenID identity provider.
""" % configuration.short_title
        if redirect_url:
            report_fail += """<br />The error happened on access to %s ."""  \
                           % redirect_url

        if 'no_idp_found' in openid_error:
            err_txt += "OpenID server did not respond!"
            report_txt += """It appears the requested OpenID login service is
offline""" + report_fail
        elif 'canceled' in openid_error:
            err_txt += "OpenID login canceled!"
            report_txt += """You have to either enter your OpenID login and
accept that it is used for %s login or choose another one of the login methods
below.""" % configuration.short_title
        else:
            err_txt += "OpenID server error!"
            report_txt += """It appears there's a problem with the requested
OpenID login service""" + report_fail

        html += """<h2>OpenID Login to %s Failed!</h2>
<div class='errortext'>
%s (error code(s): %s)
</div>
<div class='warningtext'>
%s
</div>
""" % (configuration.short_title, err_txt, openid_error, report_txt)
    html += """<h2>Login to %s</h2>
<p>
There are multiple login methods as described below.
</p>
""" % configuration.short_title
    if configuration.user_openid_providers and 'extoid' in show or 'migoid' in show:
        html += """<h2>OpenID</h2>
<p>
The simplest login method is to use an existing OpenID login if you have one.
</p>
"""

        for method in show:
            if method == 'migoid':
                html += """
<p>
%(migoid_title)s users can login to %(short_title)s using the associated
OpenID server.
</p>
<div id='migoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='migoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(migoid_url)s'>
<input id='migoid_button' type='submit' value='%(migoid_title)s User OpenID Login' />
</form>
</div>
"""
            if method == 'extoid':
                html += """
<p>
%(extoid_title)s users can login to %(short_title)s using the associated
OpenID server.
</p>
<div id='extoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='extoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(extoid_url)s'>
<input id='extoid_button' type='submit' value='%(extoid_title)s User OpenID Login' />
</form>
</div>
"""

        html += """
<p>
When you click the OpenID Login button you will be taken to a login page, where
you need to provide your credentials and accept that your identity is used for
login on %(short_title)s.
</p>
"""

    if 'migcert' in show or 'extcert' in show:
        html += """
<h2>Client Certificate</h2>
<p>
We provide high security access control with client certificates, like the ones
you may know from digital signature providers.
</p>
"""
        for method in show:
            if method == 'migcert':
                html += """<p>
%(migcert_title)s users with an associated x509 certificate can use it for
login here.
</p>
<div class='form_container'>
<form method='get' action='%(migcert_url)s'>
<input id='reqcert_button' type='submit' value='%(migcert_title)s User Certificate Login' />
</form>
</div>
"""
            if method == 'extcert':
                html += """<p>
%(extcert_title)s users with an associated x509 certificate can use it for
login here.
</p>
<div class='form_container'>
<form method='get' action='%(extcert_url)s'>
<input id='reqcert_button' type='submit' value='%(extcert_title)s User Certificate Login' />
</form>
</div>
"""
        html += """
<p>
Depending on your certificate installation you may be prompted for a password
to use the certificate.
</p>
"""
    var_map = {
        'migoid_url': valid_show['migoid']['url'],
        'migoid_title': configuration.user_mig_oid_title,
        'extoid_url': valid_show['extoid']['url'],
        'extoid_title': configuration.user_ext_oid_title,
        'migcert_url': valid_show['migcert']['url'],
        'migcert_title': configuration.user_mig_cert_title,
        'extcert_url': valid_show['extcert']['url'],
        'extcert_title': configuration.user_ext_cert_title,
        'short_title': configuration.short_title
    }
    output_objects.append({'object_type': 'html_form', 'text': html % var_map})
    return (output_objects, returnvalues.OK)
Ejemplo 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,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox Download' % \
                            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)

    username = accepted['username'][-1]
    password = accepted['password'][-1]
    hd_size = accepted['hd_size'][-1]
    image_format = accepted['image_format'][-1]
    net_bw = accepted['net_bw'][-1]
    memory = accepted['memory'][-1]
    operating_system = accepted['operating_system'][-1]
    win_solution = accepted['win_solution'][-1]
    vgrid_list = accepted['vgrid']
    cputime = 1000000
    sandboxkey = hexlify(open('/dev/urandom').read(32))
    ip_address = 'UNKNOWN'
    if os.environ.has_key('REMOTE_ADDR'):
        ip_address = os.environ['REMOTE_ADDR']

    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 safe_handler(configuration, 'post', op_name, username,
                        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)

    # check that requested image format is valid

    if not image_format in ['raw', 'qcow', 'cow', 'qcow2', 'vmdk']:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Unsupported image format: %s' % image_format
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # check that requested vgrids are valid - anybody can offer their sandbox
    # for a vgrid but it is still left to the vgrid owners to explicitly
    # accept all resources

    all_vgrids = get_vgrid_map_vgrids(configuration)
    for vgrid in vgrid_list:
        if not vgrid in all_vgrids:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to validate %s %s: %s' %
                (configuration.site_vgrid_label, vgrid, all_vgrids)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

    # Load the user file

    try:
        userdb = load_sandbox_db(configuration)
    except Exception, exc:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Failed to read login info: %s' % exc
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)
Ejemplo 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, 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)
Ejemplo n.º 43
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)
    logger = configuration.logger
    logger.info('%s: args: %s' % (op_name, user_arguments_dict))
    prefilter_map = {}
    
    output_objects.append({'object_type': 'header', 'text'
                          : 'Automatic %s sign up' % \
                            configuration.short_title })
    identity = extract_client_openid(configuration, environ, lookup_dn=False)
    if client_id and client_id == identity:
        login_type = 'cert'
        base_url = configuration.migserver_https_cert_url
    elif identity:
        login_type = 'oid'
        base_url = configuration.migserver_https_oid_url
        for name in ('openid.sreg.cn', 'openid.sreg.fullname',
                     'openid.sreg.full_name'):
            prefilter_map[name] = filter_commonname
    else:
        output_objects.append(
            {'object_type': 'error_text', 'text': 'Missing user credentials'})
        return (output_objects, returnvalues.CLIENT_ERROR)
    defaults = signature(login_type)[1]
    (validate_status, accepted) = validate_input(
        user_arguments_dict, defaults, output_objects, allow_rejects=False,
        prefilter_map=prefilter_map)
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

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

    # Unfortunately OpenID redirect does not use POST
    if login_type != 'oid' and 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)

    admin_email = configuration.admin_email
    openid_names, oid_extras = [], {}

    # Extract raw values
    if login_type == 'cert':
        uniq_id = accepted['cert_id'][-1].strip()
        raw_name = accepted['cert_name'][-1].strip()
        country = accepted['country'][-1].strip()
        state = accepted['state'][-1].strip()
        org = accepted['org'][-1].strip()
        org_unit = ''
        role = ','.join([i for i in accepted['role'] if i])
        locality = ''
        timezone = ''
        email = accepted['email'][-1].strip()
        raw_login = None
    elif login_type == 'oid':
        uniq_id = accepted['openid.sreg.nickname'][-1].strip() or \
                   accepted['openid.sreg.short_id'][-1].strip()
        raw_name = accepted['openid.sreg.fullname'][-1].strip() or \
                    accepted['openid.sreg.full_name'][-1].strip()
        country = accepted['openid.sreg.country'][-1].strip()
        state = accepted['openid.sreg.state'][-1].strip()
        org = accepted['openid.sreg.o'][-1].strip() or \
              accepted['openid.sreg.organization'][-1].strip()
        org_unit = accepted['openid.sreg.ou'][-1].strip() or \
                   accepted['openid.sreg.organizational_unit'][-1].strip()
        # We may receive multiple roles
        role = ','.join([i for i in accepted['openid.sreg.role'] if i])
        locality = accepted['openid.sreg.locality'][-1].strip()
        timezone = accepted['openid.sreg.timezone'][-1].strip()
        email = accepted['openid.sreg.email'][-1].strip()

    # Fix case of values:
    # 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.
    try:
        full_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        logger.warning("could not use unicode form to capitalize full name")
        full_name = raw_name.title()
    country = country.upper()
    state = state.upper()
    email = email.lower()

    if login_type == 'oid':
        # Remap some oid attributes if on kit format with faculty in
        # organization and institute in organizational_unit. We can add them
        # as different fields as long as we make sure the x509 fields are
        # preserved.
        # We do that to allow autocreate updating existing cert users.
        
        if org_unit not in ('', 'NA'):
            org_unit = org_unit.upper()
            oid_extras['faculty'] = org
            oid_extras['institute'] = org_unit
            org = org_unit.upper()
            org_unit = 'NA'

        # Stay on virtual host - extra useful while we test dual OpenID
        base_url = environ.get('REQUEST_URI',
                               base_url).split('?')[0].replace('autocreate',
                                                               'fileman')
        raw_login = None
        for oid_provider in configuration.user_openid_providers:
            openid_prefix = oid_provider.rstrip('/') + '/'
            if identity.startswith(openid_prefix):
                raw_login = identity.replace(openid_prefix, '')
                break

    if raw_login:
        openid_names.append(raw_login)

    # we should have the proxy file read...
    proxy_content = accepted['proxy_upload'][-1]

    # keep comment to a single line

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

    # single quotes break command line format - remove

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

    user_dict = {
        'short_id': uniq_id,
        'full_name': full_name,
        'organization': org,
        'organizational_unit': org_unit,
        'locality': locality,
        'state': state,
        'country': country,
        'email': email,
        'role': role,
        'timezone': timezone,
        'password': '',
        'comment': '%s: %s' % ('Existing certificate', comment),
        'openid_names': openid_names,
        }
    user_dict.update(oid_extras)

    # We must receive some ID from the provider
    if not uniq_id and not email:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'No ID information received!'})
        if accepted.get('openid.sreg.required', '') and \
               identity:
            # Stay on virtual host - extra useful while we test dual OpenID
            url = environ.get('REQUEST_URI',
                              base_url).split('?')[0].replace('autocreate',
                                                              'logout')
            output_objects.append(
                {'object_type': 'text', 'text': '''Please note that sign-up
for OpenID access does not work if you are already signed in with your OpenID
provider - and that appears to be the case now.
You probably have to reload this page after you explicitly '''})
            output_objects.append(        
                {'object_type': 'link', 'destination': url,
                 'target': '_blank', 'text': "Logout"
                 })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if login_type == 'cert':
        user_dict['expire'] = int(time.time() + cert_valid_days * 24 * 60 * 60)
        try:
            distinguished_name_to_user(uniq_id)
            user_dict['distinguished_name'] = uniq_id
        except:
            output_objects.append({'object_type': 'error_text', 'text'
                                   : '''Illegal Distinguished name:
Please note that the distinguished name must be a valid certificate DN with
multiple "key=val" fields separated by "/".
'''})
            return (output_objects, returnvalues.CLIENT_ERROR)
    elif login_type == 'oid':
        user_dict['expire'] = int(time.time() + oid_valid_days * 24 * 60 * 60)
        fill_distinguished_name(user_dict)
        uniq_id = user_dict['distinguished_name']

    # If server allows automatic addition of users with a CA validated cert
    # we create the user immediately and skip mail
    
    if login_type == 'cert' and configuration.auto_add_cert_user or \
           login_type == 'oid' and configuration.auto_add_oid_user:
        fill_user(user_dict)

        logger.info('create user: %s' % user_dict)
        
        # Now all user fields are set and we can begin adding the user

        db_path = os.path.join(configuration.mig_server_home, user_db_filename)
        try:
            create_user(user_dict, configuration.config_file, 
                        db_path, ask_renew=False, default_renew=True)
            if configuration.site_enable_griddk and \
                   accepted['proxy_upload'] != ['']:
                # save the file, display expiration date
                proxy_out = handle_proxy(proxy_content, uniq_id, 
                                         configuration)
                output_objects.extend(proxy_out)
        except Exception, err:
            logger.error('create failed for %s: %s' % (uniq_id, err))
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '''Could not create the user account for you:
Please report this problem to the grid administrators (%s).''' % \
                 admin_email})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({'object_type': 'html_form', 'text'
                                   : '''Created the user account for you -
please open <a href="%s">your personal page</a> to proceed using it.
''' % base_url})
        return (output_objects, returnvalues.OK)
Ejemplo 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, op_menu=False)
    defaults = signature(configuration)[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    valid_show = get_valid_topics(configuration)
    if keyword_all in accepted['show']:
        show = valid_show.keys()
    else:
        show = [i.lower() for i in accepted['show'] if i.lower() in valid_show]
    if not show:
        logger.info('%s showing default topics' % op_name)
        show = defaults['show']

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s account sign up' % configuration.short_title
    title_entry['javascript'] = '''
<script type="text/javascript" src="/images/js/jquery.js"></script>
<script type="text/javascript" src="/images/js/jquery.migtools.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        var action = "sign up", oid_title, oid_url, tag_prefix;
        oid_title = "KIT";
        oid_url = "https://openid.ku.dk/id/";
        tag_prefix = "kitoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
        oid_title = "%s";
        var oid_url = "https://%s:%s/openid/id/";
        tag_prefix = "migoid_";
        check_oid_available(action, oid_title, oid_url, tag_prefix);
    });
</script>
''' % (configuration.short_title, configuration.user_openid_show_address,
       configuration.user_openid_show_port)
    title_entry['skipmenu'] = True
    header_entry = {'object_type': 'header', 'text'
                    : 'Welcome to the %s account sign up page' % \
                    configuration.short_title}
    output_objects.append(header_entry)

    html = """<h2>Signup for %s</h2>
<p>
Before you can use this site you need a user account. You can sign up for one
here as described below.
</p>
""" % configuration.short_title
    if configuration.user_openid_providers and 'kitoid' in show or \
           'migoid' in show:
        html += """<h2>OpenID</h2>
The simplest sign up method is to use an existing OpenID login if you have one.
"""
        if 'kitoid' in show:
            html += """
<p>
If you are a KU user, your usual login for KU Net and KU webmail works for
OpenID as well.
</p>
<div id='kitoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='kitoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(kitoid_url)s'>
<input type='hidden' name='openid.ns' value='http://specs.openid.net/auth/2.0' />
<input type='hidden' name='openid.ns.sreg' value='http://openid.net/extensions/sreg/1.1' />
<input type='hidden' name='openid.sreg.required' value='nickname,fullname,email,o,ou,country,state,role' />
<input id='kitoid_button' type='submit' value='Sign Up with KU OpenID' />
</form>
</div>
"""
        if 'migoid' in show:
            html += """
<p>
If you already have a MiG user certificate and account here you can sign up for
OpenID access to the account using the local MiG OpenID server.
<div id='migoid_status'>
<!-- OpenID status updated by AJAX call -->
</div>
<div id='migoid_debug'>
<!-- OpenID debug updated by AJAX call -->
</div>
<div class='form_container'>
<form method='post' action='%(migoid_url)s'>
<input type='hidden' name='openid.ns' value='http://specs.openid.net/auth/2.0' />
<input type='hidden' name='openid.ns.sreg' value='http://openid.net/extensions/sreg/1.1' />
<input type='hidden' name='openid.sreg.required' value='nickname,fullname,email,o,ou,country,state,role' />
<input id='migoid_button' type='submit' value='Sign Up with MiG OpenID' />
</form>
</p>
</div>
"""
            
        html += """
<p>
When you click the Sign Up with OpenID button you will be taken to a login
page where you need to enter your credentials and accept that your identity is
used for login with this site as well.
</p>
"""

    if 'migcert' in show or 'extcert' in show:
        html += """
<h2>Client Certificate</h2>
<p>
We provide high security access control with client certificates, like the ones
you may know from digital signature providers. It is a bit cumbersome to get
and install such a client certificate, so if you want to keep it simple and
have other access options, you may want to use those instead.
</p>
"""
        if 'migcert' in show:
            html += """
<p>
You can sign up for an account with an associated x509 user certificate here.
</p>
<div class='form_container'>
<form method='get' action='%(migcert_url)s'>
<input id='reqcert_button' type='submit' value='Sign Up for a User Certificate' />
</form>
</div>
"""
        if 'extcert' in show:
            html += """
<p>
If you already have an x509 user certificate that we trust, you can also sign
up with that instead of requesting a new one.
</p>
<div class='form_container'>
<form method='get' action='%(extcert_url)s'>
<input id='extcert_button' type='submit' value='Sign Up with Existing User Certificate' />
</form>
</div>
"""
        html += """
"""
    var_map = {'kitoid_url': valid_show['kitoid']['url'],
               'migoid_url':valid_show['migoid']['url'],
               'migcert_url': valid_show['migcert']['url'],
               'extcert_url': valid_show['extcert']['url'],
               }
    output_objects.append({'object_type': 'html_form', 'text': html % var_map})
    return (output_objects, returnvalues.OK)
Ejemplo 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)
    output_objects.append({'object_type': 'header', 'text':
                           'Grid Usage Statistics'})
    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)

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

    # read view options
    group_in_time = accepted['group_in_time'][-1] # day, week, month
    time_start = accepted['time_start'][-1]
    time_end = accepted['time_end'][-1]
    display = accepted['display'][-1] # machine, user, vgrid, summary

    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)

    # check arguments against configured lists of valid inputs:
    reject = False

    # make sure: grouping in ['user','machine', 'vgrid']
    if not display in displays:
        output_objects.append({'object_type': 'error_text', 'text'
                   : 'invalid display grouping specified: %s' % display })
        display = displays[0]
        reject = True
    # make sure: group_in_time in ['all', 'month', 'day', 'week']
    if not group_in_time in time_groups:
        output_objects.append({'object_type': 'error_text', 'text'
                   : 'invalid time grouping specified: %s' % group_in_time })
        group_in_time = time_groups[0]
        reject = True
    # make sure: start and end match "20[0-9]{2}-[01][0-9]"
    if not re.match('20\d\d-[01]\d', time_start):
        output_objects.append({'object_type': 'error_text', 'text'
                   : 'invalid start time specified: %s' % time_start })
        time_start = '2009-09'
        reject = True

    if not re.match('20\d\d-[01]\d', time_end):
        output_objects.append({'object_type': 'error_text', 'text'
                    : 'invalid end time specified: %s' % time_end })
        time_end = time.strftime('%Y-%m')
        reject = True

    # always include a form to re-display with different values:
    updateform = '           <form action="%s" >' %  \
                 os.path.basename(requested_page())
    updateform +='''
                <table class="runtimeenventry">
                  <thead>
                    <tr>
                    <th>Grouping by time</th>
                    <th>Start (YYYY-MM)</th>
                    <th>End (YYYY-MM)</th>
                    <th>Category</th>
                    <th><!-- dummy for update button --></th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>
                        <select name="group_in_time">
'''
#     updateform += \
#      ''.join([ '\n<option value="' + t + '">' + t.title() + '</option>'
#                for t in time_groups ])
    for t in time_groups:
        updateform +='<option '
        if group_in_time == t:
            updateform += 'selected '
        updateform += 'value="' + t + '">' + t.title() + '</option>\n'
    updateform +='''
                        </select>
                      </td>
                      <td><input type="text" name="time_start" value="%s"></td>
                      <td><input type="text" name="time_end" value="%s"></td>
''' %  (time_start, time_end) + '''
                      <td><select name="display">
'''
#     updateform += \
#     ''.join([ '\n<option value="' + d + '">' + d.title() + '</option>'
#                 for d in displays ])
    for d in displays:
        updateform +='<option '
        if display == d:
            updateform += 'selected '
        updateform += 'value="' + d + '">' + d.title() + '</option>\n'
    updateform +='''
                        </select>
                      </td>
                      <td><input type="submit" value="Update View"></td>
                    </tr>
                  </tbody>  
                </table>
            </form>
            <hr>
'''

    output_objects.append({'object_type': 'html_form', 'text': updateform})
    if reject:
        output_objects.append({'object_type': 'text', 'text'
                   : 'Please check your view parameters.'})
        return(output_objects, returnvalues.CLIENT_ERROR)

    # else: all parameters OK, go:

    # determine the view and group level to use:

    # we use couchdb views with name convention <group-in-time>-<display>
    view = group_in_time + '-' + display

    # default group-level (max. 2 view components relevant)
    group_level = 2

    # could handle summary display specially, by setting group_level = 1
    # and using either <time>-machine or <time>-user view
#    if display == 'summary':
#        display = 'user'
#        group_level = 1

    # construct start and end key.

    # machine and user cannot be filtered from the user, only 
    # time can be specified, and as YYYY-MM only.
    # for view per week, we have to convert it to a week number
    # python starts by week 0, whereas javascript starts by week 1
    if group_in_time == 'week':
        t = time.strptime(time_start + '-07',"%Y-%m-%d")
        time_start = time.strftime("%Y,week%U",t)

    start_key = '["'+ time_start.replace("-"," ") + '",null]'
    # 2nd component: user or machine
    # TODO allow only own user ID and only machines owned???
    # drawback: cannot restrict user/machine when requesting more than one time period 
    # To restrict user/machine, views which have this as the first key part 
    # have to be used. In which case only one user can be selected 
    # to keep the time period selection valid.

    if group_in_time == 'week':
        # last week of the month = first week 1 month later
        # we better compute this instead of tweaking the input
        t = time.mktime(time.strptime(time_end + '-28',"%Y-%m-%d"))
        t += 7*24*3600
        end_key = '["'+ time.strftime("%Y,week%U",time.localtime(t)) + '",{}]'
    else:
        end_key = '["'+ time_end.replace("-"," ") + ' 32' + '",{}]'
        # append last day, so inclusive end

    #  1. get json data from couchdb using the view
    #     group=true, group_level as calculated,
    #     start and end key as constructed

    # couchdb URL, default http://localhost:5984/
    # TODO use configuration.usagedb
    database ='http://localhost:5984/usagerecords' 

    [check,db_url,db_name] = database.rsplit('/',2)
    if check and check != 'http:/':
        logger.debug('bad URL %s' % database)
        db_url = 'none'
        db_name = 'none'
    
    # views are organised in files per "timegrouping",
    # and contain views with names <category>-<timegrouping>
    query = '/'.join(['',db_name,'_design' ,group_in_time,'_view',view])
    query += '?'
    query += urllib.urlencode({'group'      : 'true',
                               'group_level': group_level,
                               'startkey'   : start_key,
                               'endkey'     : end_key,
                               })
    try:
        logger.debug("asking database at %s: %s" % (db_url,query))
        res = urllib.urlopen('http://' + db_url + query)
        jsonreply = res.read()
        res.close()
    except Exception, err:
        logger.error('Could not get data from database: %s' % err)
        output_objects.append({'object_type': 'error_text', 'text'
                   : 'Error accessing the database.' })
        jsonreply = '{"rows":[]}'
Ejemplo 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, 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)
Ejemplo 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, op_header=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)
    show = accepted['show'][-1].lower()
    search = accepted['search'][-1].lower()

    # Topic to generator-function mapping - add new topics here by adding an
    # anchor_name -> {'title': topic, 'generator': generator_function,
    #                 'arg': generator_args}
    # entry.

    default_args = (configuration, output_objects)
    all_docs = {
        'mrsl':{'title': 'Job description: mRSL', 'generator': mrsl_keywords,
                'args': default_args},
        'resconf': {'title': 'Resource configuration', 'generator':
                    resconf_keywords, 'args': default_args},
        'outformats': {'title': 'Valid outputformats', 'generator':
                       valid_outputformats, 'args': default_args},
        'runtimeenv': {'title': 'Runtime Environments', 'generator':
                       runtime_environments, 'args': default_args},
        'credits': {'title': 'License and Acknowledgements', 'generator':
                    license_information, 'args': default_args},
                }

    output_objects.append({'object_type': 'header', 'text'
                          : '%s On-demand Documentation' % \
                            configuration.short_title})
    if not show:
        output_objects.append({'object_type': 'text',
                               'text': '''
This is the integrated help system for %s.
You can search for a documentation topic or select the particular
section directly.
Please note that the integrated help is rather limited to short overviews and
technical specifications.''' % configuration.short_title})

        output_objects.append({'object_type': 'text',
                               'text': '''
You can find more user friendly tutorials and examples on the
official site support pages:'''})
        output_objects.append({'object_type': 'link', 'destination':
                               configuration.site_external_doc,
                               'class': 'urllink', 'title':
                               'external documentation',
                               'text': 'external %s documentation' % \
                               configuration.site_title,
                               'plain_text': configuration.site_external_doc})

    html = '<br />Filter (using *,? etc.)'
    html += "<form method='post' action='docs.py'>"
    html += "<input type='hidden' name='show' value='' />"
    html += "<input type='text' name='search' value='' />"
    html += "<input type='submit' value='Filter' />"
    html += '</form><br />'
    output_objects.append({'object_type': 'html_form', 'text': html})

    # Fall back to show all topics

    if not search and not show:
        search = '*'

    if search:

        # Pattern matching: select all topics that _contain_ search pattern
        # i.e. like re.search rather than re.match

        search_keys = []
        for (key, val) in all_docs.items():

            # Match any prefix and suffix.
            # No problem with extra '*'s since'***' also matches 'a')

            topic = val['title']
            if fnmatch.fnmatch(topic.lower(), '*' + search + '*'):
                search_keys.append(key)

        output_objects.append({'object_type': 'header', 'text'
                              : 'Documentation topics:'})
        for key in search_keys:
            display_topic(output_objects, key, all_docs)
        if not search_keys:
            output_objects.append({'object_type': 'text', 'text'
                                  : 'No topics matching %s' % search})

    if show:

        # Pattern matching: select all topics that _contain_ search pattern
        # i.e. like re.search rather than re.match

        show_keys = []
        for (key, val) in all_docs.items():

            # Match any prefix and suffix.
            # No problem with extra '*'s since'***' also matches 'a')

            topic = val['title']
            logger.info("match show %s vs %s or %s" % (show, topic, key))
            if fnmatch.fnmatch(topic.lower(), '*' + show + '*') or \
                   show == key:
                logger.info("found show match for %s" % show)
                show_keys.append(key)

        for key in show_keys:
            logger.info("show doc for %s" % key)
            display_doc(output_objects, key, all_docs)
        if not show_keys:
            output_objects.append({'object_type': 'text', 'text'
                                  : 'No topics matching %s' % show})

    return (output_objects, returnvalues.OK)
Ejemplo 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)
    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)
Ejemplo 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, 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 site 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)