Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
3 tasks done
mathilderv opened this issue Jun 6, 2024 · 5 comments
Labels
embedded viz:charts Namespace | Anything related to viz types

Comments

@mathilderv
Copy link

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 :

  • embedding works fine with charts using: SUM, COUNTD, AVG
  • embedding DOES NOT WORK for charts using: MIN, MAX, COUNT

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

  • I have searched Superset docs and Slack and didn't find a solution to my problem.
  • I have searched the GitHub issue tracker and didn't find a similar bug report.
  • I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
@dosubot dosubot bot added embedded viz:charts Namespace | Anything related to viz types labels Jun 6, 2024
Copy link

dosubot bot commented Jun 6, 2024

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
Copy link
Author

@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

Copy link

dosubot bot commented Jun 6, 2024

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
Copy link
Author

@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 ?

Copy link

dosubot bot commented Jun 7, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
embedded viz:charts Namespace | Anything related to viz types
Projects
None yet
Development

No branches or pull requests

1 participant