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

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Reject %s Request" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Reject %s Request' % label
    })
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    request_name = unhexlify(accepted['request_name'][-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)

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, request_name,
                                  'request', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

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

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

    if request_name:
        request_dir = os.path.join(configuration.vgrid_home, vgrid_name)
        req = load_access_request(configuration, request_dir, request_name)
    if not req or not delete_access_request(configuration, request_dir,
                                            request_name):
        logger.error("failed to delete owner request for %s in %s" % \
                     (vgrid_name, request_name))
        output_objects.append({
            'object_type': 'error_text', 'text':
            'Failed to remove saved vgrid request for %s in %s!'\
            % (vgrid_name, request_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)
    output_objects.append({
        'object_type':
        'text',
        'text':
        '''
Deleted %(request_type)s access request to %(target)s for %(entity)s .
''' % req
    })
    if req['request_type'] == 'vgridresource':
        id_field = "unique_resource_name"
    else:
        id_field = "cert_id"
    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'protocol': any_protocol,
        'id_field': id_field,
        'vgrid_label': label,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    fill_helpers.update(req)
    target_op = 'sendrequestaction'
    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':
        'html_form',
        'text':
        """
<p>
You can use the reply form below if you want to additionally send an
explanation for rejecting the request.
</p>
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type=hidden name=request_type value='vgridreject' />
<input type=hidden name=vgrid_name value='%(target)s' />
<input type=hidden name=%(id_field)s value='%(entity)s' />
<input type=hidden name=protocol value='%(protocol)s' />
<table>
<tr>
<td class='title'>Optional reject message to requestor(s)</td>
</tr><tr>
<td><textarea name=request_text cols=72 rows=10>
We have decided to reject your %(request_type)s request to our %(target)s
%(vgrid_label)s.

Regards, the %(target)s %(vgrid_label)s owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform requestor(s)' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
    })
    output_objects.append({
        'object_type': 'link',
        'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name,
        'text': 'Back to administration for %s' % vgrid_name
    })
    return (output_objects, returnvalues.OK)
Exemplo n.º 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)
    defaults = signature()[1]
    status = returnvalues.OK
    output_objects.append({
        'object_type': 'header',
        'text': 'Add Resource Owner(s)'
    })
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1].strip()
    cert_id_list = accepted['cert_id']
    request_name = unhexlify(accepted['request_name'][-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)

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'You must be an owner of %s to add a new owner!' %
            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

    cert_id_added = []
    for cert_id in cert_id_list:
        cert_id = cert_id.strip()
        if not cert_id:
            continue
        if not is_user(cert_id, configuration.mig_server_home):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is not a valid %s user!' %
                (cert_id, configuration.short_title)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already an owner

        if resource_is_owner(unique_resource_name, cert_id, configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is already an owner of %s.' %
                (cert_id, unique_resource_name)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # Add owner

        (add_status, add_msg) = resource_add_owners(configuration,
                                                    unique_resource_name,
                                                    [cert_id])
        if not add_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not add new owner, reason: %s' % add_msg
            })
            status = returnvalues.SYSTEM_ERROR
            continue
        cert_id_added.append(cert_id)

    if request_name:
        request_dir = os.path.join(configuration.resource_home,
                                   unique_resource_name)
        if not delete_access_request(configuration, request_dir, request_name):
            logger.error("failed to delete owner request for %s in %s" % \
                         (unique_resource_name, request_name))
            output_objects.append({
                'object_type': 'error_text', 'text':
                'Failed to remove saved request for %s in %s!' % \
                (unique_resource_name, request_name)})

    if cert_id_added:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            'New owner(s)<br/>%s<br/>successfully added to %s!' %
            ('<br />'.join(cert_id_added), unique_resource_name)
        })
        cert_id_fields = ''
        for cert_id in cert_id_added:
            cert_id_fields += """<input type=hidden name=cert_id value='%s' />
""" % cert_id

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers = {
            'res_id': unique_resource_name,
            'cert_id_fields': cert_id_fields,
            'any_protocol': any_protocol,
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit
        }
        target_op = 'sendrequestaction'
        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':
            'html_form',
            'text':
            """
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type=hidden name=request_type value='resourceaccept' />
<input type=hidden name=unique_resource_name value='%(res_id)s' />
%(cert_id_fields)s
<input type=hidden name=protocol value='%(any_protocol)s' />
<table>
<tr>
<td class='title'>Custom message to user(s)</td>
</tr>
<tr>
<td><textarea name=request_text cols=72 rows=10>
We have granted you ownership access to our %(res_id)s resource.
You can access the resource administration page from the Resources page.

Regards, the %(res_id)s resource owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform user(s)' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
        })

    output_objects.append({'object_type': 'link', 'destination':
                           'resadmin.py?unique_resource_name=%s' % \
                           unique_resource_name, 'class':
                           'adminlink iconspace', 'title':
                           'Administrate resource', 'text': 'Manage resource'})
    return (output_objects, status)
Exemplo 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)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Add %s Resource" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Add %s Resource(s)' % label
    })
    status = returnvalues.OK
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    res_id_list = accepted['unique_resource_name']
    request_name = unhexlify(accepted['request_name'][-1])
    rank_list = accepted['rank'] + ['' for _ in res_id_list]

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_map = get_full_user_map(configuration)
    user_dict = user_map.get(client_id, None)
    # Optional site-wide limitation of manage vgrid permission
    if not user_dict or \
            not vgrid_manage_allowed(configuration, user_dict):
        logger.warning("user %s is not allowed to manage vgrids!" % client_id)
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Only privileged users can manage %ss' % label
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # make sure vgrid settings allow this owner to edit resources

    (allow_status, allow_msg) = allow_resources_adm(configuration, vgrid_name,
                                                    client_id)
    if not allow_status:
        output_objects.append({'object_type': 'error_text', 'text': allow_msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    res_id_added = []
    for (res_id, rank_str) in zip(res_id_list, rank_list):
        unique_resource_name = res_id.lower().strip()
        try:
            rank = int(rank_str)
        except ValueError:
            rank = None

        # Validity of user and vgrid names is checked in this init function so
        # no need to worry about illegal directory traversal through variables

        (ret_val, msg, ret_variables) = \
            init_vgrid_script_add_rem(vgrid_name, client_id,
                                      unique_resource_name, 'resource',
                                      configuration)
        if not ret_val:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            status = returnvalues.CLIENT_ERROR
            continue
        elif msg:

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

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

        # don't add if already in vgrid or parent vgrid unless rank is given

        if rank is None and vgrid_is_resource(vgrid_name, unique_resource_name,
                                              configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is already a resource in the %s' %
                (unique_resource_name, label)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already in subvgrid

        (list_status,
         subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration)
        if not list_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error getting list of sub%ss: %s' % (label, subvgrids)
            })
            status = returnvalues.SYSTEM_ERROR
            continue
        skip_entity = False
        for subvgrid in subvgrids:
            if vgrid_is_resource(subvgrid,
                                 unique_resource_name,
                                 configuration,
                                 recursive=False):
                output_objects.append({
                    'object_type': 'error_text',
                    'text': '''%(res_name)s is already in a
sub-%(vgrid_label)s (%(subvgrid)s). Please remove the resource from the
sub-%(vgrid_label)s and try again''' % {
                        'res_name': unique_resource_name,
                        'subvgrid': subvgrid,
                        'vgrid_label': label
                    }
                })
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
        if skip_entity:
            continue

        # Check if only rank change was requested and apply if so

        if rank is not None:
            (add_status, add_msg) = vgrid_add_resources(configuration,
                                                        vgrid_name,
                                                        [unique_resource_name],
                                                        rank=rank)
            if not add_status:
                output_objects.append({
                    'object_type': 'error_text',
                    'text': add_msg
                })
                status = returnvalues.SYSTEM_ERROR
            else:
                output_objects.append({
                    'object_type':
                    'text',
                    'text':
                    'changed %s to resource %d' % (res_id, rank)
                })
            # No further action after rank change as everything else exists
            continue

        # Getting here means res_id is neither resource of any parent or
        # sub-vgrids.

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

        base_dir = os.path.abspath(configuration.vgrid_home + os.sep +
                                   vgrid_name) + os.sep
        resources_file = base_dir + 'resources'

        # Add to list and pickle

        (add_status, add_msg) = vgrid_add_resources(configuration, vgrid_name,
                                                    [unique_resource_name])
        if not add_status:
            output_objects.append({
                'object_type': 'error_text',
                'text': '%s' % add_msg
            })
            status = returnvalues.SYSTEM_ERROR
            continue
        res_id_added.append(unique_resource_name)

    if request_name:
        request_dir = os.path.join(configuration.vgrid_home, vgrid_name)
        if not delete_access_request(configuration, request_dir, request_name):
            logger.error("failed to delete res request for %s in %s" %
                         (vgrid_name, request_name))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to remove saved request for %s in %s!' %
                (vgrid_name, request_name)
            })

    if res_id_added:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            'New resource(s)<br />%s<br />successfully added to %s %s!'
            '' % ('<br />'.join(res_id_added), vgrid_name, label)
        })
        res_id_fields = ''
        for res_id in res_id_added:
            res_id_fields += """
<input type=hidden name=unique_resource_name value='%s' />""" % res_id

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers = {
            'vgrid_name': vgrid_name,
            'unique_resource_name': unique_resource_name,
            'protocol': any_protocol,
            'short_title': configuration.short_title,
            'vgrid_label': label,
            'res_id_fields': res_id_fields,
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit
        }
        target_op = 'sendrequestaction'
        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':
            'html_form',
            'text':
            """
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type=hidden name=request_type value='vgridaccept' />
<input type=hidden name=vgrid_name value='%(vgrid_name)s' />
%(res_id_fields)s
<input type=hidden name=protocol value='%(protocol)s' />
<table>
<tr>
<td class='title'>Custom message to resource owners</td>
</tr><tr>
<td><textarea name=request_text cols=72 rows=10>
We have granted your %(unique_resource_name)s resource access to our
%(vgrid_name)s %(vgrid_label)s.
You can assign it to accept jobs from the %(vgrid_name)s %(vgrid_label)s from
your Resources page on %(short_title)s.

Regards, the %(vgrid_name)s %(vgrid_label)s owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform owners' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
        })

    output_objects.append({
        'object_type': 'link',
        'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name,
        'text': 'Back to administration for %s' % vgrid_name
    })
    return (output_objects, returnvalues.OK)
Exemplo n.º 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)
    defaults = signature()[1]
    output_objects.append({
        'object_type': 'header',
        'text': 'Reject Resource Request'
    })
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1].strip()
    request_name = unhexlify(accepted['request_name'][-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)

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

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

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

    # IMPORTANT: path must be expanded to abs for proper chrooting
    abs_path = os.path.abspath(os.path.join(base_dir, request_name))
    if not valid_user_path(
            configuration, abs_path, base_dir, allow_equal=False):
        logger.warning('%s tried to access restricted path %s ! (%s)' % \
                       (client_id, abs_path, request_name))
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Illegal request name "%s":
you can only reject requests to your own resources.''' % request_name
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if request_name:
        request_dir = os.path.join(configuration.resource_home,
                                   unique_resource_name)
        req = load_access_request(configuration, request_dir, request_name)
    if not req or not delete_access_request(configuration, request_dir,
                                            request_name):
        logger.error("failed to delete owner request for %s in %s" % \
                     (unique_resource_name, request_name))
        output_objects.append({
            'object_type': 'error_text', 'text':
            'Failed to remove saved resource request for %s in %s!'\
            % (unique_resource_name, request_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)
    output_objects.append({
        'object_type':
        'text',
        'text':
        '''
Deleted %(request_type)s access request to %(target)s for %(entity)s .
''' % req
    })
    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'protocol': any_protocol,
        'unique_resource_name': unique_resource_name,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    fill_helpers.update(req)
    target_op = 'sendrequestaction'
    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':
        'html_form',
        'text':
        """
