Google 具有服务帐户的管理员 API -- 凭据错误

Google Admin API with service account -- bad credentials

我正在尝试编写控制台应用程序代码以使用从 SQL 数据库中提取的值更新 Google 目录。使用服务帐户时,我似乎无法使 API 连接成功。有任何想法吗?我已将代码缩减为此处的基本内容。


    static void Main(string[] args)
            {
                try
                { 
                    // Create a ServiceAccountCredential credential
                    var xCred = new ServiceAccountCredential(new ServiceAccountCredential.Initializer("saxxxxxxxx@directorysync-xxxxxx.iam.gserviceaccount.com")
                    {
                        Scopes = new[] {
                                DirectoryService.Scope.AdminDirectoryUser,
                                DirectoryService.Scope.AdminDirectoryUserReadonly
                            }
                    }.FromPrivateKey("-----BEGIN PRIVATE KEY-----\nMI...p9XnI4DZFO/QQJc=\n-----END PRIVATE KEY-----\n"));
    
                    // Create the service
                    DirectoryService service = new DirectoryService(
                        new BaseClientService.Initializer()
                        {
                            HttpClientInitializer = xCred,
                        }
                    );
                    
                    var listReq = service.Users.List();
                    listReq.Domain = "mycompany.com";
                    listReq.MaxResults = 100;
                    listReq.OrderBy = UsersResource.ListRequest.OrderByEnum.Email;
                    Users results = listReq.Execute();
                    //  process the users list here...
                    
                }
                catch (Exception e)
                  { Console.WriteLine(e.Message); }
            }

错误发生在 .Execute() 行:

Google.Apis.Requests.RequestError
Not Authorized to access this resource/api [403]
Errors [
        Message[Not Authorized to access this resource/api] Location[ - ] Reason[forbidden] Domain[global]
]

我已经尝试在其他地方看到的代码 () 引入包含服务帐户凭据的 .JSON 文件的全部内容;那没有什么区别。我不是 google 域管理员,但管理员构建了凭据并承诺它确实有权访问用户资源。我完全迷失在不对的地方。

或者:

  • 您缺少要模拟的管理员用户的电子邮件地址。
  • 域管理员需要为服务帐户分配用户管理权限。

背景

使用服务帐户发出 Google API 请求涉及两个 HTTP 请求:

  1. 使用服务帐户的凭据从 Google OAuth 2.0 服务器请求访问令牌。 HTTP POST 与使用服务帐户私钥签名的 JWT 一起发送。如果成功,将返回一个访问令牌,有效期为一小时。

  2. 使用从上一步获得的 OAuth 访问令牌发出服务 API 请求(在本例中为 Admin SDK Directory API)。

您提供的错误消息未在 JWT error codes 页面中列出,因此第 1 步有效,错误来自第 2 步 - 对目录 API.[=27= 的请求]

您应该能够使用像 mitmproxy.

这样的 HTTPS 请求拦截器来确认这一点

目录 API users.list 方法会出现 403 错误,原因如下:

  1. 您已通过服务帐户身份验证,但该服务帐户没有足以满足请求的管理员权限。

  2. 您已作为域中的用户进行身份验证(使用具有 JWT 请求中 sub 参数的模拟服务帐户,或使用三足交互式 OAuth),但该用户没有足以满足请求的管理员权限。

  3. 您已验证为具有足够权限的服务帐户或用户,但 domain 参数不属于与服务帐户或用户相关联的客户。

在您的示例代码中,没有指定域用户(管理员)的电子邮件地址(ServiceAccountCredential.Initializer 的电子邮件地址实际上是服务帐户的 OAuth 客户端名称,而不是真实的电子邮件地址) , 所以它是情况 1 或 3.

解决案例 1

默认情况下,服务帐户与域或访问权限没有关联。

管理员可以打开 Admin console,转到“帐户 > 管理员角色 >“用户管理管理员”> 管理员 > 分配服务帐户”,然后:

  • 添加服务帐户名称(看起来像电子邮件地址,以 @gserviceaccount.com 结尾)。
  • 点击“分配角色”。

现在,服务帐号不需要模拟域中的其他管理员,直接拥有管理员权限。

这有几个副作用:

  • 服务帐户不能被“暂停”,只能从管理员角色中删除。
  • 操作的审核日志记录将在管理控制台的“报告 > 审核 > 管理”部分显示服务帐户名称。

解决案例 2

您可能想模拟域中的管理员用户,您可以通过添加以下内容来实现:

, User = "admin@example.com"

-将Scopes数组传递给ServiceAccountCredential.Initializer后.

这会将用户的电子邮件地址添加到 JWT 请求以检索该用户的访问令牌(通过将 sub 字段添加到 JWT 断言的声明集中)。

解决案例 3

替换行上的"mycompany.com"

listReq.Domain = "mycompany.com";

- 使用与客户关联的域,或者删除该行并添加:

listReq.Customer = "my_customer";

(字面意思是 my_customer - 参见 users.list query-parameters) - 这将列出与客户关联的所有域上的用户(Google Workspace 和 Cloud Identity 客户可以有许多辅助域)。