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):
"""Custom security manager class for Superset."""
def request_loader(self, request: Request) -> User | None:
# pylint: disable=import-outside-toplevel
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:
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:
# 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
return
self.get_session.query(self.user_model).filter_by(id=user_id).first()
```
In the frontend 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]