<p>
You can use the reply form below if you want to additionally send an
explanation for rejecting the request.
</p>
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type=hidden name=request_type value='resourcereject' />
<input type=hidden name=unique_resource_name value='%(target)s' />
<input type=hidden name=cert_id value='%(entity)s' />
<input type=hidden name=protocol value='%(protocol)s' />
<table>
<tr>
<td class='title'>Optional reject message to requestor(s)</td>
</tr><tr>
<td><textarea name=request_text cols=72 rows=10>
We have decided to reject your %(request_type)s request to our %(target)s
resource.

Regards, the %(target)s resource owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform requestor(s)' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
    })
    output_objects.append({
        'object_type':
        'link',
        'destination':
        'resadmin.py?unique_resource_name=%s' % unique_resource_name,
        'text':
        'Back to administration for %s' % unique_resource_name
    })
    return (output_objects, returnvalues.OK)
Exemplo n.º 5
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Add %s Owner" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Add %s Owner(s)' % label
    })
    status = returnvalues.OK
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    cert_id_list = accepted['cert_id']
    request_name = unhexlify(accepted['request_name'][-1])
    rank_list = accepted['rank'] + ['' for _ in cert_id_list]
    # inherited vgrid membership
    inherit_vgrid_member = False

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_map = get_full_user_map(configuration)
    user_dict = user_map.get(client_id, None)
    # Optional site-wide limitation of manage vgrid permission
    if not user_dict or \
            not vgrid_manage_allowed(configuration, user_dict):
        logger.warning("user %s is not allowed to manage vgrids!" % client_id)
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Only privileged users can manage %ss' % label
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # make sure vgrid settings allow this owner to edit owners

    (allow_status, allow_msg) = allow_owners_adm(configuration, vgrid_name,
                                                 client_id)
    if not allow_status:
        output_objects.append({'object_type': 'error_text', 'text': allow_msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    cert_id_added = []
    for (cert_id, rank_str) in zip(cert_id_list, rank_list):
        cert_id = cert_id.strip()
        cert_dir = client_id_dir(cert_id)
        try:
            rank = int(rank_str)
        except ValueError:
            rank = None

        # Allow openid alias as subject if openid with alias is enabled
        if configuration.user_openid_providers and configuration.user_openid_alias:
            cert_id = expand_openid_alias(cert_id, configuration)

        # Validity of user and vgrid names is checked in this init function so
        # no need to worry about illegal directory traversal through variables

        (ret_val, msg, _) = \
            init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                      'owner', configuration)
        if not ret_val:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already an owner unless rank is given

        if rank is None and vgrid_is_owner(vgrid_name, cert_id, configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is already an owner of %s or a parent %s.' %
                (cert_id, vgrid_name, label)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already a direct member

        if vgrid_is_member(vgrid_name, cert_id, configuration,
                           recursive=False):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is already a member of %s - please remove first.' %
                (cert_id, vgrid_name)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # owner of subvgrid?

        (list_status,
         subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration)
        if not list_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error getting list of sub%ss: %s' % (label, subvgrids)
            })
            status = returnvalues.SYSTEM_ERROR
            continue

        skip_entity = False
        for subvgrid in subvgrids:
            if vgrid_is_owner(subvgrid,
                              cert_id,
                              configuration,
                              recursive=False):
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    """%s is already an owner of a sub-%s ('%s'). Please
remove the person first and then try this operation again.""" %
                    (cert_id, label, subvgrid)
                })
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
            if vgrid_is_member(subvgrid,
                               cert_id,
                               configuration,
                               recursive=False):
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    """%s is already a member of a sub-%s ('%s'). Please
remove the person first and then try this operation again.""" %
                    (cert_id, label, subvgrid)
                })
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
        if skip_entity:
            continue

        # we DO allow ownership if member of parent vgrid - only handle with care

        if vgrid_is_member(vgrid_name, cert_id, configuration):
            # list is in top-down order
            parent_vgrids = vgrid_list_parents(vgrid_name, configuration)
            inherit_vgrid_member = vgrid_name
            for parent in parent_vgrids:
                if vgrid_is_member(parent,
                                   cert_id,
                                   configuration,
                                   recursive=False):
                    inherit_vgrid_member = parent
                    break
            output_objects.append({
                'object_type':
                'text',
                'text':
                '''NOTE: %s is already a member of parent %s %s.''' %
                (cert_id, label, inherit_vgrid_member)
            })

        # Check if only rank change was requested and apply if so

        if rank is not None:
            (add_status, add_msg) = vgrid_add_owners(configuration,
                                                     vgrid_name, [cert_id],
                                                     rank=rank)
            if not add_status:
                output_objects.append({
                    'object_type': 'error_text',
                    'text': add_msg
                })
                status = returnvalues.SYSTEM_ERROR
            else:
                output_objects.append({
                    'object_type':
                    'text',
                    'text':
                    'changed %s to owner %d' % (cert_id, rank)
                })
            # No further action after rank change as everything else exists
            continue

        # Getting here means cert_id is not owner of any parent or child vgrids.
        # may still be member of a parent grid but not a child vgrid.

        public_base_dir = \
            os.path.abspath(os.path.join(configuration.vgrid_public_base,
                                         vgrid_name)) + os.sep
        private_base_dir = \
            os.path.abspath(os.path.join(configuration.vgrid_private_base,
                                         vgrid_name)) + os.sep

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

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

        user_public_base = os.path.abspath(
            os.path.join(user_dir, 'public_base')) + os.sep
        user_private_base = os.path.abspath(
            os.path.join(user_dir, 'private_base')) + os.sep

        # make sure all dirs can be created (that a file or directory with the same
        # name do not exist prior to adding the owner)

        if os.path.exists(user_public_base + vgrid_name):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Could not add owner, a file or directory in public_base
    exists with the same name! %s''' % user_dir + vgrid_name
            })
            status = returnvalues.CLIENT_ERROR
            continue

        if os.path.exists(user_private_base + vgrid_name):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Could not add owner, a file or directory in private_base
exists with the same name!'''
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # vgrid share already exists if user is a member of parent vgrid

        if not inherit_vgrid_member and os.path.exists(user_dir + vgrid_name):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Could not add owner, a file or directory in the home
