mirror of
https://github.com/apache/superset.git
synced 2026-09-01 04:51:23 +00:00
feat(security): add guest user attributes and get_guest_user_attribute() macro (#33924)
Co-authored-by: Yash Janoria <yash.janoria@314ecorp.com> Co-authored-by: Evan <evan@preset.io> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Evan Rusackas <evan@rusackas.com>
This commit is contained in:
co-authored by
Yash Janoria
Evan
Claude Opus 4.8
Evan Rusackas
parent
8181917f79
commit
42e4030104
@@ -315,6 +315,76 @@ Here's a concrete example:
|
||||
WHERE country_code = 'US'
|
||||
```
|
||||
|
||||
**Guest User Attributes**
|
||||
|
||||
The `{{ get_guest_user_attribute('attribute_name') }}` macro returns a specific attribute value from the guest user context.
|
||||
This is useful when working with embedded Superset where guest tokens can contain custom attributes that need to be
|
||||
accessed in SQL queries.
|
||||
|
||||
This macro only works when the current user is a guest user (authenticated via guest token). If the current user is
|
||||
not a guest user, or if the specified attribute doesn't exist, the macro will return `None` or the provided default value.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the resolved value (whether it
|
||||
came from the guest token, a null attribute, or the provided default) will be used by Superset when
|
||||
calculating the cache key. A cache key is a unique identifier that determines if there's a cache hit in the
|
||||
future and Superset can retrieve cached data. Including the resolved value on every branch ensures two guests
|
||||
whose tokens render different SQL never share a cache entry.
|
||||
|
||||
You can disable the inclusion of the attribute value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code, but only do so
|
||||
when the value cannot affect the query results:
|
||||
|
||||
```
|
||||
{{ get_guest_user_attribute('department', add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
You can also provide a default value if the attribute is not found:
|
||||
|
||||
```
|
||||
{{ get_guest_user_attribute('region', default='US') }}
|
||||
```
|
||||
|
||||
Here's a concrete example of using guest user attributes in a query:
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM sales_data
|
||||
WHERE region = '{{ get_guest_user_attribute("user_region", default="global") }}'
|
||||
AND department = '{{ get_guest_user_attribute("department") }}'
|
||||
```
|
||||
|
||||
:::warning[Security Warning]
|
||||
|
||||
Guest token attributes come from the embedding application. By default,
|
||||
`get_guest_user_attribute()` escapes string values — including strings nested inside
|
||||
arrays and object values, and caller-supplied defaults — through the database dialect's
|
||||
literal rendering (the same mechanism as `url_param()`). This covers dialect-specific
|
||||
escape characters such as the backslash on MySQL/MariaDB, so the example above is safe
|
||||
to interpolate directly. If you pass `escape_result=False`, or interpolate non-string
|
||||
values (numbers, booleans), you are responsible for validating or allowlisting the
|
||||
values, since they originate outside Superset.
|
||||
|
||||
If a guest attribute is an array and you plan to pipe it through the `|where_in` filter
|
||||
(for example `full_name IN {{ get_guest_user_attribute('names')|where_in }}`), call
|
||||
`get_guest_user_attribute('names', escape_result=False)`. `where_in` already applies its
|
||||
own dialect-safe quoting, so escaping the values twice can corrupt them (a value such as
|
||||
`O'Brien` would come back doubly escaped and match nothing).
|
||||
|
||||
Only individual string values are escaped as SQL literals. Interpolating an entire array
|
||||
or object directly (rather than through `|where_in`, or by accessing a specific element)
|
||||
renders Python's string form of that structure, which is not valid SQL, and object keys
|
||||
are not escaped at all. Use `|where_in` for arrays, `|tojson` where you need a
|
||||
JSON-stringified value, or read individual keys/elements out of the structure yourself.
|
||||
|
||||
The same double-escaping problem described above for `|where_in` applies to `|tojson`:
|
||||
pass `escape_result=False` before piping to `|tojson` (for example
|
||||
`{{ get_guest_user_attribute('profile', escape_result=False)|tojson }}`), since JSON
|
||||
already handles its own quoting and re-escaping a value first would corrupt it (a nested
|
||||
string such as `O'Brien` would come back as the altered `O''Brien` in the serialized
|
||||
JSON).
|
||||
|
||||
:::
|
||||
|
||||
### Explicitly Including Values in Cache Key
|
||||
|
||||
The `{{ cache_key_wrapper() }}` function explicitly instructs Superset to add a value to the
|
||||
|
||||
Reference in New Issue
Block a user