EnxDev commented on code in PR #44705:
URL: https://github.com/apache/superset/pull/44705#discussion_r4137497088


##########
superset/db_engine_specs/databricks.py:
##########
@@ -437,6 +468,13 @@ def update_params_from_encrypted_extra(
         consumed by ``Database.get_oauth2_config``; it is not a Databricks 
driver
         connection argument, so it must be stripped here to avoid poisoning the
         connection when OAuth2 is configured on the database itself.
+
+        ``connect_args`` are merged key by key, so credentials kept in the 
secure
+        extra (an access token, an OAuth M2M client secret) do not discard the
+        ``connect_args`` from ``extra`` or Superset's own (e.g. the 
User-Agent).
+        With user impersonation enabled, shared credentials are dropped: the
+        user's OAuth2 token set by ``impersonate_user`` is the only credential,
+        instead of being silently replaced by a shared one.
         """
         if not database.encrypted_extra:

Review Comment:
   This early return skips the impersonation filter whenever `encrypted_extra` 
is empty (OAuth2 from the global `DATABASE_OAUTH2_CLIENTS`, say), so an 
`auth_type` or `oauth_client_*` in `extra` still reaches the connector next to 
the user's token.
   
   What about stripping the `extra` side in `impersonate_user` instead? It 
always runs when impersonating, drops the `key == "access_token"` special case, 
and a test with impersonation on and no `encrypted_extra` would pin it.



##########
superset/db_engine_specs/databricks.py:
##########
@@ -335,7 +352,21 @@ def needs_oauth2(cls, ex: Exception) -> bool:
         if isinstance(ex, cls.oauth2_exception):
             return True
         message = str(ex).lower()
-        return any(signal in message for signal in 
cls.oauth2_auth_failure_signals)
+        if any(signal in message for signal in 
cls.oauth2_auth_failure_signals):
+            return True
+        # A rejected bearer token fails the request with HTTP 401 and a message
+        # such as "Credential was not sent or was of an unsupported type for 
this
+        # API", which no signal above matches; the connector reports the status
+        # in ``RequestError.context["http-code"]``. 403 is left out on 
purpose: it
+        # also means a missing permission, which re-authorizing cannot fix.
+        error = getattr(ex, "orig", None) or ex
+        context = getattr(error, "context", None)
+        if isinstance(context, dict):
+            try:
+                return int(context.get("http-code") or 0) == 401

Review Comment:
   `_handle_oauth2_error` and `check_for_oauth2` start the dance whenever 
OAuth2 is enabled, without looking at `impersonate_user`. So on a 
non-impersonating database with a Databricks entry in 
`DATABASE_OAUTH2_CLIENTS`, a revoked shared token would send every user through 
an authorize prompt that can't fix it, and hide the error an admin needs to see.
   
   Might be misreading which failures come back as 401 there, but is it worth 
only treating a 401 as OAuth2 when the database impersonates?



-- 
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