예제 #1
0
    def get_acl(self, sub_api_route=None):
        self.expand_acl(self.service, self.request.user)

        match_index = 0
        route_parts = self.request.path.split("/")
        route_api_base = self.service.resource_name if sub_api_route is None else sub_api_route

        if self.service.resource_name in route_parts and route_api_base in route_parts:
            api_idx = route_parts.index(route_api_base)
            # keep only parts after api base route to process it
            if len(route_parts) - 1 > api_idx:
                route_parts = route_parts[api_idx + 1::]
                route_child = self.service

                # process read/write inheritance permission access
                while route_child and route_parts:
                    part_name = route_parts.pop(0)
                    route_res_id = route_child.resource_id
                    route_child = models.find_children_by_name(part_name, parent_id=route_res_id,
                                                               db_session=self.request.db)
                    match_index = len(self.acl)
                    self.expand_acl(route_child, self.request.user)

        # process read/write-match specific permission access
        # (convert exact route 'match' to read/write counterparts only if matching last item's permissions)
        for i in range(match_index, len(self.acl)):
            if Permission.get(self.acl[i][2]) == Permission.READ_MATCH:
                self.acl[i] = (self.acl[i][0], self.acl[i][1], Permission.READ.value)
            if Permission.get(self.acl[i][2]) == Permission.WRITE_MATCH:
                self.acl[i] = (self.acl[i][0], self.acl[i][1], Permission.WRITE.value)
        return self.acl
예제 #2
0
def check_valid_service_or_resource_permission(permission_name,
                                               service_or_resource,
                                               db_session):
    # type: (Union[Str, Permission], ServiceOrResourceType, Session) -> Optional[Permission]
    """
    Checks if a permission is valid to be applied to a specific `service` or a `resource` under a root service.

    :param permission_name: permission name to be validated
    :param service_or_resource: resource item corresponding to either a Service or a Resource
    :param db_session: db connection
    :return: valid Permission if allowed by the service/resource
    :raises HTTPBadRequest: if the permission is not valid for the targeted service/resource
    """
    svc_res_permissions = get_resource_permissions(service_or_resource,
                                                   db_session=db_session)
    svc_res_type = service_or_resource.resource_type
    svc_res_name = service_or_resource.resource_name
    svc_res_perm = Permission.get(permission_name)
    ax.verify_param(
        svc_res_perm,
        param_name="permission_name",
        param_compare=svc_res_permissions,
        is_in=True,
        http_error=HTTPBadRequest,
        content={
            "resource_type": str(svc_res_type),
            "resource_name": str(svc_res_name)
        },
        msg_on_fail=s.UserResourcePermissions_POST_BadRequestResponseSchema.
        description)
    return svc_res_perm
예제 #3
0
 def permission_requested(self):
     # type: () -> Permission
     try:
         req = self.parser.params[u"request"]
         perm = Permission.get(req)
         if perm is None:
             raise NotImplementedError("Undefined 'Permission' from 'request' parameter: {!s}".format(req))
         return perm
     except KeyError as ex:
         # if 'ServiceInterface', 'params_expected' is empty and will raise a KeyError
         raise NotImplementedError("Exception: [{!r}] for class '{}'.".format(ex, type(self)))
예제 #4
0
    def check_request(self, request):
        if request.path.startswith(self.twitcher_protected_path):
            service_name = parse_service_name(request.path,
                                              self.twitcher_protected_path)
            service = evaluate_call(
                lambda: Service.by_service_name(service_name,
                                                db_session=request.db),
                http_error=HTTPForbidden,
                msg_on_fail="Service query by name refused by db.")
            verify_param(service,
                         not_none=True,
                         http_error=HTTPNotFound,
                         msg_on_fail="Service name not found.")

            # return a specific type of service, ex: ServiceWPS with all the acl (loaded according to the service_type)
            service_specific = service_factory(service, request)
            # should contain all the acl, this the only thing important
            # parse request (GET/POST) to get the permission requested for that service
            permission_requested = service_specific.permission_requested()
            # convert permission enum to str for comparison
            permission_requested = Permission.get(
                permission_requested).value if permission_requested else None

            if permission_requested:
                LOGGER.info("'%s' request '%s' permission on '%s'",
                            request.user, permission_requested, request.path)
                self.update_request_cookies(request)
                authn_policy = request.registry.queryUtility(
                    IAuthenticationPolicy)
                authz_policy = request.registry.queryUtility(
                    IAuthorizationPolicy)
                principals = authn_policy.effective_principals(request)
                has_permission = authz_policy.permits(service_specific,
                                                      principals,
                                                      permission_requested)

                if LOGGER.isEnabledFor(logging.DEBUG):
                    LOGGER.debug("%s - AUTHN policy configurations:",
                                 type(self).__name__)
                    base_attr = [
                        attr for attr in dir(authn_policy.cookie)
                        if not attr.startswith("_")
                    ]
                    for attr_name in base_attr:
                        LOGGER.debug("  %s: %s", attr_name,
                                     getattr(authn_policy.cookie, attr_name))

                if has_permission:
                    return  # allowed

            raise OWSAccessForbidden(
                "Not authorized to access this resource. "
                "User does not meet required permissions.")
예제 #5
0
 def permission_requested(self):
     # type: () -> Permission
     try:
         req = str(self.parser.params["request"]).lower()
         perm = Permission.get(req)
         if perm is None:
             raise NotImplementedError(
                 "Undefined 'Permission' from 'request' parameter: {!s}".
                 format(req))
         return perm
     except KeyError as exc:
         raise NotImplementedError(
             "Exception: [{!r}] for class '{}'.".format(exc, type(self)))
