Token federation: `_exchange_token` raises KeyError('access_token') on error responses, discarding the real failure reason

オープン 初心者向け
#904 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
76/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
静か
技術スタック
python

調査の方向性

src/databricks/sql/auth/token_federation.py の 191~194 行付近にある _exchange_token から始め、次に 148 行付近の handler と、src/databricks/sql/auth/auth.py:68 にあるそれをラップするエントリポイントを追跡します。OAuth エラーボディを返す exchange を再現し、トークンをログに記録せずに warning がエンドポイントのエラー理由を示すことを確認します。その間、外部トークンへのフォールバックは変更されないままにします。

索引モデルが issue の本文から書いたものです。

説明

Summary

When token exchange fails, _exchange_token raises KeyError: 'access_token' instead of surfacing the error the endpoint actually returned. The caller catches it and logs the KeyError, so the log line reports the name of a missing dict key rather than why the exchange was rejected:

Token exchange failed, using external token: 'access_token'

There is no way to tell from that whether the exchange was misconfigured, unauthorized, or unsupported.

Versions

Reproduced on databricks-sql-connector==4.3.0. The relevant code is byte-identical in v4.4.0 and on main today, so this is not fixed in a later release.

Where

src/databricks/sql/auth/token_federation.py on main:

191:        token_response = json.loads(response.data.decode())
192:
193:        return Token(
194:            token_response["access_token"], token_response.get("token_type", "Bearer")
195:        )

token_type is read defensively with .get(); access_token is not. When the endpoint returns an OAuth error body ({"error": ..., "error_description": ...}) rather than a token, line 194 raises KeyError.

That propagates to the handler at line 148:

147:            except Exception as e:
148:                logger.warning("Token exchange failed, using external token: %s", e)

str(KeyError("access_token")) renders as 'access_token', which is what reaches the log. The error and error_description from the response body are never read and are lost.

Reproduction

  1. Connect using an OAuth access token issued by an identity provider whose iss host differs from the workspace host — for example an Microsoft Entra ID token for the Azure Databricks resource (2ff814a6-3304-4ab8-85cb-cd0e6f879c1d).
  2. TokenFederationProvider wraps every provider unconditionally (src/databricks/sql/auth/auth.py:68, "Always wrap with token federation"), and _should_exchange_token returns True because the issuer host does not match the workspace host, so an exchange is always attempted.
  3. Against a workspace where that exchange is not accepted, every connection logs the message above.

Functionally this is harmless — the fallback to the external token works correctly and queries succeed. The problem is purely diagnostic: the warning fires on every connection and gives no actionable information.

Suggested fix

Read the response defensively and raise something that names the actual failure, without logging the token itself:

token_response = json.loads(response.data.decode())

if "access_token" not in token_response:
    error = token_response.get("error", "unknown_error")
    description = token_response.get("error_description", "")
    raise RuntimeError(f"Token exchange rejected by {token_url}: {error} {description}".strip())

return Token(token_response["access_token"], token_response.get("token_type", "Bearer"))

The existing except Exception at line 147 would then log the endpoint's own reason, and the graceful fallback behaviour is unchanged.

A non-JSON or non-2xx response would also currently surface as a confusing JSONDecodeError; checking the status code before parsing would cover that case too.

主要言語
Python
スター
233
フォーク
152
平均マージ
21時間 5分
マージ済み PR(30日)
10

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

databricks/databricks-sql-python のほかの issue

databricks/databricks-sql-python の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。