Skip to content

Commit b316568

Browse files
Feat: Switching HTTP request library for FetchIAPToken (#1699)
Switches HTTP request library from HttpClient to HttpURLConnection. Improves error message handling Login error with no IAP credentials provided. ``` Please check your Looker API client_id and client_secret. Underlying Error: POST /api/4.0/login error_body: ``` Login error with IAP credentials provided ``` Please ensure your Identity-Aware Proxy credentials and your Looker credentials are correct Proxy layer OR at Looker's internal API layer. Underlying Error: POST /api/4.0/login error_body: ``` --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 6468b1f commit b316568

2 files changed

Lines changed: 61 additions & 37 deletions

File tree

kotlin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ val googleHttpVersion = providers.gradleProperty("googleHttpVersion").get()
77
plugins {
88
kotlin("jvm")
99
id("com.diffplug.spotless")
10-
id("com.github.johnrengelman.shadow") version "8.1.1"
10+
id("com.github.johnrengelman.shadow")
1111
}
1212

1313
sourceSets {

kotlin/src/main/com/looker/rtl/AuthSession.kt

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@ package com.looker.rtl
2727
import com.google.api.client.http.UrlEncodedContent
2828
import com.google.auth.oauth2.GoogleCredentials
2929
import com.google.gson.JsonParser
30-
import java.net.URI
31-
import java.net.http.HttpClient
32-
import java.net.http.HttpRequest
33-
import java.net.http.HttpResponse
34-
import java.time.Duration
3530
import java.time.LocalDateTime
3631

3732
open class AuthSession(
@@ -89,10 +84,6 @@ open class AuthSession(
8984
return init.copy(headers = headers)
9085
}
9186

92-
private val httpClient: HttpClient = HttpClient.newBuilder()
93-
.connectTimeout(Duration.ofSeconds(5))
94-
.build()
95-
9687
private val googleCreds by lazy {
9788
GoogleCredentials.getApplicationDefault()
9889
.createScoped(listOf("https://www.googleapis.com/auth/cloud-platform"))
@@ -126,32 +117,54 @@ open class AuthSession(
126117
val encodedServiceAccount = java.net.URLEncoder.encode(serviceAccount, java.nio.charset.StandardCharsets.UTF_8)
127118
val apiUrl = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$encodedServiceAccount:generateIdToken"
128119

120+
val includeEmail = true
121+
val requestMethod = "POST"
122+
val connectTimeout = 5000
123+
val readTimeout = 5000
124+
val doOutput = true
125+
129126
val jsonBody = com.google.gson.JsonObject().apply {
130127
addProperty("audience", audience)
131-
addProperty("includeEmail", true)
128+
addProperty("includeEmail", includeEmail)
132129
}.toString()
133130

134-
val iapRequest = HttpRequest.newBuilder()
135-
.uri(URI.create(apiUrl))
136-
.header("Authorization", "Bearer $accessToken")
137-
.header("Content-Type", "application/json")
138-
.timeout(Duration.ofSeconds(5))
139-
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
140-
.build()
131+
val url = java.net.URL(apiUrl)
132+
val connection = url.openConnection() as java.net.HttpURLConnection
141133

142-
val iapResponse = httpClient.send(iapRequest, HttpResponse.BodyHandlers.ofString())
134+
try {
135+
connection.requestMethod = requestMethod
136+
connection.setRequestProperty("Authorization", "Bearer $accessToken")
137+
connection.setRequestProperty("Content-Type", "application/json")
138+
connection.connectTimeout = connectTimeout
139+
connection.readTimeout = readTimeout
140+
connection.doOutput = doOutput
141+
142+
connection.outputStream.use { os ->
143+
val input = jsonBody.toByteArray(Charsets.UTF_8)
144+
os.write(input, 0, input.size)
145+
}
143146

144-
if (iapResponse.statusCode() != 200) {
145-
throw RuntimeException("IAM API Error: ${iapResponse.statusCode()} - ${iapResponse.body()}")
146-
}
147+
val statusCode = connection.responseCode
148+
val responseBody = if (statusCode == 200) {
149+
connection.inputStream.bufferedReader().use { it.readText() }
150+
} else {
151+
connection.errorStream?.bufferedReader()?.use { it.readText() } ?: ""
152+
}
147153

148-
val iapJsonObject = JsonParser.parseString(iapResponse.body()).asJsonObject
149-
val token = iapJsonObject.get("token")?.asString
150-
?: throw RuntimeException("Could not find token in IAM JSON response")
154+
if (statusCode != 200) {
155+
throw RuntimeException("IAM API Error: $statusCode - $responseBody")
156+
}
157+
158+
val iapJsonObject = JsonParser.parseString(responseBody).asJsonObject
159+
val token = iapJsonObject.get("token")?.asString
160+
?: throw RuntimeException("Could not find token in IAM JSON response")
151161

152-
cachedIapToken = token
153-
iapTokenExpiration = LocalDateTime.now().plusMinutes(IAP_TOKEN_CACHE_MINUTES)
154-
token
162+
cachedIapToken = token
163+
iapTokenExpiration = LocalDateTime.now().plusMinutes(IAP_TOKEN_CACHE_MINUTES)
164+
token
165+
} finally {
166+
connection.disconnect()
167+
}
155168
} catch (e: Exception) {
156169
cachedIapToken = null
157170
iapTokenExpiration = null
@@ -238,9 +251,9 @@ open class AuthSession(
238251
val params = mapOf(client_id to clientId, client_secret to clientSecret)
239252
val body = UrlEncodedContent(params)
240253

241-
val iapToken = fetchIapToken()
242-
243254
try {
255+
val iapToken = fetchIapToken()
256+
244257
val token = ok<AuthToken>(
245258
transport.request<AuthToken>(
246259
HttpMethod.POST,
@@ -256,15 +269,26 @@ open class AuthSession(
256269
},
257270
)
258271
authToken = token
259-
} catch (e: Exception) {
260-
val isUsingIap = !config["iap_client_id"].isNullOrBlank() || !config["iap_service_account_email"].isNullOrBlank()
261-
262-
val errorMessage = if (isUsingIap) {
263-
"Authentication failed during login. \nPlease check your iap_client_id and iap_service_account_email fields, as well as your Looker credentials.\nDetails: ${e.message}"
272+
} catch (e: Throwable) {
273+
val config = apiSettings.readConfig()
274+
val isUsingIap =
275+
!config["iap_client_id"].isNullOrBlank() || !config["iap_service_account_email"].isNullOrBlank()
276+
277+
if (isUsingIap) {
278+
throw RuntimeException(
279+
"""Please ensure your Identity-Aware Proxy credentials and your Looker credentials are correct.
280+
| Underlying Error: ${e.message}
281+
""".trimMargin(),
282+
e,
283+
)
264284
} else {
265-
"Authentication failed during login. \nPlease check your Looker client_id and client_secret.\nDetails: ${e.message}"
285+
throw RuntimeException(
286+
"""Please check your Looker API client_id and client_secret.
287+
| Underlying Error: ${e.message}
288+
""".trimMargin(),
289+
e,
290+
)
266291
}
267-
throw RuntimeException(errorMessage, e)
268292
}
269293
}
270294

0 commit comments

Comments
 (0)