谷歌云函数使用服务帐号域范围访问调用 Gmail API

huangapple go评论117阅读模式
英文:

Google Cloud Function Calling Gmail API Using Service Account Domain-Wide Access

问题

// 包 p 包含一个 HTTP 云函数。
package p

import (
"log"
"fmt"
"net/http"
"context"
"google.golang.org/api/gmail/v1"
)

func HelloWorld(wx http.ResponseWriter, rx *http.Request) {
log.Println("开始")

srv, err := gmail.NewService(context.Background())
if err != nil {
	log.Fatalf("无法获取 Gmail 客户端:%v", err)
}

user := "me"
r, err := srv.Users.Labels.List(user).Do()
if err != nil {
	log.Fatalf("无法获取标签:%v", err)
}
if len(r.Labels) == 0 {
	fmt.Println("未找到标签。")
	return
}
fmt.Println("标签:")
for _, l := range r.Labels {
	fmt.Printf("- %s\n", l.Name)
}

log.Println("结束")

}

我正在使用 Go 编写一个 Google Cloud 函数,需要访问拥有该项目、Gmail 账户和创建云函数的管理员用户 ID 的 Gmail。

根据页面 选择在 Google Cloud 上使用和验证服务帐号的最佳方法 上的信息,我确定应该使用“附加服务帐号”选项进行身份验证。

按照页面 为服务器到服务器应用程序使用 OAuth 2.0 上的说明,我创建了一个新的服务帐号,并向其授予了对 https://mail.google.com/ 范围的域级访问权限。我将新的服务帐号分配为云函数的运行时服务帐号。

gmail.NewService 语句似乎执行成功,但 srv.Users.Labels.List(user) 语句失败,并显示“错误 400: 前提条件检查失败。”。
以下是日志文件。

2022-07-09T03:34:14.575564Z testgogmail hy9add8bqppl 2022/07/09 03:34:14 开始

2022-07-09T03:34:14.785116Z testgogmail hy9add8bqppl 2022/07/09 03:34:14 无法获取标签:googleapi: 错误 400: 前提条件检查失败。, failedPrecondition

2022-07-09T03:34:14.799538102Z testgogmail hy9add8bqppl 函数执行耗时 553 毫秒。状态:连接错误

那么我漏掉了什么?我做错了什么?

英文:
// Package p contains an HTTP Cloud Function.
package p

import (
	"log"
	"fmt"
	"net/http"
	"context"
	"google.golang.org/api/gmail/v1"
)


func HelloWorld(wx http.ResponseWriter, rx *http.Request) {
	log.Println("start")

	srv, err := gmail.NewService(context.Background())
	if err != nil {
        log.Fatalf("Unable to retrieve Gmail client: %v", err)
    }

	user := "me"
	r, err := srv.Users.Labels.List(user).Do()
	if err != nil {
		log.Fatalf("Unable to retrieve labels: %v", err)
	}
	if len(r.Labels) == 0 {
		fmt.Println("No labels found.")
		return
	}
	fmt.Println("Labels:")
	for _, l := range r.Labels {
		fmt.Printf("- %s\n", l.Name)
	}

	log.Println("end")
}

I'm writing a Google Cloud function in Go that needs to access the Gmail of my admin userid that owns the project, the gmail account, and created the cloud function.

Using the information on the page Choose the best way to use and authenticate service accounts on Google Cloud, I determined I should authenticate using "Attach Service Account" option.

Following the instructions on page Using OAuth 2.0 for Server to Server Applications, I created a new service account and delegated to it domain-wide access to scope https://mail.google.com/
I assigned the new service account as the Runtime Service Account for the Cloud Function.

The gmail.NewService statement seems to execute successfully but the srv.Users.Labels.List(user) statement fails with "Error 400: Precondition check".
The log file is below.

2022-07-09T03:34:14.575564Z testgogmail hy9add8bqppl 2022/07/09 03:34:14 start

2022-07-09T03:34:14.785116Z testgogmail hy9add8bqppl 2022/07/09 03:34:14 Unable to retrieve labels: googleapi: Error 400: Precondition check failed., failedPrecondition 

2022-07-09T03:34:14.799538102Z testgogmail hy9add8bqppl Function execution took 553 ms. Finished with status: connection error

So what am I missing? What have I done wrong?

答案1

得分: 2

根据我了解,目前在使用Gmail API for Go时,如果依赖基本的域范围访问/身份验证,是不可能冒充另一个帐户的。尽管执行了gmail.NewService(context.Background())语句,但你实际上是作为服务帐户的Gmail地址进行身份验证。由于该地址实际上并不存在,即使你将不同/有效的电子邮件帐户作为用户参数传递,后续的Users.Labels.List也会失败。

然而,如果你使用具有域范围访问权限的服务帐户创建基于服务帐户的身份验证令牌,并在创建Gmail服务时使用WithTokenSource选项,它确实可以工作。注意-下面的示例代码是基于从在线UI创建和执行云函数,而不是云shell。

pathWD, err := os.Getwd()
if err != nil {
    log.Println("error getting working directory:", err)
}
log.Println("pathWD: ", pathWD)

jsonPath := pathWD + "/serverless_function_source_code/"
serviceAccountFile := "service_account.json"
serviceAccountFullFile := jsonPath + serviceAccountFile
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", serviceAccountFullFile)

serviceAccountJSON, err := ioutil.ReadFile(serviceAccountFullFile)
if err != nil {
    log.Fatal(err)
}

config, err := google.JWTConfigFromJSON(serviceAccountJSON,
    "https://mail.google.com/", "https://www.googleapis.com/auth/cloud-platform",
)

config.Subject = "admin@awarenet.us"

ctx := context.Background()
srv, err := gmail.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx)))
if err != nil {
    log.Fatalf("Unable to retrieve Gmail client: %v", err)
}

希望对你有所帮助!

英文:

From what I determined, currently it is not possible to impersonate another account using the Gmail API for Go when you are relying on the basic domain-wide access/authentication. The gmail.NewService(context.Background()) statement executes successfully but you are authenticated as the gmail address of the service account. Since that does not actually exist, the subsequent Users.Labels.List fails even if you pass a different/valid email account as the user parameter.

However, it does work if you create an authentication token based on the service account with domain-wide access by using google.JWTConfigFromJSON and then use the WithTokenSource option when creating the Gmail service. Note - the sample code below is based on creating and executing the cloud function from the online UI, not the cloud shell.

    pathWD, err := os.Getwd()
	if err != nil {
		log.Println("error getting working directory:", err)
	}
	log.Println("pathWD: ", pathWD)

	jsonPath := pathWD + "/serverless_function_source_code/"
	serviceAccountFile := "service_account.json"
	serviceAccountFullFile := jsonPath + serviceAccountFile
	os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", serviceAccountFullFile)

	serviceAccountJSON, err := ioutil.ReadFile(serviceAccountFullFile)
	if err != nil {
		log.Fatal(err)
	}

	config, err := google.JWTConfigFromJSON(serviceAccountJSON,
		"https://mail.google.com/", "https://www.googleapis.com/auth/cloud-platform",
	)

	config.Subject = "admin@awarenet.us"

	ctx := context.Background()
	srv, err := gmail.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx)))
	if err != nil {
		log.Fatalf("Unable to retrieve Gmail client: %v", err)
	}

huangapple
  • 本文由 发表于 2022年7月9日 11:59:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/72918846.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定