GitHub user teharris1 edited a comment on the discussion: How Restrict Access 
to Embedded Dashboards on a Role-By-Role Basis

Here is a solution that may help someone else. I used the basic idea of this 
post but with a bit of a twist. With the code from above, I could not get the 
CSRF token to pass in the iframe as a session token so the frame would not 
render. The general idea of the solution is to pass back the roles of the 
desired user as if they are the public user's roles. Here is the code in 
Superset that I used.  This all goes in your `config.py` file.

```
class CustomSecurityManager(SupersetSecurityManager):

    def request_loader(self, request: Request) -> User | None:
        """Override the request_loader method."""
        if feature_flag_manager.is_feature_enabled("EMBEDDED_SUPERSET"):
            guest_user_roles = self.get_user_roles_from_app(request)
            if guest_user_roles:
                return guest_user_roles
            return self.get_guest_user_from_request(request)
        return None

    def get_user_roles_from_app(self, request: Request) -> User | None:
        """Get a guest user but with the actual user's roles from the token 
provided."""
        token = request.headers.get(
            current_app.config["GUEST_TOKEN_HEADER_NAME"]
        ) or request.form.get("guest_token")
        if token:
            # Validate the token and retrieve the user
            user = self.validate_token_and_get_user(token)

            # This gets the dashboard ID for use in the guest user token
            parsed_url = urllib.parse.urlparse(request.referrer)
            queries = parsed_url.query.split("&")
            for query in queries:
                if "dashboard_id" in query:
                    dashboard_id = query.split("=")[1]
                    break
            guest_user_token = {
                "user": {
                    "username": user.username,
                    "first_name": user.first_name,
                    "last_name": user.last_name,
                },
                "resources": [{
                    "type": "dashboard",
                    "id": dashboard_id
                }]
            }

            # Return the guest user but with the logged in user's roles
            return self.guest_user_cls(
                token=guest_user_token,
                roles=user.roles,
            )
        return None

    def validate_token_and_get_user(self, token: str) -> User | None:
        """Validate the token and return the User object."""
        # WHen you use a user token the decoded token has the user ID in the 
sub field
        decoded_token = decode_token(token)
        user_id = decoded_token["sub"]
        if user_id:
            return self.get_user_by_id(user_id)
        return None

    def get_user_by_id(self, user_id: int) -> User | None:
        """Get the User object."""
        # Get the user
        return 
self.get_session.query(self.user_model).filter_by(id=user_id).first()
```

In the frontend where you want to embed the dashboard as a specific user, you 
need to call the Superset API `/api/v1/security/login` to get a user token 
similar to the following:
```
import requests

def get_user_token():
    """Get a Superset user token."""
    base_url = "<YOUR SUPERSET URL>"
    session = requests.Session()

    login_url = f"{base_url}/api/v1/security/login"
    login_payload = {
        "username": "<YOUR USER NAME>",
        "password": "<YOUR USER PASSWORD>",
        "provider": "db",
        "refresh": True,
    }
    response = session.post(login_url, json=login_payload, timeout=20)
    return response.json()['access_token']

```

This will return a user access token, which is used in the Superset 
embedDashboard API as follows:
```
embedDashboard({
    id: "<YOUR EMBEDDED DASHBOARD UID>",
    supersetDomain: "<YOUR SUPERSET URL>",
    mountPoint: <YOUR DIV>, 
    fetchGuestToken: () => { return access_token },
    dashboardUiConfig: {
        hideTitle: true,
        filters: {
            expanded: true,
        },
        urlParams: {
          dashboard_id: <YOUR DASHBOARD NUMBER>
        }
    },
    iframeSandboxExtras: ['allow-popups-to-escape-sandbox'],
});
```

The `fetchGuestToken` function is just the user `access_token` from the 
previous code snippet. This is a real user's access token rather than a guest 
token. 

Notice that there is a `urlParams` for `dashboard_id` which is used in the 
Superset code to generate the guest token. You could also get the dashboard ID 
on the Superset side by looking up the embedded dashboard UID. 

This code technically does not present the dashboard as the user that is logged 
in with the access token. But it does present the dashboard back with the roles 
of that user resulting in the same outcome. It also requires that you have a 
real user's login information otherwise you actually get the guest user role as 
a return.  Optionally, you could have no guest user role and then the dashboard 
would not render as the result would be a 401 unauthorized result. 

GitHub link: 
https://github.com/apache/superset/discussions/30420#discussioncomment-12602402

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: 
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to