예제 #6
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.")
예제 #7
0
def apply_permission_entry(
        permission_config_entry,  # type: ConfigItem
        entry_index,  # type: int
        resource_id,  # type: int
        cookies_or_session,  # type: CookiesOrSessionType
        magpie_url,  # type: Str
):  # type: (...) -> None
    """
    Applies the single permission entry retrieved from the permission configuration.

    Assumes that permissions fields where pre-validated. Permission is applied for the user/group/resource using request
    or db session accordingly to arguments.
    """
    def _apply_request(_usr_name=None, _grp_name=None):
        """
        Apply operation using HTTP request.
        """
        action_oper = None
        if usr_name:
            action_oper = UserResourcePermissionsAPI.path.replace(
                "{user_name}", _usr_name)
        if grp_name:
            action_oper = GroupResourcePermissionsAPI.path.replace(
                "{group_name}", _grp_name)
        if not action_oper:
            return None
        if create_perm:
            action_func = requests.post
            action_path = "{url}{path}".format(url=magpie_url,
                                               path=action_oper)
            action_body = {"permission_name": perm_name}
        else:
            action_func = requests.delete
            action_path = "{url}{path}/{perm_name}".format(url=magpie_url,
                                                           path=action_oper,
                                                           perm_name=perm_name)
            action_body = {}
        action_path = action_path.format(resource_id=resource_id)
        action_resp = action_func(action_path,
                                  json=action_body,
                                  cookies=cookies_or_session)
        return action_resp

    def _apply_session(_usr_name=None, _grp_name=None):
        """
        Apply operation using db session.
        """
        from magpie.api.management.user import user_utils as ut
        from magpie.api.management.group import group_utils as gt

        res = ResourceService.by_resource_id(resource_id,
                                             db_session=cookies_or_session)
        if _usr_name:
            usr = UserService.by_user_name(_usr_name,
                                           db_session=cookies_or_session)
            if create_perm:
                return ut.create_user_resource_permission_response(
                    usr, res, perm, db_session=cookies_or_session)
            else:
                return ut.delete_user_resource_permission_response(
                    usr, res, perm, db_session=cookies_or_session)
        if _grp_name:
            grp = GroupService.by_group_name(_grp_name,
                                             db_session=cookies_or_session)
            if create_perm:
                return gt.create_group_resource_permission_response(
                    grp, res, perm, db_session=cookies_or_session)
            else:
                return gt.delete_group_resource_permission_response(
                    grp, res, perm, db_session=cookies_or_session)

    def _apply_profile(_usr_name=None, _grp_name=None):
        """
        Creates the user/group profile as required.
        """
        usr_data = {
            "user_name": _usr_name,
            "password": "******",
            "email": "{}@mail.com".format(_usr_name),
            "group_name": get_constant("MAGPIE_ANONYMOUS_GROUP")
        }
        if use_request(cookies_or_session):
            if _usr_name:
                path = "{url}{path}".format(url=magpie_url, path=UsersAPI.path)
                return requests.post(path, json=usr_data)
            if _grp_name:
                path = "{url}{path}".format(url=magpie_url,
                                            path=GroupsAPI.path)
                data = {"group_name": _grp_name}
                return requests.post(path, json=data)
        else:
            if _usr_name:
                from magpie.api.management.user.user_utils import create_user
                usr_data[
                    'db_session'] = cookies_or_session  # back-compatibility python 2 cannot have kw after **unpack
                return create_user(**usr_data)
            if _grp_name:
                from magpie.api.management.group.group_utils import create_group
                return create_group(_grp_name, cookies_or_session)

    def _validate_response(operation, is_create, item_type="Permission"):
        """
        Validate action/operation applied.
        """
        # handle HTTPException raised
        if not islambda(operation):
            raise Exception("invalid use of method")
        try:
            _resp = operation()
            if _resp is None:
                return
        except HTTPException as exc:
            _resp = exc
        except Exception:
            raise

        # validation according to status code returned
        if is_create:
            if _resp.status_code == 201:
                warn_permission("{} successfully created.".format(item_type),
                                entry_index,
                                level=logging.INFO,
                                trail='')
            elif _resp.status_code == 409:
                warn_permission("{} already exists.".format(item_type),
                                entry_index,
                                level=logging.INFO)
            else:
                warn_permission("Unknown response [{}]".format(
                    _resp.status_code),
                                entry_index,
                                permission=permission_config_entry,
                                level=logging.ERROR)
        else:
            if _resp.status_code == 200:
                warn_permission("{} successfully removed.".format(item_type),
                                entry_index,
                                level=logging.INFO,
                                trail='')
            elif _resp.status_code == 404:
                warn_permission("{} already removed.".format(item_type),
                                entry_index,
                                level=logging.INFO)
            else:
                warn_permission("Unknown response [{}]".format(
                    _resp.status_code),
                                entry_index,
                                permission=permission_config_entry,
                                level=logging.ERROR)

    create_perm = permission_config_entry["action"] == "create"
    perm_name = permission_config_entry["permission"]
    usr_name = permission_config_entry.get("user")
    grp_name = permission_config_entry.get("group")
    perm = Permission.get(perm_name)

    _validate_response(lambda: _apply_profile(usr_name, None), is_create=True)
    _validate_response(lambda: _apply_profile(None, grp_name), is_create=True)

    if use_request(cookies_or_session):
        _validate_response(lambda: _apply_request(usr_name, None),
                           is_create=create_perm)
        _validate_response(lambda: _apply_request(None, grp_name),
                           is_create=create_perm)
    else:
        _validate_response(lambda: _apply_session(usr_name, None),
                           is_create=create_perm)
        _validate_response(lambda: _apply_session(None, grp_name),
                           is_create=create_perm)