Exemplo n.º 1
0
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
Exemplo n.º 2
0
 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))
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
 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
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
 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
Exemplo n.º 7
0
 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
Exemplo n.º 8
0
 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
Exemplo n.º 9
0
    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
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
    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
Exemplo n.º 12
0
    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)
Exemplo n.º 13
0
 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"]
Exemplo n.º 14
0
 def get_user_names(self):
     resp = request_api(self.request, schemas.UsersAPI.path, "GET")
     check_response(resp)
     return get_json(resp)["user_names"]
Exemplo n.º 15
0
 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"]
Exemplo n.º 16
0
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
Exemplo n.º 17
0
    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
Exemplo n.º 18
0
 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"]
Exemplo n.º 19
0
def format_response(response):
    response_json = get_json(response)
    return str(response_json.get("code")) + " : " + str(
        response_json.get("detail"))
Exemplo n.º 20
0
 def get_service_types(self):
     svc_types_resp = request_api(self.request,
                                  schemas.ServiceTypesAPI.path, "GET")
     return get_json(svc_types_resp)["service_types"]
Exemplo n.º 21
0
 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"]
Exemplo n.º 22
0
 def request_providers_json(self):
     resp = request_api(self.request, schemas.ProvidersAPI.path, "GET")
     check_response(resp)
     return get_json(resp)["providers"]
Exemplo n.º 23
0
    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)
Exemplo n.º 24
0
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.")
Exemplo n.º 25
0
 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"]
Exemplo n.º 26
0
 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"]
Exemplo n.º 27
0
    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)
Exemplo n.º 28
0
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