From 288ec4c525f22b0cd4ed7258ab1dec37d42671f7 Mon Sep 17 00:00:00 2001 From: Trevor Nederlof Date: Fri, 11 Jul 2025 06:13:57 -0400 Subject: [PATCH] Add Posit Connect-managed service principal support to databricks(). This commit adds support for service principal credentials managed by Posit Connect alongside our existing support of viewer-based credentials. The meat of this is handled by a new function in the upcoming version of the `connectcreds` package (hence the Remote). Documentation updates are included. Co-authored-by: Aaroon Jacobs --- DESCRIPTION | 4 +++- NEWS.md | 2 ++ R/driver-databricks.R | 29 ++++++++++++++++++------- man/databricks.Rd | 11 +++++----- tests/testthat/test-driver-databricks.R | 2 +- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 17b6dfbe..1f7e7756 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -29,7 +29,7 @@ Imports: Rcpp (>= 0.12.11), rlang (>= 1.1.0) Suggests: - connectcreds, + connectcreds (>= 0.1.0.9000), covr, DBItest, httr2, @@ -90,3 +90,5 @@ Collate: 'utils.R' 'zzz.R' VignetteBuilder: knitr +Remotes: + posit-dev/connectcreds diff --git a/NEWS.md b/NEWS.md index 5d78eac5..e1a27dc6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,6 +16,8 @@ * Databricks: Fix repeated calls to `dbConnect` (#901). +* `databricks()` now detects service principal credentials when running on Posit Connect (@tnederlof, #930) + # odbc 1.6.1 * odbc will now automatically find statically built installations of diff --git a/R/driver-databricks.R b/R/driver-databricks.R index 66707283..5aa8e0aa 100644 --- a/R/driver-databricks.R +++ b/R/driver-databricks.R @@ -15,9 +15,9 @@ NULL #' model, with support for personal access tokens, OAuth machine-to-machine #' credentials, and OAuth user-to-machine credentials supplied via Posit #' Workbench or the Databricks CLI on desktop. It can also detect viewer-based -#' credentials on Posit Connect if the \pkg{connectcreds} package is -#' installed. All of these credentials are detected automatically if present -#' using [standard environment variables](https://docs.databricks.com/en/dev-tools/auth.html#environment-variables-and-fields-for-client-unified-authentication). +#' and service principal credentials on Posit Connect if the \pkg{connectcreds} +#' package is installed. All of these credentials are detected automatically if +#' present using [standard environment variables](https://docs.databricks.com/en/dev-tools/auth.html#environment-variables-and-fields-for-client-unified-authentication). #' #' In addition, on macOS platforms, the `dbConnect()` method will check #' for irregularities with how the driver is configured, @@ -49,12 +49,13 @@ NULL #' httpPath = "sql/protocolv1/o/4425955464597947/1026-023828-vn51jugj" #' ) #' -#' # Use credentials from the viewer (when possible) in a Shiny app -#' # deployed to Posit Connect. +#' # Use credentials from the viewer or a service principal (when possible) in +#' # a Shiny app deployed to Posit Connect. #' library(connectcreds) #' server <- function(input, output, session) { #' conn <- DBI::dbConnect( #' odbc::databricks(), +#' workspace = "https://example.cloud.databricks.com", #' httpPath = "sql/protocolv1/o/4425955464597947/1026-023828-vn51jugj" #' ) #' } @@ -134,9 +135,12 @@ databricks_args <- function(httpPath, if (running_on_connect()) { msg <- c( msg, - "i" = "Or consider enabling Posit Connect's Databricks integration \ - for viewer-based credentials. See {.url \ - https://docs.posit.co/connect/user/oauth-integrations/#adding-oauth-integrations-to-deployed-content} + "i" = "Or consider enabling Posit Connect's Databricks integration. \ + For viewer-based credentials. See {.url \ + https://docs.posit.co/connect/user/oauth-integrations/#viewer-oauth-integrations} + for details. \ + For service principal credentials, see {.url \ + https://docs.posit.co/connect/user/oauth-integrations/#service-account-oauth-integrations} for details." ) } @@ -227,6 +231,15 @@ databricks_auth_args <- function(host, uid = NULL, pwd = NULL) { )) } + if (is_installed("connectcreds") && connectcreds::has_service_account_token(workspace)) { + token <- connectcreds::connect_service_account_token(workspace) + return(list( + authMech = 11, + auth_flow = 0, + auth_accesstoken = token$access_token + )) + } + if (!is.null(uid) && !is.null(pwd)) { return(list(uid = uid, pwd = pwd, authMech = 3)) } else if (xor(is.null(uid), is.null(pwd))) { diff --git a/man/databricks.Rd b/man/databricks.Rd index 1eb95ddd..167395dc 100644 --- a/man/databricks.Rd +++ b/man/databricks.Rd @@ -57,9 +57,9 @@ implements a subset of the \href{https://docs.databricks.com/en/dev-tools/auth.h model, with support for personal access tokens, OAuth machine-to-machine credentials, and OAuth user-to-machine credentials supplied via Posit Workbench or the Databricks CLI on desktop. It can also detect viewer-based -credentials on Posit Connect if the \pkg{connectcreds} package is -installed. All of these credentials are detected automatically if present -using \href{https://docs.databricks.com/en/dev-tools/auth.html#environment-variables-and-fields-for-client-unified-authentication}{standard environment variables}. +and service principal credentials on Posit Connect if the \pkg{connectcreds} +package is installed. All of these credentials are detected automatically if +present using \href{https://docs.databricks.com/en/dev-tools/auth.html#environment-variables-and-fields-for-client-unified-authentication}{standard environment variables}. In addition, on macOS platforms, the \code{dbConnect()} method will check for irregularities with how the driver is configured, @@ -73,12 +73,13 @@ DBI::dbConnect( httpPath = "sql/protocolv1/o/4425955464597947/1026-023828-vn51jugj" ) -# Use credentials from the viewer (when possible) in a Shiny app -# deployed to Posit Connect. +# Use credentials from the viewer or a service principal (when possible) in +# a Shiny app deployed to Posit Connect. library(connectcreds) server <- function(input, output, session) { conn <- DBI::dbConnect( odbc::databricks(), + workspace = "https://example.cloud.databricks.com", httpPath = "sql/protocolv1/o/4425955464597947/1026-023828-vn51jugj" ) } diff --git a/tests/testthat/test-driver-databricks.R b/tests/testthat/test-driver-databricks.R index 240ec1b3..4d8980b1 100644 --- a/tests/testthat/test-driver-databricks.R +++ b/tests/testthat/test-driver-databricks.R @@ -153,7 +153,7 @@ test_that("Workbench-managed credentials are ignored for other hosts", { expect_equal(databricks_auth_args(host = "some-host"), NULL) }) -test_that("we hint viewer-based credentials on Connect", { +test_that("we hint viewer-based and service principal credentials on Connect", { local_mocked_bindings( running_on_connect = function() TRUE )