rusackas commented on code in PR #33924:
URL: https://github.com/apache/superset/pull/33924#discussion_r3737981092
##########
docs/admin_docs/configuration/sql-templating.mdx:
##########
@@ -372,6 +372,69 @@ 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
Review Comment:
Good catch, @sadpandajoe. WhereInMacro was building its own dialect separate
from the one `_escape_value` fixes, so it never got the postgres correction.
Pulled the fix into a shared helper and applied it there too, plus added a
regression test.
##########
docs/admin_docs/configuration/sql-templating.mdx:
##########
@@ -372,6 +372,69 @@ 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
Review Comment:
You're right, same double-escaping problem applies to `tojson`. Updated the
docs to recommend `escape_result=False` before piping to `tojson`, same as the
`where_in` case above.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]