示例#1
0
 def apply(self, query: Query, value: Any) -> Query:
     return query.filter(
         or_(
             Dashboard.created_by_fk  # pylint: disable=comparison-with-callable
             == get_user_id(),
             Dashboard.changed_by_fk  # pylint: disable=comparison-with-callable
             == get_user_id(),
         ))
示例#2
0
 def run(self) -> str:
     self.validate()
     try:
         datasource_id = self._cmd_params.datasource_id
         datasource_type = self._cmd_params.datasource_type
         chart_id = self._cmd_params.chart_id
         tab_id = self._cmd_params.tab_id
         form_data = self._cmd_params.form_data
         check_access(datasource_id, chart_id, datasource_type)
         contextual_key = cache_key(session.get("_id"), tab_id,
                                    datasource_id, chart_id,
                                    datasource_type)
         key = cache_manager.explore_form_data_cache.get(contextual_key)
         if not key or not tab_id:
             key = random_key()
         if form_data:
             state: TemporaryExploreState = {
                 "owner": get_user_id(),
                 "datasource_id": datasource_id,
                 "datasource_type": DatasourceType(datasource_type),
                 "chart_id": chart_id,
                 "form_data": form_data,
             }
             cache_manager.explore_form_data_cache.set(key, state)
             cache_manager.explore_form_data_cache.set(contextual_key, key)
         return key
     except SQLAlchemyError as ex:
         logger.exception("Error running create command")
         raise TemporaryCacheCreateFailedError() from ex
示例#3
0
def populate_owners(
    owner_ids: Optional[List[int]],
    default_to_user: bool,
) -> List[User]:
    """
    Helper function for commands, will fetch all users from owners id's

    :param owner_ids: list of owners by id's
    :param default_to_user: make user the owner if `owner_ids` is None or empty
    :raises OwnersNotFoundValidationError: if at least one owner id can't be resolved
    :returns: Final list of owners
    """
    owner_ids = owner_ids or []
    owners = []
    if not owner_ids and default_to_user:
        return [g.user]
    if not (security_manager.is_admin() or get_user_id() in owner_ids):
        # make sure non-admins can't remove themselves as owner by mistake
        owners.append(g.user)
    for owner_id in owner_ids:
        owner = security_manager.get_user_by_id(owner_id)
        if not owner:
            raise OwnersNotFoundValidationError()
        owners.append(owner)
    return owners
        def validate_session(response: Response) -> Response:
            user_id = get_user_id()

            reset_token = (
                not request.cookies.get(self._jwt_cookie_name)
                or "async_channel_id" not in session
                or "async_user_id" not in session
                or user_id != session["async_user_id"]
            )

            if reset_token:
                async_channel_id = str(uuid.uuid4())
                session["async_channel_id"] = async_channel_id
                session["async_user_id"] = user_id

                sub = str(user_id) if user_id else None
                token = jwt.encode(
                    {"channel": async_channel_id, "sub": sub},
                    self._jwt_secret,
                    algorithm="HS256",
                )

                response.set_cookie(
                    self._jwt_cookie_name,
                    value=token,
                    httponly=True,
                    secure=self._jwt_cookie_secure,
                    domain=self._jwt_cookie_domain,
                )

            return response
示例#5
0
    def update(self, cmd_params: CommandParameters) -> Optional[str]:
        resource_id = cmd_params.resource_id
        key = cmd_params.key
        value = cast(
            str, cmd_params.value)  # schema ensures that value is not optional
        check_access(resource_id)
        entry: Entry = cache_manager.filter_state_cache.get(
            cache_key(resource_id, key))
        owner = get_user_id()
        if entry:
            if entry["owner"] != owner:
                raise TemporaryCacheAccessDeniedError()

            # Generate a new key if tab_id changes or equals 0
            contextual_key = cache_key(session.get("_id"), cmd_params.tab_id,
                                       resource_id)
            key = cache_manager.filter_state_cache.get(contextual_key)
            if not key or not cmd_params.tab_id:
                key = random_key()
                cache_manager.filter_state_cache.set(contextual_key, key)

            new_entry: Entry = {"owner": owner, "value": value}
            cache_manager.filter_state_cache.set(cache_key(resource_id, key),
                                                 new_entry)
        return key
