apache / superset

Apache Superset is a Data Visualization and Data Exploration Platform
https://superset.apache.org/
Apache License 2.0
62.71k stars 13.84k forks source link

"Error 403 Forbidden" displayed on an embedded chart when using a particular aggregation function in the chart metric #29106

Open mathilderv opened 5 months ago

mathilderv commented 5 months ago

Bug description

I am embedding a dashboard in another app. Embedding does not work when the chart metrics are using some of the aggregation functions :

On the Superset tool itself, there's no visible issue. It's only once the chart is embedded that I am encountering this issue and the following error message: image <!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden

How to reproduce the bug

You need to embed the charts in another app to reproduce the bug. There's no sign of the bug on Superset.

  1. Create a chart (tested on : big number chart, bar chart, line chart)
  2. For the metric, choose an aggregation of type MIN or MAX or COUNT
  3. Save the chart and add it to the dashboard you are embedding.
  4. Normally: you should see the chart on Superset, but chart should be broken in the final destination of the chart.

Screenshots/recordings

No response

Superset version

3.1.3

Python version

I don't know

Node version

I don't know

Browser

Chrome

Additional context

No response

Checklist

dosubot[bot] commented 5 months ago

Hey there, @mathilderv! 👋 I'm here to help you with your Superset issue. I'm a bot that can help you solve bugs, answer questions, and become a contributor. Let's get to the bottom of this together!

The "403 Forbidden" error for charts using aggregation functions such as MIN, MAX, or COUNT when embedded from Superset version 3.1.3 is likely due to permission issues. Specifically, the code checks if the user has permission to export files in certain formats, and if not, it returns a 403 error.

From the provided code:

if result_format in ChartDataResultFormat.table_like():
    # Verify user has permission to export file
    if not security_manager.can_access("can_csv", "Superset"):
        return self.response_403()

This snippet indicates that if the result format is table-like (which includes formats like CSV), the system checks if the user has the "can_csv" permission. If the user lacks this permission, a "403 Forbidden" response is returned.

Aggregation functions like MIN, MAX, and COUNT might be triggering this permission check, whereas SUM, COUNTD, and AVG might not, possibly due to differences in how the results are formatted or processed.

To resolve this issue, ensure that the user embedding the charts has the necessary permissions, specifically the "can_csv" permission in Superset [1].

To continue talking to Dosu, mention @dosu.

mathilderv commented 5 months ago

@dosu I have taken a look at the permissions associated with each role in the Superset settings: all of them already has the "can csv on Superset" permission.

You are mentioning a "can_csv" permission: is it a permission that should be implemented elsewhere ? thanks

dosubot[bot] commented 5 months ago

The "can_csv" permission mentioned is indeed the same as the "can csv on Superset" permission. However, there might be another permission that is required for embedding charts with certain aggregation functions.

Ensure that the user also has the "explore_json" permission. This permission is necessary for accessing the /explore_json/ endpoint, which is used for generating chart data. Without this permission, a "403 Forbidden" error can occur.

To add the "explore_json" permission to a role:

  1. Navigate to Roles:

    • Go to Menu -> Security -> List Roles.
  2. Edit the Role:

    • Select the role you want to edit (e.g., the role assigned to the user embedding the charts).
    • In the Permissions dropdown, search for and select the "explore_json" permission.
    • Save the changes.

This should resolve the "403 Forbidden" error when embedding charts with MIN, MAX, or COUNT aggregation functions [1][2].

To continue talking to Dosu, mention @dosu.

mathilderv commented 5 months ago

@dosu

I have verified for all of my users and they all have the "can csv on Superset" and the "can explore json on Superset" permissions.

Could there be another reason to my issue ?

dosubot[bot] commented 5 months ago

Yes, there could be another reason for the "403 Forbidden" error when embedding charts with the MIN, MAX, or COUNT aggregation functions in Superset version 3.1.3, despite having the necessary permissions. The issue might be related to the security checks implemented in the SupersetSecurityManager class, specifically in the raise_for_access method.

The raise_for_access method performs various checks to ensure that the user has the appropriate permissions to access the requested resource. If any of these checks fail, a SupersetSecurityException is raised, resulting in a "403 Forbidden" error.

Here is the relevant part of the raise_for_access method:

def raise_for_access(
    self,
    dashboard: Optional["Dashboard"] = None,
    chart: Optional["Slice"] = None,
    database: Optional["Database"] = None,
    datasource: Optional["BaseDatasource"] = None,
    query: Optional["Query"] = None,
    query_context: Optional["QueryContext"] = None,
    table: Optional["Table"] = None,
    viz: Optional["BaseViz"] = None,
    sql: Optional[str] = None,
    catalog: Optional[str] = None,
    schema: Optional[str] = None,
) -> None:
    # ... (other checks)

    if datasource or query_context or viz:
        form_data = None
        if query_context:
            datasource = query_context.datasource
            form_data = query_context.form_data
        elif viz:
            datasource = viz.datasource
            form_data = viz.form_data

        assert datasource
        if not (
            self.can_access_schema(datasource)
            or self.can_access("datasource_access", datasource.perm or "")
            or self.is_owner(datasource)
            or (
                form_data
                and (dashboard_id := form_data.get("dashboardId"))
                and (
                    dashboard_ := self.get_session.query(Dashboard)
                    .filter(Dashboard.id == dashboard_id)
                    .one_or_none()
                )
                and (
                    (is_feature_enabled("DASHBOARD_RBAC") and dashboard_.roles)
                    or (
                        is_feature_enabled("EMBEDDED_SUPERSET")
                        and self.is_guest_user()
                    )
                )
                and (
                    (
                        form_data.get("type") == "NATIVE_FILTER"
                        and (native_filter_id := form_data.get("native_filter_id"))
                        and dashboard_.json_metadata
                        and (json_metadata := json.loads(dashboard_.json_metadata))
                        and any(
                            target.get("datasetId") == datasource.id
                            for fltr in json_metadata.get(
                                "native_filter_configuration",
                                [],
                            )
                            for target in fltr.get("targets", [])
                            if native_filter_id == fltr.get("id")
                        )
                    )
                    or (
                        form_data.get("type") != "NATIVE_FILTER"
                        and (slice_id := form_data.get("slice_id"))
                        and (
                            slc := self.get_session.query(Slice)
                            .filter(Slice.id == slice_id)
                            .one_or_none()
                        )
                        and slc in dashboard_.slices
                        and slc.datasource == datasource
                    )
                )
                and self.can_access_dashboard(dashboard_)
            )
        ):
            raise SupersetSecurityException(
                self.get_datasource_access_error_object(datasource)
            )

    # ... (other checks)

In this method, the checks for datasource, query_context, and viz ensure that the user has the necessary permissions to access the datasource. If any of these checks fail, a SupersetSecurityException is raised, which results in a "403 Forbidden" error.

Additionally, the ChartDataRestApi class in superset/charts/data/api.py includes methods that handle data requests and responses for charts. These methods also perform various checks and validations, such as verifying the query context, checking for cached data, and ensuring the user has the necessary permissions to access the data. If any of these checks fail, it could result in a "403 Forbidden" error.

Therefore, even if you have the necessary permissions, other factors such as the specific configuration of the datasource, the form data, the dashboard roles, or the query context might be causing the error [1][2].

To continue talking to Dosu, mention @dosu.