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]

Reply via email to