示例#6
0
    def _run_async(self, form_data: Dict[str, Any],
                   command: ChartDataCommand) -> Response:
        """
        Execute command as an async query.
        """
        # First, look for the chart query results in the cache.
        result = None
        try:
            result = command.run(force_cached=True)
            if result is not None:
                return self._send_chart_response(result)
        except ChartDataCacheLoadError:
            pass

        # Otherwise, kick off a background job to run the chart query.
        # Clients will either poll or be notified of query completion,
        # at which point they will call the /data/<cache_key> endpoint
        # to retrieve the results.
        async_command = CreateAsyncChartDataJobCommand()
        try:
            async_command.validate(request)
        except AsyncQueryTokenException:
            return self.response_401()

        result = async_command.run(form_data, get_user_id())
        return self.response(202, **result)
示例#7
0
 def favorited_ids(charts: List[Slice]) -> List[FavStar]:
     ids = [chart.id for chart in charts]
     return [
         star.obj_id for star in db.session.query(FavStar.obj_id).filter(
             FavStar.class_name == FavStarClassName.CHART,
             FavStar.obj_id.in_(ids),
             FavStar.user_id == get_user_id(),
         ).all()
     ]
示例#8
0
def test_get_user_id(
    app_context: AppContext,
    mocker: MockFixture,
    username: Optional[str],
    user_id: Optional[int],
) -> None:
    mock_g = mocker.patch("superset.utils.core.g", spec={})
    mock_g.user = security_manager.find_user(username)
    assert get_user_id() == user_id
示例#9
0
 def favorited_ids(dashboards: List[Dashboard]) -> List[FavStar]:
     ids = [dash.id for dash in dashboards]
     return [
         star.obj_id for star in db.session.query(FavStar.obj_id).filter(
             FavStar.class_name == FavStarClassName.DASHBOARD,
             FavStar.obj_id.in_(ids),
             FavStar.user_id == get_user_id(),
         ).all()
     ]
示例#10
0
    def apply(self, query: BaseQuery, value: Any) -> BaseQuery:
        """
        Filter queries to only those owned by current user. If
        can_access_all_queries permission is set a user can list all queries

        :returns: query
        """
        if not security_manager.can_access_all_queries():
            query = query.filter(Query.user_id == get_user_id())
        return query
示例#11
0
 def set_owners(instance: Model, owners: List[int]) -> None:
     owner_objs = []
     user_id = get_user_id()
     if user_id and user_id not in owners:
         owners.append(user_id)
     for owner_id in owners:
         user = current_app.appbuilder.get_session.query(
             current_app.appbuilder.sm.user_model).get(owner_id)
         owner_objs.append(user)
     instance.owners = owner_objs
示例#12
0
 def apply(self, query: Query, value: Any) -> Query:
     # If anonymous user filter nothing
     if security_manager.current_user is None:
         return query
     users_favorite_query = db.session.query(FavStar.obj_id).filter(
         and_(
             FavStar.user_id == get_user_id(),
             FavStar.class_name == self.class_name,
         ))
     if value:
         return query.filter(and_(self.model.id.in_(users_favorite_query)))
     return query.filter(and_(~self.model.id.in_(users_favorite_query)))
示例#13
0
    def apply(self, query: Query, value: Any) -> Query:
        if security_manager.is_admin():
            return query

        filter_set_ids_by_dashboard_owners = (  # pylint: disable=C0103
            query.from_self(FilterSet.id).join(
                dashboard_user,
                FilterSet.owner_id == dashboard_user.c.dashboard_id).filter(
                    and_(
                        FilterSet.owner_type == DASHBOARD_OWNER_TYPE,
                        dashboard_user.c.user_id == get_user_id(),
                    )))

        return query.filter(
            or_(
                and_(
                    FilterSet.owner_type == USER_OWNER_TYPE,
                    FilterSet.owner_id == get_user_id(),
                ),
                FilterSet.id.in_(filter_set_ids_by_dashboard_owners),
            ))
示例#14
0
 def delete(self, cmd_params: CommandParameters) -> bool:
     resource_id = cmd_params.resource_id
     key = cache_key(resource_id, cmd_params.key)
     check_access(resource_id)
     entry: Entry = cache_manager.filter_state_cache.get(key)
     if entry:
         if entry["owner"] != get_user_id():
             raise TemporaryCacheAccessDeniedError()
         tab_id = cmd_params.tab_id
         contextual_key = cache_key(session.get("_id"), tab_id, resource_id)
         cache_manager.filter_state_cache.delete(contextual_key)
         return cache_manager.filter_state_cache.delete(key)
     return False
示例#15
0
 def create(self, cmd_params: CommandParameters) -> str:
     resource_id = cmd_params.resource_id
     tab_id = cmd_params.tab_id
     contextual_key = cache_key(session.get("_id"), tab_id, resource_id)
     key = cache_manager.filter_state_cache.get(contextual_key)
     if not key or not tab_id:
         key = random_key()
     value = cast(str, cmd_params.value)  # schema ensures that value is not optional
     check_access(resource_id)
     entry: Entry = {"owner": get_user_id(), "value": value}
     cache_manager.filter_state_cache.set(cache_key(resource_id, key), entry)
     cache_manager.filter_state_cache.set(contextual_key, key)
     return key