directory exists with the same name!'''
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # Add

        (add_status, add_msg) = vgrid_add_owners(configuration, vgrid_name,
                                                 [cert_id])
        if not add_status:
            output_objects.append({
                'object_type': 'error_text',
                'text': add_msg
            })
            status = returnvalues.SYSTEM_ERROR
            continue

        vgrid_name_parts = vgrid_name.split('/')
        is_subvgrid = len(vgrid_name_parts) > 1

        # create public_base in cert_ids home dir if it does not exists

        try:
            os.mkdir(user_public_base)
        except Exception as exc:
            pass

        # create private_base in cert_ids home dir if it does not exists

        try:
            os.mkdir(user_private_base)
        except Exception as exc:
            pass

        if is_subvgrid:
            share_dir = None
            try:

                # Example:
                #    vgrid_name = IMADA/STUD/BACH
                #    vgrid_name_last_fragment = BACH
                #    vgrid_name_without_last_fragment = IMADA/STUD/

                vgrid_name_last_fragment = \
                    vgrid_name_parts[len(vgrid_name_parts) - 1].strip()

                vgrid_name_without_last_fragment = \
                    ('/'.join(vgrid_name_parts[0:len(vgrid_name_parts) - 1]) +
                     os.sep).strip()

                # create dirs if they do not exist

                share_dir = user_dir + vgrid_name_without_last_fragment
                if not os.path.isdir(share_dir):
                    os.makedirs(share_dir)
                pub_dir = user_public_base + vgrid_name_without_last_fragment
                if not os.path.isdir(pub_dir):
                    os.makedirs(pub_dir)
                priv_dir = user_private_base + vgrid_name_without_last_fragment
                if not os.path.isdir(priv_dir):
                    os.makedirs(priv_dir)
            except Exception as exc:

                # out of range? should not be possible due to is_subvgrid check

                output_objects.append({
                    'object_type':
                    'error_text',
                    'text': ('Could not create needed dirs on %s server! %s' %
                             (configuration.short_title, exc))
                })
                logger.error('%s when looking for dir %s.' % (exc, share_dir))
                status = returnvalues.SYSTEM_ERROR
                continue

        # create symlink from users home directory to vgrid file directory
        # unless member of parent vgrid so that it is included already

        link_src = os.path.abspath(configuration.vgrid_files_home + os.sep +
                                   vgrid_name) + os.sep
        link_dst = user_dir + vgrid_name

        if not inherit_vgrid_member and \
                not make_symlink(link_src, link_dst, logger):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not create link to %s share!' % label
            })
            logger.error('Could not create link to %s files (%s -> %s)' %
                         (label, link_src, link_dst))
            status = returnvalues.SYSTEM_ERROR
            continue

        public_base_dst = user_public_base + vgrid_name

        # create symlink for public_base files

        if not make_symlink(public_base_dir, public_base_dst, logger):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not create link to public_base dir!'
            })
            logger.error(
                'Could not create link to public_base dir (%s -> %s)' %
                (public_base_dir, public_base_dst))
            status = returnvalues.SYSTEM_ERROR
            continue

        private_base_dst = user_private_base + vgrid_name

        # create symlink for private_base files

        if not make_symlink(private_base_dir, private_base_dst, logger):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not create link to private_base dir!'
            })
            status = returnvalues.SYSTEM_ERROR
            continue

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

    if request_name:
        request_dir = os.path.join(configuration.vgrid_home, vgrid_name)
        if not delete_access_request(configuration, request_dir, request_name):
            logger.error("failed to delete owner request for %s in %s" %
                         (vgrid_name, request_name))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to remove saved request for %s in %s!' %
                (vgrid_name, request_name)
            })

    if cert_id_added:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            'New owner(s)<br />%s<br />successfully added to %s %s!'
            '' % ('<br />'.join(cert_id_added), vgrid_name, label)
        })
        cert_id_fields = ''
        for cert_id in cert_id_added:
            cert_id_fields += """<input type=hidden name=cert_id value='%s' />
""" % cert_id

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers = {
            'vgrid_name': vgrid_name,
            'cert_id': cert_id,
            'protocol': any_protocol,
            'short_title': configuration.short_title,
            'vgrid_label': label,
            'cert_id_fields': cert_id_fields,
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit
        }
        target_op = 'sendrequestaction'
        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':
            'html_form',
            'text':
            """
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type=hidden name=request_type value='vgridaccept' />
<input type=hidden name=vgrid_name value='%(vgrid_name)s' />
%(cert_id_fields)s
<input type=hidden name=protocol value='%(protocol)s' />
<table>
<tr>
<td class='title'>Custom message to user(s)</td>
</tr><tr>
<td><textarea name=request_text cols=72 rows=10>
We have granted you ownership access to our %(vgrid_name)s %(vgrid_label)s.
You can access the %(vgrid_label)s administration page from the
%(vgrid_label)ss page on %(short_title)s.

Regards, the %(vgrid_name)s %(vgrid_label)s owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform user(s)' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
        })

    output_objects.append({
        'object_type': 'link',
        'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name,
        'text': 'Back to administration for %s' % vgrid_name
    })
    return (output_objects, status)