-
Notifications
You must be signed in to change notification settings - Fork 154
[DERCBOT-1691] Support GSA Impersonation #1950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -31,7 +31,9 @@ import com.google.api.client.json.jackson2.JacksonFactory | |||||
| import com.google.api.services.chat.v1.HangoutsChat | ||||||
| import com.google.auth.http.HttpCredentialsAdapter | ||||||
| import com.google.auth.oauth2.GoogleCredentials | ||||||
| import com.google.auth.oauth2.ImpersonatedCredentials | ||||||
| import com.google.auth.oauth2.ServiceAccountCredentials | ||||||
| import mu.KotlinLogging | ||||||
| import java.io.ByteArrayInputStream | ||||||
| import java.io.InputStream | ||||||
| import kotlin.reflect.KClass | ||||||
|
|
@@ -41,23 +43,36 @@ private const val SERVICE_CREDENTIAL_PATH_PARAMETER = "serviceCredentialPath" | |||||
| private const val SERVICE_CREDENTIAL_CONTENT_PARAMETER = "serviceCredentialContent" | ||||||
| private const val BOT_PROJECT_NUMBER_PARAMETER = "botProjectNumber" | ||||||
| private const val CONDENSED_FOOTNOTES_PARAMETER = "useCondensedFootnotes" | ||||||
| private const val GSA_TO_IMPERSONATE_PARAMETER = "gsaToImpersonate" | ||||||
|
|
||||||
| internal object GoogleChatConnectorProvider : ConnectorProvider { | ||||||
|
|
||||||
| private val logger = KotlinLogging.logger {} | ||||||
|
|
||||||
| override val connectorType: ConnectorType get() = googleChatConnectorType | ||||||
|
|
||||||
| override fun connector(connectorConfiguration: ConnectorConfiguration): Connector { | ||||||
| with(connectorConfiguration) { | ||||||
|
|
||||||
| val credentialInputStream = | ||||||
| connectorConfiguration.parameters[SERVICE_CREDENTIAL_PATH_PARAMETER] | ||||||
| ?.let { resourceAsStream(it) } | ||||||
| ?: connectorConfiguration.parameters[SERVICE_CREDENTIAL_CONTENT_PARAMETER] | ||||||
| ?.let { ByteArrayInputStream(it.toByteArray()) } | ||||||
| ?: error("Service credential missing : either $SERVICE_CREDENTIAL_PATH_PARAMETER or $SERVICE_CREDENTIAL_CONTENT_PARAMETER must be provided") | ||||||
| val gsaToImpersonate = connectorConfiguration.parameters[GSA_TO_IMPERSONATE_PARAMETER] | ||||||
|
|
||||||
| val credentials: GoogleCredentials = if (gsaToImpersonate.isNullOrBlank()) { | ||||||
| logger.info { "Using classic authentication mode with JSON credentials" } | ||||||
| val credentialInputStream = getCredentialInputStream(connectorConfiguration) | ||||||
| loadCredentials(credentialInputStream) | ||||||
| } else { | ||||||
| logger.info { "Using impersonation mode with GSA: $gsaToImpersonate" } | ||||||
|
||||||
| logger.info { "Using impersonation mode with GSA: $gsaToImpersonate" } | |
| logger.info { "Using impersonation mode with GSA domain: ${gsaToImpersonate.substringAfter('@')}" } |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging the source service account email could expose sensitive configuration information. Consider removing this log statement or redacting the email address.
| logger.info { "Source credentials: ${(sourceCredentials as? ServiceAccountCredentials)?.clientEmail}" } |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging the target service account email could expose sensitive configuration information. Consider removing this log statement or redacting the email address.
| logger.info { "Impersonating target GSA = $targetServiceAccount with scopes = $CHAT_SCOPE" } | |
| logger.info { "Impersonating target GSA with scopes = $CHAT_SCOPE" } |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardcoded lifetime value of 3600 seconds (1 hour) should be extracted to a named constant for better maintainability. Consider adding private const val IMPERSONATION_TOKEN_LIFETIME_SECONDS = 3600 at the top of the file alongside other constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use a property to make it configurable
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging the service account email could expose sensitive configuration information. Consider removing this log statement or redacting the email address.
| logger.info { "Loaded explicit service account: ${(creds as ServiceAccountCredentials).clientEmail}" } |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The catch block handles all exceptions generically with catch (e: Exception), which might hide configuration errors (e.g., invalid JSON format, missing files). Consider catching only specific exceptions related to missing credentials (e.g., FileNotFoundException, IOException) and let other exceptions propagate with more context. This will help distinguish between "credentials not provided" vs "credentials provided but invalid".
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description "Service account email to impersonate (if provided, priority over JSON credentials)" is misleading. Impersonation doesn't replace JSON credentials; it uses them (or ADC) as the source for impersonation. Consider revising to: "Service account email to impersonate (optional, uses JSON credentials or ADC as source)" to clarify that both can work together.
| "Service account email to impersonate (if provided, priority over JSON credentials)", | |
| "Service account email to impersonate (optional, uses JSON credentials or ADC as source)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging the complete message content with
message=${message.toGoogleMessage()}could inadvertently log sensitive user data or PII. Consider logging only metadata (space, thread) or use a sanitized representation of the message.