示例#16
0
    def current_user_id(self, add_to_cache_keys: bool = True) -> Optional[int]:
        """
        Return the user ID of the user who is currently logged in.

        :param add_to_cache_keys: Whether the value should be included in the cache key
        :returns: The user ID
        """

        if hasattr(g, "user") and g.user:
            id_ = get_user_id()
            if add_to_cache_keys:
                self.cache_key_wrapper(id_)
            return id_
        return None
示例#17
0
    def validate_unique_creation_method(
        dashboard_id: Optional[int] = None, chart_id: Optional[int] = None
    ) -> bool:
        """
        Validate if the user already has a chart or dashboard
        with a report attached form the self subscribe reports
        """

        query = db.session.query(ReportSchedule).filter_by(created_by_fk=get_user_id())
        if dashboard_id is not None:
            query = query.filter(ReportSchedule.dashboard_id == dashboard_id)

        if chart_id is not None:
            query = query.filter(ReportSchedule.chart_id == chart_id)

        return not db.session.query(query.exists()).scalar()
示例#18
0
 def apply(self, query: Query, value: Any) -> Query:
     if security_manager.can_access_all_datasources():
         return query
     datasource_perms = security_manager.user_view_menu_names("datasource_access")
     schema_perms = security_manager.user_view_menu_names("schema_access")
     owner_ids_query = (
         db.session.query(models.SqlaTable.id)
         .join(models.SqlaTable.owners)
         .filter(security_manager.user_model.id == get_user_id())
     )
     return query.filter(
         or_(
             self.model.perm.in_(datasource_perms),
             self.model.schema_perm.in_(schema_perms),
             models.SqlaTable.id.in_(owner_ids_query),
         )
     )
示例#19
0
 def filter_sets_lst(self) -> Dict[int, FilterSet]:
     if security_manager.is_admin():
         return self._filter_sets
     filter_sets_by_owner_type: Dict[str, List[Any]] = {
         "Dashboard": [],
         "User": []
     }
     for fs in self._filter_sets:
         filter_sets_by_owner_type[fs.owner_type].append(fs)
     user_filter_sets = list(
         filter(
             lambda filter_set: filter_set.owner_id == get_user_id(),
             filter_sets_by_owner_type["User"],
         ))
     return {
         fs.id: fs
         for fs in user_filter_sets + filter_sets_by_owner_type["Dashboard"]
     }
示例#20
0
    def update(self) -> Optional[Key]:
        filter_ = get_filter(self.resource, self.key)
        entry: KeyValueEntry = (
            db.session.query(KeyValueEntry)
            .filter_by(**filter_)
            .autoflush(False)
            .first()
        )
        if entry:
            entry.value = pickle.dumps(self.value)
            entry.expires_on = self.expires_on
            entry.changed_on = datetime.now()
            entry.changed_by_fk = get_user_id()
            db.session.merge(entry)
            db.session.commit()
            return Key(id=entry.id, uuid=entry.uuid)

        return None
示例#21
0
 def create(self) -> Key:
     entry = KeyValueEntry(
         resource=self.resource.value,
         value=pickle.dumps(self.value),
         created_on=datetime.now(),
         created_by_fk=get_user_id(),
         expires_on=self.expires_on,
     )
     if self.key is not None:
         try:
             if isinstance(self.key, UUID):
                 entry.uuid = self.key
             else:
                 entry.id = self.key
         except ValueError as ex:
             raise KeyValueCreateFailedError() from ex
     db.session.add(entry)
     db.session.commit()
     return Key(id=entry.id, uuid=entry.uuid)
示例#22
0
 def run(self) -> str:
     self.validate()
     try:
         DashboardDAO.get_by_id_or_slug(self.dashboard_id)
         value = {
             "dashboardId": self.dashboard_id,
             "state": self.state,
         }
         user_id = get_user_id()
         key = UpsertKeyValueCommand(
             resource=self.resource,
             key=get_deterministic_uuid(self.salt, (user_id, value)),
             value=value,
         ).run()
         assert key.id  # for type checks
         return encode_permalink_key(key=key.id, salt=self.salt)
     except SQLAlchemyError as ex:
         logger.exception("Error running create command")
         raise DashboardPermalinkCreateFailedError() from ex
