hughhhh commented on code in PR #45890:
URL: https://github.com/apache/superset/pull/45890#discussion_r4447465506
##########
superset/commands/dataset/export.py:
##########
@@ -137,6 +173,12 @@ def _export(
)
payload["ssh_tunnel"] =
mask_password_info(ssh_tunnel_payload)
+ if carried := _carried_secure_extra(
+ model.database.masked_encrypted_extra
+ ):
+ payload["masked_encrypted_extra"] = carried
+ payload["masked_encrypted_extra_partial"] = True
Review Comment:
> [!NOTE]
> 🤖 **Claude Opus 5.5 responding on behalf of Hugh (hughhhh)**
Added in 8e0061d3a5, and on #45870 in 104eeeaf31.
`test_bundle_overwrite_import_keeps_what_the_bundle_does_not_carry` exports a
bundle, asserts the flag in its `databases/*.yaml`, then runs that file through
`ImportV1DatabaseSchema(overwrites_existing=True)` and
`import_database(overwrite=True)`. It checks that a stored `auth_params`
survives and the secrets are revealed. Deleting the export line now fails it.
It calls those two directly, not `ImportDashboardsCommand` with
`overwrite_all`, which reaches the same `import_database` call.
##########
docs/docs/using-superset/embedding.mdx:
##########
@@ -172,6 +172,164 @@ When enabled, the **Logout** menu item is removed from
the user avatar dropdown
Must be `True` to enable the embedded SDK and the guest token endpoint.
Without this flag, `embedDashboard` will fail to load.
+### `EMBEDDED_CREDENTIAL_FALLBACK`
+
+Allows a database connection that authenticates logged-in users per-user via
OAuth2 to
+also carry a single Snowflake username with either a password or a PEM key
pair, used
+**only** for embedded guest requests.
+
+This exists because the two authentication models do not meet. An embedded
viewer signs
+in with a guest token rather than a Superset account, so there is no per-user
OAuth2
+token to resolve for them — and an external viewer may have no identity on the
+analytical database at all. Without a fallback, embedded dashboards on a
per-user OAuth2
+connection cannot run queries.
+
+```python
+# superset_config.py
+FEATURE_FLAGS = {
+ "EMBEDDED_SUPERSET": True,
+ "EMBEDDED_CREDENTIAL_FALLBACK": True,
+}
+```
+
+With both flags on, engines that support it (currently Snowflake) show an
**Embedded
+guest credentials** section on the **Basic** tab of the connection dialog. The
section
+is editable only when the connection has an OAuth2 client and **Impersonate
logged in
+user** is on; otherwise it is disabled and states what is missing.
+
+#### Before turning the flag on
+
+Turning the flag on stops embedded dashboards on some existing connections from
+loading for embedded viewers. A Snowflake connection with **Impersonate logged
in
+user** on but no OAuth2 client (none in its **OAuth2 client information** and
no
+`DATABASE_OAUTH2_CLIENTS` entry for Snowflake) served embedded viewers under
its base
+account, because impersonation without OAuth2 never changed the Snowflake
login. With
+the flag on, Superset refuses those viewers rather than serve them under an
identity
+nobody chose for them. The viewer sees *This chart can't be shown here because
its
+database connection isn't set up for embedded dashboards*, and the server log
has a
+`Refused an embedded viewer's query on database connection ...` warning naming
the
+connection and the fix. With `GLOBAL_ASYNC_QUERIES` on, the viewer sees the
generic
+*An error occurred while fetching the data.* instead, and the warning is the
same.
+Logged-in users are not affected.
+
+Update each such connection before turning the flag on, in one of two ways:
+
+- **Keep serving embedded viewers under the base account:** on the
**Advanced** tab,
+ under **Security**, turn off **Impersonate logged in user**. On a connection
with no
+ OAuth2 client this changes nothing for logged-in users, who were already on
the
+ base account.
+- **Serve embedded viewers under a dedicated account:** configure an OAuth2
client and
+ **Embedded guest credentials** as described below. Logged-in users then sign
in to
+ Snowflake individually through OAuth2.
+
+#### Setting up the credential
+
+1. Enable `EMBEDDED_SUPERSET` and `EMBEDDED_CREDENTIAL_FALLBACK` (above).
+2. Open the Snowflake connection for editing. On the **Basic** tab, expand
**OAuth2
+ client information** and enter the client ID, client secret, authorization
and token
+ request URIs, and scope. Alternatively, configure a deployment-wide client
for
+ Snowflake in `DATABASE_OAUTH2_CLIENTS`.
+3. On the **Advanced** tab, under **Security**, turn on **Impersonate logged
in user**.
+ On a new connection this option appears only after you connect, so connect
first and
+ then edit the connection.
+4. Back on the **Basic** tab, expand **Embedded guest credentials**, enter the
Snowflake
+ username, choose **Password** or **Key pair**, and fill in the secret.
+5. Save. The section header shows **Configured** once a credential is stored.
+
+Configure the Snowflake OAuth2 scopes explicitly to match your integration. For
+example, `session:role:ANALYST refresh_token` selects the `ANALYST` role and
requests a
+refresh token. Omitting a role scope uses the user's default role; the dialog
does not
+prefill a scope or require a specific role scope.
+
+For key-pair authentication, enter the Snowflake username, its PEM private
key, and an
+optional passphrase; register the corresponding public key with that Snowflake
user. The
+credential is stored encrypted in the connection's *Secure Extra* under
+`embedded_credentials`. Passwords, private keys, and passphrases are masked on
read,
+while the username stays visible so an administrator can see which database
user
+embedded queries run as.
+
+The credential must be complete: a username with no password or private key,
or the
+reverse, is rejected when both embedding flags are enabled. A whitespace-only
username
+is invalid. Validation uses the engine's credential rules and rejects
malformed JSON
+or non-object credential values. It checks the edited credential, so an
incomplete
+imported credential can be completed or cleared.
+
+To remove the credential, expand **Embedded guest credentials**, click
**Remove embedded
+guest credentials** (or clear every field), and save. This deletes the
+`embedded_credentials` key from *Secure Extra*. Removal stays available while
the section
+is otherwise disabled.
+
+#### Requirements and limitations
+
+- Both `EMBEDDED_SUPERSET` and `EMBEDDED_CREDENTIAL_FALLBACK` must be enabled.
While
+ either is off, a stored credential is preserved, unused, and does not block
unrelated
+ edits.
+- The connection needs an OAuth2 client — per-connection **OAuth2 client
information**
+ or a deployment-wide `DATABASE_OAUTH2_CLIENTS` entry — and **Impersonate
logged in
+ user** must be on. Superset refuses to save a credential otherwise, and it
never
+ applies to a connection without OAuth2.
+- Embedded viewers run with the embedded account's **default Snowflake role**.
The
+ connection's configured role and authenticator are not used for guest
connections.
+- The embedded account needs `USAGE` on the connection's warehouse.
+- Supported secrets are a password, a Snowflake programmatic access token
entered as the
+ password, or a key pair (PEM private key with an optional passphrase).
+- Alerts, reports, connection tests, and logged-in users never use the
credential; they
+ keep using the connection's own credential or their per-user OAuth2 token.
+- **Async queries run logged-in users as the base account.** With
+ `GLOBAL_ASYNC_QUERIES` on, guest queries use the same fallback credential as
+ synchronous guest queries. Logged-in users' chart queries on a Snowflake
OAuth2
+ connection, however, run in the async worker under the connection's own base
+ credential instead of the user's OAuth2 token, so Snowflake grants and row
access
+ policies keyed to the user do not apply and the queries are attributed to
the base
+ account. This predates `EMBEDDED_CREDENTIAL_FALLBACK`, and the flag does not
change
+ it. Leave `GLOBAL_ASYNC_QUERIES` off on deployments that depend on per-user
OAuth2.
+- **Turn on Per user caching on OAuth2 connections.** Guest results always get
their
+ own cache partition (below), but logged-in users do not unless **Per user
caching**
+ (**Advanced** → **Security**) is on, or the `CACHE_IMPERSONATION` or
+ `CACHE_QUERY_BY_USER` feature flag is enabled. Without one of them,
logged-in users
+ share one cache entry per query, so a user can be shown a result fetched
under
+ another user's OAuth2 identity, including rows their own Snowflake policies
would
+ hide, until the entry expires.
+- **Connections created in SQLAlchemy URI mode** show neither the **OAuth2
client
+ information** nor the **Embedded guest credentials** section, and an existing
+ connection cannot be switched to the dynamic form while editing. For such a
+ connection, set `oauth2_client_info` and `embedded_credentials` directly in
+ **Secure extra** (**Advanced** → **Security**), or configure a
deployment-wide
+ client in `DATABASE_OAUTH2_CLIENTS`.
+- **Turning off Impersonate logged in user moves embedded viewers onto the base
+ account.** The credential applies only while impersonation is on. With it
off,
+ embedded viewers query under the connection's own credential, and so do
logged-in
+ users, who also stop signing in through OAuth2. A save with impersonation
off is
Review Comment:
> [!NOTE]
> 🤖 **Claude Opus 5.5 responding on behalf of Hugh (hughhhh)**
I limited the docs rather than changing the update path, in 8e0061d3a5. The
paragraph now says the connection dialog refuses that save, and that a `PUT`
sending only `impersonate_user: false` is accepted and leaves the credential
stored but unused until impersonation is back on. Running the check on that
`PUT` would make an impersonation change depend on Secure Extra for API
clients, so I'd treat it as a separate change. Tell me if you'd rather have it
here.
--
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]