def magpie_update_services_conflict(conflict_services, services_dict, request_cookies): # type: (List[Str], ConfigDict, Dict[Str, Str]) -> Dict[Str, int] """ Resolve conflicting services by name during registration by updating them only if pointing to different URL. """ magpie_url = get_magpie_url() statuses = dict() for svc_name in conflict_services: statuses[svc_name] = 409 svc_url_new = services_dict[svc_name]["url"] svc_url_db = "{magpie}/services/{svc}".format(magpie=magpie_url, svc=svc_name) svc_resp = requests.get(svc_url_db, cookies=request_cookies) svc_info = get_json(svc_resp).get(svc_name) svc_url_old = svc_info["service_url"] if svc_url_old != svc_url_new: svc_info["service_url"] = svc_url_new res_svc_put = requests.put(svc_url_db, data=svc_info, cookies=request_cookies) statuses[svc_name] = res_svc_put.status_code print_log( "[{url_old}] => [{url_new}] Service URL update ({svc}): {resp}" .format(svc=svc_name, url_old=svc_url_old, url_new=svc_url_new, resp=res_svc_put.status_code), logger=LOGGER) return statuses
def goto_service(self, resource_id): path = schemas.ResourceAPI.path.format(resource_id=resource_id) resp = request_api(self.request, path, "GET") check_response(resp) body = get_json(resp) svc_name = body["resource"]["resource_name"] # get service type instead of 'cur_svc_type' in case of 'default' ('cur_svc_type' not set yet) path = schemas.ServiceAPI.path.format(service_name=svc_name) resp = request_api(self.request, path, "GET") check_response(resp) body = get_json(resp) svc_type = body["service"]["service_type"] return HTTPFound( self.request.route_url("edit_service", service_name=svc_name, cur_svc_type=svc_type))
def edit_user_or_group_resource_permissions(self, user_or_group_name, resource_id, is_user=False): if is_user: res_perms_path = schemas.UserResourcePermissionsAPI.path \ .format(user_name=user_or_group_name, resource_id=resource_id) else: res_perms_path = schemas.GroupResourcePermissionsAPI.path \ .format(group_name=user_or_group_name, resource_id=resource_id) try: resp = request_api(self.request, res_perms_path, "GET") res_perms = get_json(resp)["permission_names"] except Exception as e: raise HTTPBadRequest(detail=repr(e)) selected_perms = self.request.POST.getall("permission") removed_perms = list(set(res_perms) - set(selected_perms)) new_perms = list(set(selected_perms) - set(res_perms)) for perm in removed_perms: path = "{path}/{perm}".format(path=res_perms_path, perm=perm) resp = request_api(self.request, path, "DELETE") check_response(resp) for perm in new_perms: data = {u"permission_name": perm} resp = request_api(self.request, res_perms_path, "POST", data=data) check_response(resp) return removed_perms, new_perms
def get_services(self, cur_svc_type): resp = request_api(self.request, schemas.ServicesAPI.path, "GET") check_response(resp) all_services = get_json(resp)["services"] svc_types = sorted(all_services.keys()) if cur_svc_type not in svc_types: cur_svc_type = svc_types[0] services = all_services[cur_svc_type] return svc_types, cur_svc_type, services
def get_all_groups(self, first_default_group=None): resp = request_api(self.request, schemas.GroupsAPI.path, "GET") check_response(resp) groups = list(get_json(resp)["group_names"]) if isinstance(first_default_group, six.string_types) and first_default_group in groups: groups.remove(first_default_group) groups.insert(0, first_default_group) return groups
def get_user_emails(self): user_names = self.get_user_names() emails = list() for user in user_names: path = schemas.UserAPI.path.format(user_name=user) resp = request_api(self.request, path, "GET") check_response(resp) user_email = get_json(resp)["user"]["email"] emails.append(user_email) return emails
def get_resource_types(self): """ :return: dictionary of all resources as {id: 'resource_type'} :rtype: dict """ resp = request_api(self.request, schemas.ResourcesAPI.path, "GET") check_response(resp) res_dic = self.default_get(get_json(resp), "resources", dict()) res_ids = dict() self.flatten_tree_resource(res_dic, res_ids) return res_ids
def get_service_resources(self, service_name): resources = {} path = schemas.ServiceResourcesAPI.path.format( service_name=service_name) resp = request_api(self.request, path, "GET") check_response(resp) raw_resources = get_json(resp)[service_name] resources[service_name] = dict(id=raw_resources["resource_id"], permission_names=[], children=self.resource_tree_parser( raw_resources["resources"], {})) resources_id_type = self.get_resource_types() return resources, resources_id_type
def add_remote_resource(self, service_type, services_names, user_or_group, remote_id, is_user=False): try: res_perm_names, res_perms = self.get_user_or_group_resources_permissions_dict( user_or_group, services=services_names, service_type=service_type, is_user=is_user) except Exception as e: raise HTTPBadRequest(detail=repr(e)) # get the parent resources for this remote_id # TODO: # Until the api is modified to make it possible to request from the RemoteResource table, # we have to access the database directly here session = self.request.db parents = remote_resource_tree_service.path_upper(remote_id, db_session=session) parents = list(reversed(list(parents))) parent_id = None current_resources = res_perms for remote_resource in parents: name = remote_resource.resource_name if name in current_resources: parent_id = current_resources[name]["id"] current_resources = current_resources[name]["children"] else: data = { "resource_name": name, "resource_display_name": remote_resource.resource_display_name, "resource_type": remote_resource.resource_type, "parent_id": parent_id, } resp = request_api(self.request, schemas.ResourcesAPI.path, "POST", data=data) check_response(resp) parent_id = get_json(resp)["resource"]["resource_id"] return parent_id
def add_resource(self): cur_svc_type = self.request.matchdict["cur_svc_type"] service_name = self.request.matchdict["service_name"] resource_id = self.request.matchdict["resource_id"] if "add_child" in self.request.POST: resource_name = self.request.POST.get("resource_name") resource_type = self.request.POST.get("resource_type") data = { u"resource_name": resource_name, u"resource_type": resource_type, u"parent_id": int(resource_id) if resource_id else None } resp = request_api(self.request, schemas.ResourcesAPI.path, "POST", data=data, headers={"Content-Type": CONTENT_TYPE_JSON}) check_response(resp) return HTTPFound( self.request.route_url("edit_service", service_name=service_name, cur_svc_type=cur_svc_type)) path = schemas.ServiceTypeResourceTypesAPI.path.format( service_type=cur_svc_type) resp = request_api(self.request, path, "GET") check_response(resp) svc_res_types = get_json(resp)["resource_types"] data = { u"service_name": service_name, u"cur_svc_type": cur_svc_type, u"resource_id": resource_id, u"cur_svc_res": svc_res_types, } return add_template_data(self.request, data)
def error_view(self): """ Generates the wrapped API error view for cleaner error page returned by the UI. Renders a controlled UI error page with viewable details of the error generated by an API sub-request or some generic processing operation. The API HTTP error status code is forwarded to this UI response. """ def get_any_detail(): req_data = data.get("error_request", {}) return data.get("detail", data.get("explanation", req_data.get("detail", http.explanation))) data = {} if self.request.method == "POST": data = get_json(self.request) data = self.add_template_data(data) data.setdefault("error_code", 500) http = status_map[data["error_code"]] data.setdefault("error_title", data.get("title", http.title)) data.setdefault("error_detail", get_any_detail()) data.setdefault("error_image", "forbidden" if data["error_code"] in [401, 403] else "exclamation-circle") resp = render_to_response("templates/error.mako", data, request=self.request) resp.status_int = data["error_code"] return resp
def edit_service(self): cur_svc_type = self.request.matchdict["cur_svc_type"] service_name = self.request.matchdict["service_name"] service_data = self.get_service_data(service_name) service_url = service_data["service_url"] service_perm = service_data["permission_names"] service_id = service_data["resource_id"] # apply default state if arriving on the page for the first time # future editions on the page will transfer the last saved state service_push_show = cur_svc_type in register.SERVICES_PHOENIX_ALLOWED service_push = asbool( self.request.POST.get("service_push", service_push_show)) service_info = { u"edit_mode": u"no_edit", u"service_name": service_name, u"service_url": service_url, u"public_url": register.get_twitcher_protected_service_url(service_name), u"service_perm": service_perm, u"service_id": service_id, u"service_push": service_push, u"service_push_show": service_push_show, u"cur_svc_type": cur_svc_type } if "edit_name" in self.request.POST: service_info["edit_mode"] = u"edit_name" if "save_name" in self.request.POST: new_svc_name = self.request.POST.get("new_svc_name") if service_name != new_svc_name and new_svc_name != "": self.update_service_name(service_name, new_svc_name, service_push) service_info["service_name"] = new_svc_name service_info[ "public_url"] = register.get_twitcher_protected_service_url( new_svc_name), service_info["edit_mode"] = u"no_edit" # return directly to "regenerate" the URL with the modified name return HTTPFound( self.request.route_url("edit_service", **service_info)) if "edit_url" in self.request.POST: service_info["edit_mode"] = u"edit_url" if "save_url" in self.request.POST: new_svc_url = self.request.POST.get("new_svc_url") if service_url != new_svc_url and new_svc_url != "": self.update_service_url(service_name, new_svc_url, service_push) service_info["service_url"] = new_svc_url service_info["edit_mode"] = u"no_edit" if "delete" in self.request.POST: service_data = json.dumps({u"service_push": service_push}) path = schemas.ServiceAPI.path.format(service_name=service_name) resp = request_api(self.request, path, "DELETE", data=service_data) check_response(resp) return HTTPFound( self.request.route_url("view_services", **service_info)) if "delete_child" in self.request.POST: resource_id = self.request.POST.get("resource_id") path = schemas.ResourceAPI.path.format(resource_id=resource_id) resp = request_api(self.request, path, "DELETE") check_response(resp) if "add_child" in self.request.POST: service_info["resource_id"] = self.request.POST.get("resource_id") return HTTPFound( self.request.route_url("add_resource", **service_info)) resources, resources_id_type = self.get_service_resources(service_name) path = schemas.ServiceAPI.path.format(service_name=service_name) resp = request_api(self.request, path, "GET") check_response(resp) svc_body = get_json(resp)["service"] # TODO: use an API request instead of direct access to `RESOURCE_TYPE_DICT` service_info["resources"] = resources service_info["resources_id_type"] = resources_id_type service_info["resources_no_child"] = [ res for res in RESOURCE_TYPE_DICT if not RESOURCE_TYPE_DICT[res].child_resource_allowed ] service_info[ "service_no_child"] = not svc_body["resource_child_allowed"] return add_template_data(self.request, service_info)
def get_discoverable_groups(self): # type: () -> List[str] resp = request_api(self.request, schemas.RegisterGroupsAPI.path, "GET") check_response(resp) return get_json(resp)["group_names"]
def get_user_names(self): resp = request_api(self.request, schemas.UsersAPI.path, "GET") check_response(resp) return get_json(resp)["user_names"]
def get_service_data(self, service_name): path = schemas.ServiceAPI.path.format(service_name=service_name) resp = request_api(self.request, path, "GET") check_response(resp) return get_json(resp)["service"]
def parse_resource_path( permission_config_entry, # type: ConfigItem entry_index, # type: int service_info, # type: ConfigItem cookies_or_session=None, # type: CookiesOrSessionType magpie_url=None, # type: Optional[Str] ): # type: (...) -> Tuple[Optional[int], bool] """ Parses the `resource` field of a permission config entry and retrieves the final resource id. Creates missing resources as necessary if they can be automatically resolved. If `cookies` are provided, uses requests to a running `Magpie` instance (with `magpie_url`) to apply permission. If `session` to db is provided, uses direct db connection instead to apply permission. :returns: tuple of found id (if any, `None` otherwise), and success status of the parsing operation (error) """ if not magpie_url and use_request(cookies_or_session): raise ValueError( "cannot use cookies without corresponding request URL") resource = None resource_path = permission_config_entry.get("resource", "") if resource_path.startswith("/"): resource_path = resource_path[1:] if resource_path.endswith("/"): resource_path = resource_path[:-1] if resource_path: try: svc_name = service_info["service_name"] svc_type = service_info["service_type"] if use_request(cookies_or_session): res_path = get_magpie_url() + ServiceResourcesAPI.path.format( service_name=svc_name) res_resp = requests.get(res_path, cookies=cookies_or_session) res_dict = get_json(res_resp)[svc_name]["resources"] else: from magpie.api.management.service.service_formats import format_service_resources svc = models.Service.by_service_name( svc_name, db_session=cookies_or_session) res_dict = format_service_resources( svc, show_all_children=True, db_session=cookies_or_session) parent = res_dict["resource_id"] child_resources = res_dict["resources"] for res in resource_path.split("/"): # search in existing children resources if len(child_resources): # noinspection PyTypeChecker res_id = list( filter( lambda r: res in [r, child_resources[r]["resource_name"]], child_resources)) if res_id: res_info = child_resources[ res_id[0]] # type: Dict[Str, JSON] child_resources = res_info[ "children"] # update next sub-resource iteration parent = res_info["resource_id"] continue # missing resource, attempt creation svc_res_types = SERVICE_TYPE_DICT[svc_type].resource_type_names type_count = len(svc_res_types) if type_count != 1: warn_permission( "Cannot automatically generate resources", entry_index, detail= "Service [{}] of type [{}] allows {} sub-resource types" .format(svc_name, svc_type, type_count)) raise Exception( "Missing resource to apply permission.") # fail fast res_type = svc_res_types[0] if use_request(cookies_or_session): body = { "resource_name": res, "resource_type": res_type, "parent_id": parent } # noinspection PyUnboundLocalVariable resp = requests.post(res_path, json=body, cookies=cookies_or_session) else: from magpie.api.management.resource.resource_utils import create_resource resp = create_resource(res, res, res_type, parent, db_session=cookies_or_session) if resp.status_code != 201: resp.raise_for_status() child_resources = {} parent = get_json(resp)["resource"]["resource_id"] resource = parent if not resource: raise Exception( "Could not extract child resource from resource path.") except Exception as ex: if isinstance(ex, HTTPException): detail = "{} ({}), {}".format( type(ex).__name__, ex.status_code, str(ex)) else: detail = repr(ex) warn_permission("Failed resources parsing.", entry_index, detail=detail) return None, False return resource, True
def get_user_or_group_resources_permissions_dict( self, user_or_group_name, services, service_type, is_user=False, is_inherit_groups_permissions=False): if is_user: query = "?inherit=true" if is_inherit_groups_permissions else "" path = schemas.UserResourcesAPI.path.format( user_name=user_or_group_name) + query else: path = schemas.GroupResourcesAPI.path.format( group_name=user_or_group_name) resp_group_perms = request_api(self.request, path, "GET") check_response(resp_group_perms) resp_group_perms_json = get_json(resp_group_perms) path = schemas.ServiceTypeAPI.path.format(service_type=service_type) resp = request_api(self.request, path, "GET") check_response(resp) resp_available_svc_types = get_json(resp)["services"][service_type] # remove possible duplicate permissions from different services resources_permission_names = set() for svc in resp_available_svc_types: resources_permission_names.update( set(resp_available_svc_types[svc]["permission_names"])) # inverse sort so that displayed permissions are sorted, since added from right to left in tree view resources_permission_names = sorted(resources_permission_names, reverse=True) resources = OrderedDict() for service in sorted(services): if not service: continue permission = OrderedDict() try: raw_perms = resp_group_perms_json["resources"][service_type][ service] permission[ raw_perms["resource_id"]] = raw_perms["permission_names"] permission.update(self.perm_tree_parser( raw_perms["resources"])) except KeyError: pass path = schemas.ServiceResourcesAPI.path.format( service_name=service) resp = request_api(self.request, path, "GET") check_response(resp) raw_resources = get_json(resp)[service] resources[service] = OrderedDict( id=raw_resources["resource_id"], permission_names=self.default_get(permission, raw_resources["resource_id"], []), children=self.resource_tree_parser(raw_resources["resources"], permission)) return resources_permission_names, resources
def get_user_groups(self, user_name): path = schemas.UserGroupsAPI.path.format(user_name=user_name) resp = request_api(self.request, path, "GET") check_response(resp) return get_json(resp)["group_names"]
def format_response(response): response_json = get_json(response) return str(response_json.get("code")) + " : " + str( response_json.get("detail"))
def get_service_types(self): svc_types_resp = request_api(self.request, schemas.ServiceTypesAPI.path, "GET") return get_json(svc_types_resp)["service_types"]
def get_current_user_groups(self): # type: () -> List[str] resp = request_api(self.request, schemas.LoggedUserGroupsAPI.path, "GET") check_response(resp) return get_json(resp)["group_names"]
def request_providers_json(self): resp = request_api(self.request, schemas.ProvidersAPI.path, "GET") check_response(resp) return get_json(resp)["providers"]
def edit_user(self): user_name = self.request.matchdict["user_name"] cur_svc_type = self.request.matchdict["cur_svc_type"] inherit_grp_perms = self.request.matchdict.get( "inherit_groups_permissions", False) own_groups = self.get_user_groups(user_name) all_groups = self.get_all_groups( first_default_group=get_constant("MAGPIE_USERS_GROUP")) # TODO: # Until the api is modified to make it possible to request from the RemoteResource table, # we have to access the database directly here session = self.request.db try: # The service type is "default". This function replaces cur_svc_type with the first service type. svc_types, cur_svc_type, services = self.get_services(cur_svc_type) except Exception as e: raise HTTPBadRequest(detail=repr(e)) user_path = schemas.UserAPI.path.format(user_name=user_name) user_resp = request_api(self.request, user_path, "GET") check_response(user_resp) user_info = get_json(user_resp)["user"] user_info[u"edit_mode"] = u"no_edit" user_info[u"own_groups"] = own_groups user_info[u"groups"] = all_groups user_info[u"inherit_groups_permissions"] = inherit_grp_perms error_message = "" # In case of update, changes are not reflected when calling # get_user_or_group_resources_permissions_dict so we must take care # of them res_id = None removed_perms = None new_perms = None if self.request.method == "POST": res_id = self.request.POST.get(u"resource_id") is_edit_group_membership = False is_save_user_info = False requires_update_name = False if u"inherit_groups_permissions" in self.request.POST: inherit_grp_perms = asbool( self.request.POST[u"inherit_groups_permissions"]) user_info[u"inherit_groups_permissions"] = inherit_grp_perms if u"delete" in self.request.POST: resp = request_api(self.request, user_path, "DELETE") check_response(resp) return HTTPFound(self.request.route_url("view_users")) elif u"goto_service" in self.request.POST: return self.goto_service(res_id) elif u"clean_resource" in self.request.POST: # "clean_resource" must be above "edit_permissions" because they"re in the same form. self.delete_resource(res_id) elif u"edit_permissions" in self.request.POST: if not res_id or res_id == "None": remote_id = int(self.request.POST.get("remote_id")) services_names = [ s["service_name"] for s in services.values() ] res_id = self.add_remote_resource(cur_svc_type, services_names, user_name, remote_id, is_user=True) removed_perms, new_perms = \ self.edit_user_or_group_resource_permissions(user_name, res_id, is_user=True) elif u"edit_group_membership" in self.request.POST: is_edit_group_membership = True elif u"edit_username" in self.request.POST: user_info[u"edit_mode"] = u"edit_username" elif u"edit_password" in self.request.POST: user_info[u"edit_mode"] = u"edit_password" elif u"edit_email" in self.request.POST: user_info[u"edit_mode"] = u"edit_email" elif u"save_username" in self.request.POST: user_info[u"user_name"] = self.request.POST.get( u"new_user_name") is_save_user_info = True requires_update_name = True elif u"save_password" in self.request.POST: user_info[u"password"] = self.request.POST.get( u"new_user_password") is_save_user_info = True elif u"save_email" in self.request.POST: user_info[u"email"] = self.request.POST.get(u"new_user_email") is_save_user_info = True elif u"force_sync" in self.request.POST: errors = [] for service_info in services.values(): # noinspection PyBroadException try: sync_resources.fetch_single_service( service_info["resource_id"], session) except Exception: errors.append(service_info["service_name"]) if errors: error_message += self.make_sync_error_message(errors) elif u"clean_all" in self.request.POST: ids_to_clean = self.request.POST.get("ids_to_clean").split(";") for id_ in ids_to_clean: self.delete_resource(id_) if is_save_user_info: resp = request_api(self.request, user_path, "PUT", data=user_info) check_response(resp) # need to commit updates since we are using the same session # otherwise, updated user doesn't exist yet in the db for next calls self.request.tm.commit() # always remove password from output user_info.pop(u"password", None) if requires_update_name: # re-fetch user groups as current user-group will have changed on new user_name user_name = user_info[u"user_name"] user_info[u"own_groups"] = self.get_user_groups(user_name) # return immediately with updated URL to user with new name users_url = self.request.route_url("edit_user", user_name=user_name, cur_svc_type=cur_svc_type) return HTTPMovedPermanently(location=users_url) # edits to groups checkboxes if is_edit_group_membership: selected_groups = self.request.POST.getall("member") removed_groups = list(set(own_groups) - set(selected_groups)) new_groups = list(set(selected_groups) - set(own_groups)) for group in removed_groups: path = schemas.UserGroupAPI.path.format( user_name=user_name, group_name=group) resp = request_api(self.request, path, "DELETE") check_response(resp) for group in new_groups: path = schemas.UserGroupsAPI.path.format( user_name=user_name) data = {"group_name": group} resp = request_api(self.request, path, "POST", data=data) check_response(resp) user_info[u"own_groups"] = self.get_user_groups(user_name) # display resources permissions per service type tab try: res_perm_names, res_perms = self.get_user_or_group_resources_permissions_dict( user_name, services, cur_svc_type, is_user=True, is_inherit_groups_permissions=inherit_grp_perms) except Exception as e: raise HTTPBadRequest(detail=repr(e)) if res_id and (removed_perms or new_perms): self.update_user_or_group_resources_permissions_dict( res_perms, res_id, removed_perms, new_perms) sync_types = [s["service_sync_type"] for s in services.values()] sync_implemented = any(s in sync_resources.SYNC_SERVICES_TYPES for s in sync_types) info = self.get_remote_resources_info(res_perms, services, session) res_perms, ids_to_clean, last_sync_humanized, out_of_sync = info if out_of_sync: error_message = self.make_sync_error_message(out_of_sync) user_info[u"error_message"] = error_message user_info[u"ids_to_clean"] = ";".join(ids_to_clean) user_info[u"last_sync"] = last_sync_humanized user_info[u"sync_implemented"] = sync_implemented user_info[u"out_of_sync"] = out_of_sync user_info[u"cur_svc_type"] = cur_svc_type user_info[u"svc_types"] = svc_types user_info[u"resources"] = res_perms user_info[u"permissions"] = res_perm_names return add_template_data(self.request, data=user_info)
def magpie_register_permissions_from_config(permissions_config, magpie_url=None, db_session=None): # type: (Union[Str, ConfigDict], Optional[Str], Optional[Session]) -> None """ Applies permissions specified in configuration. :param permissions_config: file path to 'permissions' config or JSON/YAML equivalent pre-loaded. :param magpie_url: URL to magpie instance (when using requests; default: `magpie.url` from this app's config). :param db_session: db session to use instead of requests to directly create/remove permissions with config. .. seealso:: `magpie/permissions.cfg` for specific parameters and operational details. """ permissions = _load_config(permissions_config, "permissions") if not permissions: LOGGER.warning("Permissions configuration are empty.") return if use_request(db_session): magpie_url = magpie_url or get_magpie_url() settings = {'magpie.url': magpie_url} logging.debug( "Editing permissions using requests to [{}]...".format(magpie_url)) err_msg = "Invalid credentials to register Magpie permissions." cookies_or_session = get_admin_cookies(settings, raise_message=err_msg) else: logging.debug("Editing permissions using db session...") cookies_or_session = db_session logging.info("Found {} permissions to update.".format(len(permissions))) for i, perm_cfg in enumerate(permissions): # parameter validation if not isinstance(perm_cfg, dict) or not all( f in perm_cfg for f in ["permission", "service"]): warn_permission( "Invalid permission format for [{!s}]".format(perm_cfg), i) continue if perm_cfg["permission"] not in Permission.values(): warn_permission( "Unknown permission [{!s}]".format(perm_cfg['permission']), i) continue usr_name = perm_cfg.get("user") grp_name = perm_cfg.get("group") if not any([usr_name, grp_name]): warn_permission("Missing required user and/or group field.", i) continue if "action" not in perm_cfg: warn_permission("Unspecified action", i, trail="using default (create)...") perm_cfg["action"] = "create" if perm_cfg["action"] not in ["create", "remove"]: warn_permission("Unknown action [{!s}]".format(perm_cfg["action"]), i) continue # retrieve service for permissions validation svc_name = perm_cfg["service"] if use_request(cookies_or_session): svc_path = magpie_url + ServiceAPI.path.format( service_name=svc_name) svc_resp = requests.get(svc_path, cookies=cookies_or_session) if svc_resp.status_code != 200: warn_permission("Unknown service [{!s}]".format(svc_name), i) continue service_info = get_json(svc_resp)[svc_name] else: transaction.commit( ) # force any pending transaction to be applied to find possible dependencies svc = models.Service.by_service_name(svc_name, db_session=cookies_or_session) if not svc: warn_permission( "Unknown service [{!s}]. Can't edit permissions without service." .format(svc_name), i) continue from magpie.api.management.service.service_formats import format_service service_info = format_service(svc) # apply permission config resource_id, found = parse_resource_path(perm_cfg, i, service_info, cookies_or_session, magpie_url) if found: if not resource_id: resource_id = service_info["resource_id"] apply_permission_entry(perm_cfg, i, resource_id, cookies_or_session, magpie_url) if not use_request(cookies_or_session): transaction.commit() logging.info("Done processing permissions.")
def get_current_user_info(self): # type: () -> JSON user_resp = request_api(self.request, schemas.LoggedUserAPI.path, "GET") check_response(user_resp) return get_json(user_resp)["user"]
def get_group_users(self, group_name): path = schemas.GroupUsersAPI.path.format(group_name=group_name) resp = request_api(self.request, path, "GET") check_response(resp) return get_json(resp)["user_names"]
def edit_current_user(self): joined_groups = self.get_current_user_groups() public_groups = self.get_discoverable_groups() user_info = self.get_current_user_info() user_info["edit_mode"] = "no_edit" user_info["joined_groups"] = joined_groups user_info["groups"] = public_groups # reset error messages/flags user_info["error_message"] = "" for field in ["password", "user_email", "user_name"]: user_info["invalid_" + field] = "" user_info["reason_" + field] = "" if self.request.method == "POST": is_edit_group_membership = False is_save_user_info = False if "edit_group_membership" in self.request.POST: is_edit_group_membership = True elif "edit_password" in self.request.POST: user_info["edit_mode"] = "edit_password" elif "edit_email" in self.request.POST: user_info["edit_mode"] = "edit_email" elif "save_password" in self.request.POST: user_info["password"] = self.request.POST.get( "new_user_password") is_save_user_info = True elif "save_email" in self.request.POST: user_info["email"] = self.request.POST.get("new_user_email") is_save_user_info = True elif "delete" in self.request.POST: delete_response = request_api( self.request, schemas.UserAPI.path.format( user_name=user_info["user_name"]), "DELETE") check_response(delete_response) logout_response = request_api(self.request, schemas.SignoutAPI.path, "GET") check_response(logout_response) return HTTPFound(location="/") if is_save_user_info: resp = request_api(self.request, schemas.LoggedUserAPI.path, "PATCH", data=user_info) if resp.status_code in (HTTPBadRequest.code, HTTPUnprocessableEntity.code): # attempt to retrieve the API specific reason why the operation is invalid body = get_json(resp) param_name = body.get("param", {}).get("name") reason = body.get("detail", "Invalid") user_info.pop("password", None) # always remove password from output if param_name == "password": user_info["invalid_password"] = True user_info["reason_password"] = reason return self.add_template_data(user_info) if param_name == "user_email": user_info["invalid_user_email"] = True user_info["reason_user_email"] = reason return self.add_template_data(user_info) # fail if unknown bad request reason or other error type check_response(resp) # need to commit updates since we are using the same session # otherwise, updated user doesn't exist yet in the db for next calls self.request.tm.commit() # edits to groups checkboxes if is_edit_group_membership: selected_groups = self.request.POST.getall("member") removed_groups = list( set(joined_groups) - set(selected_groups)) new_groups = list(set(selected_groups) - set(joined_groups)) for group in removed_groups: self.leave_discoverable_group(group) for group in new_groups: self.join_discoverable_group(group) user_info["joined_groups"] = self.get_current_user_groups() user_info.pop("password", None) # always remove password from output return self.add_template_data(data=user_info)
def magpie_add_register_services_perms(services, statuses, curl_cookies, request_cookies, disable_getcapabilities): magpie_url = get_magpie_url() login_usr = get_constant("MAGPIE_ANONYMOUS_USER") for service_name in services: svc_available_perms_url = "{magpie}/services/{svc}/permissions" \ .format(magpie=magpie_url, svc=service_name) resp_available_perms = requests.get(svc_available_perms_url, cookies=request_cookies) if resp_available_perms.status_code == 401: raise_log("Invalid credentials, cannot update service permissions", exception=ValueError, logger=LOGGER) available_perms = get_json(resp_available_perms).get( "permission_names", []) # only applicable to services supporting "GetCapabilities" request if resp_available_perms.status_code and Permission.GET_CAPABILITIES.value in available_perms: # enforce 'getcapabilities' permission if available for service just updated (200) or created (201) # update 'getcapabilities' permission when the service existed and it allowed if (not disable_getcapabilities and statuses[service_name] == 409) \ or statuses[service_name] == 200 or statuses[service_name] == 201: # noqa svc_anonym_add_perms_url = "{magpie}/users/{usr}/services/{svc}/permissions" \ .format(magpie=magpie_url, usr=login_usr, svc=service_name) svc_anonym_perm_data = { "permission_name": Permission.GET_CAPABILITIES.value } requests.post(svc_anonym_add_perms_url, data=svc_anonym_perm_data, cookies=request_cookies) # check service response so Phoenix doesn't refuse registration # try with both the 'direct' URL and the 'GetCapabilities' URL attempt = 0 service_info_url = "{magpie}/services/{svc}".format( magpie=magpie_url, svc=service_name) service_info_resp = requests.get(service_info_url, cookies=request_cookies) service_url = get_json(service_info_resp).get(service_name).get( "service_url") svc_getcap_url = "{svc_url}/wps?service=WPS&version=1.0.0&request=GetCapabilities" \ .format(svc_url=service_url) while True: service_msg_direct = "Service response ({svc})".format( svc=service_name) service_msg_getcap = "Service response ({svc}, GetCapabilities)".format( svc=service_name) err, http = request_curl(service_url, cookies=curl_cookies, msg=service_msg_direct) if not err and http == 200: break err, http = request_curl(svc_getcap_url, cookies=curl_cookies, msg=service_msg_getcap) if not err and http == 200: break print_log( "[{url}] Bad response from service '{svc}' retrying after {sec}s..." .format(svc=service_name, url=service_url, sec=GETCAPABILITIES_INTERVAL), logger=LOGGER) time.sleep(GETCAPABILITIES_INTERVAL) attempt += 1 if attempt >= GETCAPABILITIES_ATTEMPTS: msg = "[{url}] No response from service '{svc}' after {tries} attempts. Skipping..." \ .format(svc=service_name, url=service_url, tries=attempt) print_log(msg, logger=LOGGER) break