示例#23
0
 def upsert(self) -> Key:
     filter_ = get_filter(self.resource, self.key)
     entry: KeyValueEntry = (
         db.session.query(KeyValueEntry)
         .filter_by(**filter_)
         .autoflush(False)
         .first()
     )
     if entry:
         entry.value = pickle.dumps(self.value)
         entry.expires_on = self.expires_on
         entry.changed_on = datetime.now()
         entry.changed_by_fk = get_user_id()
         db.session.merge(entry)
         db.session.commit()
         return Key(entry.id, entry.uuid)
     return CreateKeyValueCommand(
         resource=self.resource,
         value=self.value,
         key=self.key,
         expires_on=self.expires_on,
     ).run()
示例#24
0
 def check_ownership(self) -> None:
     try:
         if not security_manager.is_admin():
             filter_set: FilterSet = cast(FilterSet, self._filter_set)
             if filter_set.owner_type == USER_OWNER_TYPE:
                 if get_user_id() != filter_set.owner_id:
                     raise FilterSetForbiddenError(
                         str(self._filter_set_id),
                         "The user is not the owner of the filter_set",
                     )
             elif not security_manager.is_owner(self._dashboard):
                 raise FilterSetForbiddenError(
                     str(self._filter_set_id),
                     "The user is not an owner of the filter_set's dashboard",
                 )
     except NotAuthorizedException as err:
         raise FilterSetForbiddenError(
             str(self._filter_set_id),
             "user not authorized to access the filterset",
         ) from err
     except FilterSetForbiddenError as err:
         raise err
示例#25
0
 def run(self) -> bool:
     try:
         key = self._cmd_params.key
         state: TemporaryExploreState = cache_manager.explore_form_data_cache.get(
             key)
         if state:
             datasource_id: int = state["datasource_id"]
             chart_id: Optional[int] = state["chart_id"]
             datasource_type = DatasourceType(state["datasource_type"])
             check_access(datasource_id, chart_id, datasource_type)
             if state["owner"] != get_user_id():
                 raise TemporaryCacheAccessDeniedError()
             tab_id = self._cmd_params.tab_id
             contextual_key = cache_key(session.get("_id"), tab_id,
                                        datasource_id, chart_id,
                                        datasource_type)
             cache_manager.explore_form_data_cache.delete(contextual_key)
             return cache_manager.explore_form_data_cache.delete(key)
         return False
     except SQLAlchemyError as ex:
         logger.exception("Error running delete command")
         raise TemporaryCacheDeleteFailedError() from ex
示例#26
0
    def run(self) -> Optional[str]:
        self.validate()
        try:
            datasource_id = self._cmd_params.datasource_id
            chart_id = self._cmd_params.chart_id
            datasource_type = self._cmd_params.datasource_type
            key = self._cmd_params.key
            form_data = self._cmd_params.form_data
            check_access(datasource_id, chart_id, datasource_type)
            state: TemporaryExploreState = cache_manager.explore_form_data_cache.get(
                key)
            owner = get_user_id()
            if state and form_data:
                if state["owner"] != owner:
                    raise TemporaryCacheAccessDeniedError()

                # Generate a new key if tab_id changes or equals 0
                tab_id = self._cmd_params.tab_id
                contextual_key = cache_key(session.get("_id"), tab_id,
                                           datasource_id, chart_id,
                                           datasource_type)
                key = cache_manager.explore_form_data_cache.get(contextual_key)
                if not key or not tab_id:
                    key = random_key()
                    cache_manager.explore_form_data_cache.set(
                        contextual_key, key)

                new_state: TemporaryExploreState = {
                    "owner": owner,
                    "datasource_id": datasource_id,
                    "datasource_type": DatasourceType(datasource_type),
                    "chart_id": chart_id,
                    "form_data": form_data,
                }
                cache_manager.explore_form_data_cache.set(key, new_state)
            return key
        except SQLAlchemyError as ex:
            logger.exception("Error running update command")
            raise TemporaryCacheUpdateFailedError() from ex
