|
21 | 21 | ``oauth_client_id`` / ``oauth_redirect_port`` overriding it) is |
22 | 22 | forwarded to the kernel's ``auth_type='oauth-u2m'`` and the kernel |
23 | 23 | runs the browser flow itself. |
24 | | -- **Azure Entra (Azure AD)** — both Azure auth types route to the |
25 | | - kernel's *generic* OAuth flows with Azure values as overrides (the |
26 | | - kernel needs no Azure-specific code): |
27 | | -
|
28 | | - - ``azure-oauth`` (U2M) → ``oauth-u2m`` with the Azure app client id |
29 | | - (``96eecda7-…``), redirect port ``8030``, and the AAD delegated scope |
30 | | - ``{app_id}/user_impersonation offline_access`` (via |
31 | | - ``AzureOAuthEndpointCollection``, honoring ``DATABRICKS_AZURE_TENANT_ID``). |
32 | | - The kernel discovers endpoints via the workspace ``/oidc`` redirector, |
33 | | - which an Azure workspace redirects to Entra (PECOBLR-4120). |
34 | | - - ``azure-sp-m2m`` (M2M) → ``oauth-m2m`` with the Azure service-principal |
35 | | - credentials, an Entra v2.0 ``token_url``, and the |
36 | | - ``{effective_app_id}/.default`` scope (PECOBLR-4141). ``azure_tenant_id`` |
37 | | - is required (the kernel path does not auto-discover it). The Azure |
38 | | - management-token header and ``azure_workspace_resource_id`` are **not** |
39 | | - applied on the kernel path — no SQL connector uses them; an SP that is |
40 | | - not a workspace member (RBAC-only) is unsupported here. |
| 24 | +- **Azure Entra (Azure AD)** — both Azure auth types forward the selector |
| 25 | + and Azure credentials to the KERNEL, which is the Azure-aware auth core |
| 26 | + (it owns the endpoints, scopes, app ids, and tenant discovery). The |
| 27 | + binding stays thin — it does not construct endpoints or scopes: |
| 28 | +
|
| 29 | + - ``azure-oauth`` (U2M) → forward ``auth_type='azure-oauth'`` (plus any |
| 30 | + optional ``oauth_client_id`` / ``oauth_redirect_port`` passthrough). The |
| 31 | + kernel pins the workspace v2.0 authorize/token endpoints, the Azure app |
| 32 | + client id (``96eecda7-…``), port ``8030``, and the |
| 33 | + ``{app_id}/user_impersonation offline_access`` scope (PECOBLR-4120). |
| 34 | + - ``azure-sp-m2m`` (M2M) → forward ``auth_type='azure-sp-m2m'`` with the |
| 35 | + Azure service-principal ``azure_client_id`` / ``azure_client_secret``. |
| 36 | + The kernel builds the Entra v2.0 token endpoint and the |
| 37 | + ``{effective_app_id}/.default`` scope, and auto-discovers the tenant from |
| 38 | + the workspace's ``/aad/auth`` redirect when ``azure_tenant_id`` is omitted |
| 39 | + (Thrift parity). ``azure_workspace_resource_id`` is an optional add-on: |
| 40 | + forward it and the kernel additionally sends the Azure management-token |
| 41 | + header pair, so an RBAC-only SP (not a workspace member) can authenticate |
| 42 | + (PECOBLR-4141). |
41 | 43 |
|
42 | 44 | ``identity_federation_client_id`` is forwarded with whichever auth shape |
43 | 45 | wins resolution. It selects mandatory SP-wide workload-identity token |
|
72 | 74 | PYSQL_OAUTH_SCOPES, |
73 | 75 | ) |
74 | 76 | from databricks.sql.auth.authenticators import AccessTokenAuthProvider, AuthProvider |
75 | | -from databricks.sql.auth.common import get_effective_azure_login_app_id |
76 | 77 | from databricks.sql.auth.token_federation import TokenFederationProvider |
77 | 78 | from databricks.sql.exc import NotSupportedError, ProgrammingError |
78 | 79 |
|
79 | | -# Entra (Azure AD) v2.0 token endpoint template. The kernel's generic M2M |
80 | | -# provider sends the credentials as ``scope`` (v2.0), so we point it at the |
81 | | -# v2.0 endpoint (the connector's own SP path uses the v1.0 ``resource`` form). |
82 | | -_AZURE_AAD_LOGIN_HOST = "https://login.microsoftonline.com" |
83 | | - |
84 | 80 | logger = logging.getLogger(__name__) |
85 | 81 |
|
86 | 82 |
|
@@ -175,7 +171,7 @@ def kernel_auth_kwargs( |
175 | 171 | ``oauth_client_secret`` together. |
176 | 172 |
|
177 | 173 | (The Azure Entra auth types — ``azure-oauth`` and ``azure-sp-m2m`` — |
178 | | - are routed to the kernel's generic OAuth flows up front, before these |
| 174 | + are forwarded to the kernel's Azure-aware flows up front, before these |
179 | 175 | guards; see the module docstring.) |
180 | 176 | 1. **OAuth M2M** — ``oauth_client_id`` + ``oauth_client_secret`` |
181 | 177 | both present → forward raw creds to the kernel's ``oauth-m2m``. |
@@ -234,51 +230,42 @@ def kernel_auth_kwargs( |
234 | 230 | kwargs["identity_federation_client_id"] = federation_client_id |
235 | 231 | return kwargs |
236 | 232 |
|
237 | | - # azure-sp-m2m (Azure service principal, client-credentials): forward to |
238 | | - # oauth-m2m with the Azure app credentials, an Entra v2.0 token endpoint, |
239 | | - # and the {effective_app_id}/.default scope. The kernel sends the client |
240 | | - # secret via HTTP Basic (which Entra v2.0 accepts) and, because a |
241 | | - # token_url override is set, skips workspace OIDC discovery. PECOBLR-4141. |
| 233 | + # azure-sp-m2m (Azure service principal, client-credentials): forward the |
| 234 | + # selector + Azure SP credentials; the KERNEL owns Azure resolution (it is |
| 235 | + # the auth core). The kernel builds the Entra v2.0 token endpoint |
| 236 | + # (`{login}/{tenant}/oauth2/v2.0/token`) and the `{effective_app_id}/.default` |
| 237 | + # scope, and — when azure_tenant_id is omitted — auto-discovers the tenant |
| 238 | + # from the workspace's /aad/auth redirect, matching the Thrift backend |
| 239 | + # (so connect() is byte-identical between Thrift and use_kernel=True). |
| 240 | + # PECOBLR-4141. |
242 | 241 | # |
243 | | - # NOT applied on the kernel path: the Azure management-token header |
244 | | - # (X-Databricks-Azure-SP-Management-Token) and azure_workspace_resource_id. |
245 | | - # No SQL connector (Go, Node) uses them; the Databricks-audience token |
246 | | - # authenticates SPs that are workspace principals (the SQL norm). An SP with |
247 | | - # only an Azure RBAC role (not a workspace member) is unsupported here. |
| 242 | + # azure_workspace_resource_id is an optional add-on: forward it and the |
| 243 | + # kernel additionally fetches an Azure-management token and sends the |
| 244 | + # X-Databricks-Azure-SP-Management-Token + X-Databricks-Azure-Workspace- |
| 245 | + # Resource-Id pair, so an SP that holds only an Azure RBAC role (not a |
| 246 | + # workspace member) can authenticate. Omit it (the common case) and the SP |
| 247 | + # authenticates with the Databricks-audience data token alone. |
248 | 248 | if auth_type == "azure-sp-m2m": |
249 | 249 | azure_client_id = opts.get("azure_client_id") |
250 | 250 | azure_client_secret = opts.get("azure_client_secret") |
251 | | - azure_tenant_id = opts.get("azure_tenant_id") |
252 | 251 | if not (azure_client_id and azure_client_secret): |
253 | 252 | raise ProgrammingError( |
254 | 253 | "auth_type='azure-sp-m2m' requires azure_client_id and " |
255 | 254 | "azure_client_secret." |
256 | 255 | ) |
257 | | - if not azure_tenant_id: |
258 | | - # The Thrift path auto-discovers the tenant from the workspace's |
259 | | - # /aad/auth redirect; the kernel path does not make that call, so |
260 | | - # require it explicitly rather than silently guessing. |
261 | | - raise NotSupportedError( |
262 | | - "use_kernel=True auth_type='azure-sp-m2m' requires an explicit " |
263 | | - "azure_tenant_id (the kernel path does not auto-discover the " |
264 | | - "Azure tenant from the workspace as the Thrift backend does)." |
265 | | - ) |
266 | | - if opts.get("azure_workspace_resource_id"): |
267 | | - logger.warning( |
268 | | - "azure_workspace_resource_id is ignored on use_kernel=True: the " |
269 | | - "Azure management-token flow (X-Databricks-Azure-SP-Management-" |
270 | | - "Token) is not applied on the kernel path. The Databricks-" |
271 | | - "audience token authenticates service principals that are " |
272 | | - "workspace principals; an RBAC-only SP is unsupported here." |
273 | | - ) |
274 | | - app_id = get_effective_azure_login_app_id(hostname or "") |
275 | 256 | kwargs = { |
276 | | - "auth_type": "oauth-m2m", |
277 | | - "client_id": azure_client_id, |
278 | | - "client_secret": azure_client_secret, |
279 | | - "token_url": f"{_AZURE_AAD_LOGIN_HOST}/{azure_tenant_id}/oauth2/v2.0/token", |
280 | | - "oauth_scopes": [f"{app_id}/.default"], |
| 257 | + "auth_type": "azure-sp-m2m", |
| 258 | + "azure_client_id": azure_client_id, |
| 259 | + "azure_client_secret": azure_client_secret, |
281 | 260 | } |
| 261 | + # Optional passthroughs: the kernel auto-discovers the tenant when |
| 262 | + # absent, and sends the data token alone when no resource id is set. |
| 263 | + azure_tenant_id = opts.get("azure_tenant_id") |
| 264 | + if azure_tenant_id: |
| 265 | + kwargs["azure_tenant_id"] = azure_tenant_id |
| 266 | + azure_workspace_resource_id = opts.get("azure_workspace_resource_id") |
| 267 | + if azure_workspace_resource_id: |
| 268 | + kwargs["azure_workspace_resource_id"] = azure_workspace_resource_id |
282 | 269 | if federation_client_id: |
283 | 270 | kwargs["identity_federation_client_id"] = federation_client_id |
284 | 271 | return kwargs |
|
0 commit comments