def get_valid_vgrid_owner_id(configuration, vgrid_name): """Returns the first valid owner_id for *vgrid_name* """ result = None # Look for owner in current (sub)vgrid (owners_status, owners_id) = vgrid_owners(vgrid_name, configuration, recursive=False) if owners_status: # Only allow valid users for owner_id in owners_id: if is_user(owner_id, configuration.mig_server_home): result = owner_id if result is None: # If no valid vgrid owners found look recursively towards top-vgrid (owners_status, owners_id) = vgrid_owners(vgrid_name, configuration, recursive=True) if owners_status: for owner_id in owners_id: if is_user(owner_id, configuration.mig_server_home): result = owner_id return result
def get_allowed_path(configuration, client_id, path): """Check certificate data and path for either a valid user/server or a resource using a valid session id. If the check succeeds, the real path to the file is returned. """ client_dir = client_id_dir(client_id) # Check cert and decide if it is a user, resource or server if not client_id: path_slash_stripped = path.lstrip("/") sessionid = path_slash_stripped[: path_slash_stripped.find("/")] # check that the sessionid is ok (does symlink exist?) if not os.path.islink(configuration.webserver_home + sessionid): raise Exception("Invalid session id!") target_dir = configuration.webserver_home + path_slash_stripped[: path_slash_stripped.rfind("/")] target_file = path_slash_stripped[path_slash_stripped.rfind("/") + 1 :] elif is_user(client_id, configuration.mig_server_home): real_path = os.path.normpath(os.path.join(configuration.user_home, client_dir, path)) target_dir = os.path.dirname(real_path) target_file = os.path.basename(real_path) elif is_server(client_id, configuration.server_home): real_path = os.path.normpath(os.path.join(configuration.server_home, client_dir, path)) target_dir = os.path.dirname(real_path) target_file = os.path.basename(real_path) else: raise Exception("Invalid credentials %s: no such user or server" % client_id) target_path = target_dir + "/" + target_file return target_path
def get_allowed_path(configuration, client_id, path): """Check certificate data and path for either a valid user/server or a resource using a valid session id. If the check succeeds, the real path to the file is returned. """ client_dir = client_id_dir(client_id) # Check cert and decide if it is a user, resource or server if not client_id: path_slash_stripped = path.lstrip('/') sessionid = path_slash_stripped[:path_slash_stripped.find('/')] # check that the sessionid is ok (does symlink exist?) if not os.path.islink(configuration.webserver_home + sessionid): raise Exception('Invalid session id!') target_dir = configuration.webserver_home\ + path_slash_stripped[:path_slash_stripped.rfind('/')] target_file = path_slash_stripped[path_slash_stripped.rfind('/') + 1:] elif is_user(client_id, configuration.mig_server_home): real_path = \ os.path.normpath(os.path.join(configuration.user_home, client_dir, path)) target_dir = os.path.dirname(real_path) target_file = os.path.basename(real_path) elif is_server(client_id, configuration.server_home): real_path = \ os.path.normpath(os.path.join(configuration.server_home, client_dir, path)) target_dir = os.path.dirname(real_path) target_file = os.path.basename(real_path) else: raise Exception('Invalid credentials %s: no such user or server' % client_id) target_path = target_dir + '/' + target_file return target_path
def validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects, require_user=True, filter_values=None, environ=None, ): """A wrapper used by most back end functionality - redirects to sign up if client_id is missing. """ logger = configuration.logger if environ is None: environ = os.environ creds_error = '' if not client_id: creds_error = "Invalid or missing user credentials" elif require_user and not is_user(client_id, configuration.mig_server_home): creds_error = "No such user (%s)" % client_id if creds_error and not requested_page().endswith('logout.py'): output_objects.append({'object_type': 'error_text', 'text' : creds_error }) # Redirect to sign-up cert page trying to guess relevant choices signup_url = os.path.join(configuration.migserver_https_sid_url, 'cgi-sid', 'signup.py') signup_query = '' if not client_id: output_objects.append( {'object_type': 'text', 'text': '''Apparently you do not already have access to %s, but you can sign up:''' % configuration.short_title }) output_objects.append({'object_type': 'link', 'text': signup_url, 'destination': signup_url + signup_query}) output_objects.append( {'object_type': 'text', 'text': '''If you already signed up and received a user certificate you probably just need to import it in your browser.'''}) else: output_objects.append( {'object_type': 'text', 'text': '''Apparently you already have suitable credentials and just need to sign up for a local %s account on:''' % \ configuration.short_title}) if extract_client_cert(configuration, environ) is None: # Force logout/expire session cookie here to support signup identity = extract_client_openid(configuration, environ, lookup_dn=False) if identity: logger.info("expire openid user %s" % identity) (success, _) = expire_oid_sessions(configuration, identity) else: logger.info("no openid user logged in") output_objects.append({'object_type': 'link', 'text': signup_url, 'destination': signup_url + signup_query}) return (False, output_objects) (status, retval) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects, filter_values) return (status, retval)
def validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects, require_user=True, filter_values=None, environ=None, ): """A wrapper used by most back end functionality - redirects to sign up if client_id is missing. """ logger = configuration.logger if environ is None: environ = os.environ creds_error = '' if not client_id: creds_error = "Invalid or missing user credentials" elif require_user and not is_user(client_id, configuration.mig_server_home): creds_error = "No such user (%s)" % client_id if creds_error and not requested_page().endswith('logout.py'): output_objects.append({ 'object_type': 'error_text', 'text': creds_error }) if configuration.site_enable_gdp: main_url = configuration.migserver_http_url output_objects.append({ 'object_type': 'text', 'text': '''Apparently you do not have access to this page, please return to:''' }) output_objects.append({ 'object_type': 'link', 'text': main_url, 'destination': main_url }) else: # Redirect to sign-up cert page trying to guess relevant choices signup_url = os.path.join(configuration.migserver_https_sid_url, 'cgi-sid', 'signup.py') signup_query = '' if not client_id: output_objects.append({ 'object_type': 'text', 'text': '''Apparently you do not already have access to %s, but you can sign up:''' % configuration.short_title }) output_objects.append({'object_type': 'link', 'text': '%s sign up page' % \ configuration.short_title, 'destination': signup_url + signup_query}) output_objects.append({ 'object_type': 'text', 'text': '''If you already signed up and received a user certificate you probably just need to import it in your browser.''' }) else: output_objects.append({ 'object_type': 'text', 'text': '''Apparently you already have suitable credentials and just need to sign up for a local %s account on the''' % configuration.short_title }) base_url = extract_base_url(configuration, environ) if base_url == configuration.migserver_https_ext_cert_url and \ 'extcert' in configuration.site_login_methods: signup_query = '?show=extcert' elif base_url in (configuration.migserver_https_ext_oid_url, configuration.migserver_https_mig_oid_url): # Force logout/expire session cookie here to support signup (oid_db, identity) = extract_client_openid(configuration, environ, lookup_dn=False) if oid_db and identity: logger.info("openid expire user %s in %s" % (identity, oid_db)) (success, _) = expire_oid_sessions(configuration, oid_db, identity) if oid_db == auth_openid_ext_db and \ 'extoid' in configuration.site_signup_methods: signup_query = '?show=extoid' else: logger.error("unknown migoid client_id %s on %s" \ % (client_id, base_url)) else: logger.warning("unexpected client_id %s on %s" % \ (client_id, base_url)) output_objects.append({'object_type': 'link', 'text': '%s sign up page' % \ configuration.short_title, 'destination': signup_url + signup_query}) return (False, output_objects) (status, retval) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects, filter_values) return (status, retval)
def init_vgrid_script_add_rem( vgrid_name, client_id, subject, subject_type, configuration, ): """Initialize vgrid specific add and remove scripts""" msg = '' if not vgrid_name: msg += 'Please specify vgrid_name in the querystring' return (False, msg, None) if not subject: msg += 'Please provide the name of the %s' % subject_type return (False, msg, None) if not valid_dir_input(configuration.vgrid_home, vgrid_name): msg += 'Illegal vgrid_name: %s' % vgrid_name return (False, msg, None) if subject_type == 'member' or subject_type == 'owner': if not is_user(subject, configuration.mig_server_home): msg += '%s is not a valid %s user!' % \ (subject, configuration.short_title) return (False, msg, None) elif subject_type == 'resource': if not is_resource(subject, configuration.resource_home): msg += '%s is not a valid %s resource' % \ (subject, configuration.short_title) msg += \ ' (OK, if removing or e.g. the resource creation is pending)' elif subject_type == 'trigger': # Rules are checked later pass else: msg += 'unknown subject type in init_vgrid_script_add_rem' return (False, msg, []) # special case: members may terminate own membership if (subject_type == 'member') and (client_id == subject) \ and (vgrid_is_member(vgrid_name, subject, configuration)): return (True, msg, []) # special case: members may remove own triggers and add new ones if (subject_type == 'trigger') and \ (not vgrid_is_trigger(vgrid_name, subject, configuration) or \ vgrid_is_trigger_owner(vgrid_name, subject, client_id, configuration)): return (True, msg, []) # otherwise: only owners may add or remove: if not vgrid_is_owner(vgrid_name, client_id, configuration): msg += 'You must be an owner of the %s vgrid to add/remove %s'\ % (vgrid_name, subject_type) return (False, msg, None) return (True, msg, [])
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] output_objects.append({'object_type': 'header', 'text' : 'Remove Resource Owner'}) (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] cert_id = accepted['cert_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) 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 remove another 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 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) }) return (output_objects, returnvalues.CLIENT_ERROR) # reject remove if cert_id is not an owner if not resource_is_owner(unique_resource_name, cert_id, configuration): output_objects.append({'object_type': 'error_text', 'text' : '%s is not an owner of %s.' % (cert_id, unique_resource_name)}) return (output_objects, returnvalues.CLIENT_ERROR) # Remove owner (rm_status, rm_msg) = resource_remove_owners(configuration, unique_resource_name, [cert_id]) if not rm_status: output_objects.append({'object_type': 'error_text', 'text' : 'Could not remove owner, reason: %s' % rm_msg}) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({'object_type': 'text', 'text' : '%s was successfully removed and is no longer an owner of %s!' % (cert_id, unique_resource_name)}) 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, returnvalues.OK)
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)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] output_objects.append({'object_type': 'header', 'text' : 'Remove Resource Owner'}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) unique_resource_name = accepted['unique_resource_name'][-1] cert_id = accepted['cert_id'][-1] if not is_owner(client_id, unique_resource_name, configuration.resource_home, logger): output_objects.append({'object_type': 'error_text', 'text' : 'You must be an owner of %s to remove another 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 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) }) return (output_objects, returnvalues.CLIENT_ERROR) # reject remove if cert_id is not an owner if not resource_is_owner(unique_resource_name, cert_id, configuration): output_objects.append({'object_type': 'error_text', 'text' : '%s is not an owner of %s.' % (cert_id, unique_resource_name)}) return (output_objects, returnvalues.CLIENT_ERROR) base_dir = os.path.abspath(os.path.join(configuration.resource_home, unique_resource_name)) + os.sep # Remove owner owners_file = os.path.join(base_dir, 'owners') (rm_status, rm_msg) = resource_remove_owners(configuration, unique_resource_name, [cert_id]) if not rm_status: output_objects.append({'object_type': 'error_text', 'text' : 'Could not remove owner, reason: %s' % rm_msg}) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({'object_type': 'text', 'text' : '%s was successfully removed and is no longer an owner of %s!' % (cert_id, unique_resource_name)}) output_objects.append({'object_type': 'link', 'destination': 'resadmin.py?unique_resource_name=%s' % \ unique_resource_name, 'class': 'adminlink', 'title': 'Administrate resource', 'text': 'Manage resource'}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] output_objects.append({'object_type': 'header', 'text' : 'Add Resource Owner'}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) unique_resource_name = accepted['unique_resource_name'][-1].strip() cert_id = accepted['cert_id'][-1].strip() 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 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)}) return (output_objects, returnvalues.CLIENT_ERROR) # 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)}) 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 # 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}) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({'object_type': 'text', 'text' : 'New owner %s successfully added to %s!' % (cert_id, unique_resource_name)}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method='post' action='sendrequestaction.py'> <input type=hidden name=request_type value='resourceaccept' /> <input type=hidden name=unique_resource_name value='%s' /> <input type=hidden name=cert_id value='%s' /> <input type=hidden name=protocol value='%s' /> <table> <tr> <td class='title'>Custom message to user</td> </tr> <tr> <td><textarea name=request_text cols=72 rows=10> We have granted you ownership access to our %s resource. You can access the resource administration page from the Resources page. Regards, the %s resource owners </textarea></td> </tr> <tr> <td><input type='submit' value='Inform user' /></td> </tr> </table> </form> <br /> """ % (unique_resource_name, cert_id, any_protocol, unique_resource_name, unique_resource_name)}) output_objects.append({'object_type': 'link', 'destination': 'resadmin.py?unique_resource_name=%s' % \ unique_resource_name, 'class': 'adminlink', 'title': 'Administrate resource', 'text': 'Manage resource'}) return (output_objects, returnvalues.OK)