示例#27
0
    def log_with_context(  # pylint: disable=too-many-locals
        self,
        action: str,
        duration: Optional[timedelta] = None,
        object_ref: Optional[str] = None,
        log_to_statsd: bool = True,
        **payload_override: Optional[Dict[str, Any]],
    ) -> None:
        # pylint: disable=import-outside-toplevel
        from superset.views.core import get_form_data

        referrer = request.referrer[:1000] if request and request.referrer else None

        duration_ms = int(duration.total_seconds() *
                          1000) if duration else None

        # Initial try and grab user_id via flask.g.user
        user_id = get_user_id()

        # Whenever a user is not bounded to a session we
        # need to add them back before logging to capture user_id
        if user_id is None:
            try:
                session = current_app.appbuilder.get_session
                session.add(g.user)
                user_id = get_user_id()
            except Exception as ex:  # pylint: disable=broad-except
                logging.warning(ex)
                user_id = None

        payload = collect_request_payload()
        if object_ref:
            payload["object_ref"] = object_ref
        if payload_override:
            payload.update(payload_override)

        dashboard_id: Optional[int] = None
        try:
            dashboard_id = int(payload.get("dashboard_id"))  # type: ignore
        except (TypeError, ValueError):
            dashboard_id = None

        if "form_data" in payload:
            form_data, _ = get_form_data()
            payload["form_data"] = form_data
            slice_id = form_data.get("slice_id")
        else:
            slice_id = payload.get("slice_id")

        try:
            slice_id = int(slice_id)  # type: ignore
        except (TypeError, ValueError):
            slice_id = 0

        if log_to_statsd:
            self.stats_logger.incr(action)

        try:
            # bulk insert
            explode_by = payload.get("explode")
            records = json.loads(payload.get(explode_by))  # type: ignore
        except Exception:  # pylint: disable=broad-except
            records = [payload]

        self.log(
            user_id,
            action,
            records=records,
            dashboard_id=dashboard_id,
            slice_id=slice_id,
            duration_ms=duration_ms,
            referrer=referrer,
        )
示例#28
0
 def _validate_owner_id_exists(self) -> None:
     owner_id = self._properties[OWNER_ID_FIELD]
     if not (get_user_id() == owner_id or security_manager.get_user_by_id(owner_id)):
         raise FilterSetCreateFailedError(
             str(self._dashboard_id), "owner_id does not exists"
         )
示例#29
0
    def apply(self, query: Query, value: Any) -> Query:
        if security_manager.is_admin():
            return query

        datasource_perms = security_manager.user_view_menu_names(
            "datasource_access")
        schema_perms = security_manager.user_view_menu_names("schema_access")

        is_rbac_disabled_filter = []
        dashboard_has_roles = Dashboard.roles.any()
        if is_feature_enabled("DASHBOARD_RBAC"):
            is_rbac_disabled_filter.append(~dashboard_has_roles)

        datasource_perm_query = (db.session.query(Dashboard.id).join(
            Dashboard.slices, isouter=True).filter(
                and_(
                    Dashboard.published.is_(True),
                    *is_rbac_disabled_filter,
                    or_(
                        Slice.perm.in_(datasource_perms),
                        Slice.schema_perm.in_(schema_perms),
                        security_manager.can_access_all_datasources(),
                    ),
                )))

        users_favorite_dash_query = db.session.query(FavStar.obj_id).filter(
            and_(
                FavStar.user_id == get_user_id(),
                FavStar.class_name == "Dashboard",
            ))
        owner_ids_query = (db.session.query(Dashboard.id).join(
            Dashboard.owners).filter(
                security_manager.user_model.id == get_user_id()))

        feature_flagged_filters = []
        if is_feature_enabled("DASHBOARD_RBAC"):
            roles_based_query = (db.session.query(Dashboard.id).join(
                Dashboard.roles).filter(
                    and_(
                        Dashboard.published.is_(True),
                        dashboard_has_roles,
                        Role.id.in_(
                            [x.id for x in security_manager.get_user_roles()]),
                    ), ))

            feature_flagged_filters.append(Dashboard.id.in_(roles_based_query))

        if is_feature_enabled("EMBEDDED_SUPERSET"
                              ) and security_manager.is_guest_user(g.user):

            guest_user: GuestUser = g.user
            embedded_dashboard_ids = [
                r["id"] for r in guest_user.resources
                if r["type"] == GuestTokenResourceType.DASHBOARD.value
            ]

            # TODO (embedded): only use uuid filter once uuids are rolled out
            condition = (Dashboard.embedded.any(
                EmbeddedDashboard.uuid.in_(embedded_dashboard_ids)) if any(
                    is_uuid(id_) for id_ in embedded_dashboard_ids) else
                         Dashboard.id.in_(embedded_dashboard_ids))

            feature_flagged_filters.append(condition)

        query = query.filter(
            or_(
                Dashboard.id.in_(owner_ids_query),
                Dashboard.id.in_(datasource_perm_query),
                Dashboard.id.in_(users_favorite_dash_query),
                *feature_flagged_filters,
            ))

        return query
示例#30
0
 def __init__(self, query_params: Dict[str, Any]):
     self.create_table_as_select = None
     self.database = None
     self._init_from_query_params(query_params)
     self.user_id = get_user_id()
     self.client_id_or_short_id = cast(str, self.client_id or utils.shortid()[:10])