Получение 400 invalid_grant в google admin sdk api с помощью golang. Какие-либо предложения?

Я пытаюсь разработать сценарий golang, который использует мою учетную запись службы для управления моим доменом Google. Я получаю сообщение об ошибке, когда пытаюсь составить простой список пользователей: 400 invalid_grant. Похоже, я правильно использую свою учетную запись службы (?), и моя учетная запись службы является суперадминистратором. Я использую учетные данные в коде Java; поэтому я знаю, что это действительно. Какие-нибудь мысли?

package main

import (
    "fmt"
    "io/ioutil"
    "log"

    "golang.org/x/net/context"
    "golang.org/x/oauth2/google"
    directory "google.golang.org/api/admin/directory/v1"
)

func main() {
    serviceAccountFile := "/credentials.json"
    serviceAccountJSON, err := ioutil.ReadFile(serviceAccountFile)
    if err != nil {
        log.Fatalf("Could not read service account credentials file, %s => {%s}", serviceAccountFile, err)
    }

    config, err := google.JWTConfigFromJSON(serviceAccountJSON,
        directory.AdminDirectoryUserScope,
        directory.AdminDirectoryUserReadonlyScope,
    )

    // Add the service account.
    config.Email = "[email protected]"

    srv, err := directory.New(config.Client(context.Background()))
    if err != nil {
        log.Fatalf("Could not create directory service client => {%s}", err)
    }

    // The next step fails with:
    //2019/03/25 10:38:43 Unable to retrieve users in domain: Get https://www.googleapis.com/admin/directory/v1/users?alt=json&maxResults=10&orderBy=email&prettyPrint=false: oauth2: cannot fetch token: 400 Bad Request
    //Response: {
    //  "error": "invalid_grant",
    //  "error_description": "Robot is missing a project number."
    //}
    //exit status 1
    usersReport, err := srv.Users.List().MaxResults(10).OrderBy("email").Do()
    if err != nil {
        log.Fatalf("Unable to retrieve users in domain: %v", err)
    }

    if len(usersReport.Users) == 0 {
        fmt.Print("No users found.\n")
    } else {
        fmt.Print("Users:\n")
        for _, u := range usersReport.Users {
            fmt.Printf("%s (%s)\n", u.PrimaryEmail, u.Name.FullName)
        }
    }
}

person ad34    schedule 25.03.2019    source источник
comment
Выполняли ли вы эти инструкции эффективно, в частности (а) шаг делегирования; б) записка? Когда вы пишете, что использовали учетную запись службы в Java, это для очень похожей цели? то есть это работает на Java, но не на Go? developers.google.com/admin-sdk/directory/v1/guides/ делегирование   -  person DazWilkin    schedule 26.03.2019
comment
Я пробовал, но мне сложно получить доступ к домену G Suite. Я думаю, что образец Google Golang неверен. Пожалуйста, попробуйте config.Email="[[Service Account Email]] и config.Subject=[[User-being-delegated Email Address]]   -  person DazWilkin    schedule 26.03.2019
comment
Я собираюсь спросить друга, потому что я не могу заставить это работать, хотя я получаю 401 (несанкционированный доступ). Сообщу сюда с руководством моих экспертов.   -  person DazWilkin    schedule 26.03.2019
comment
Мне не удалось заставить это работать в Голанге. Я написал эквивалентную версию на Python, и она работает. Продолжаем расследование. gist.github.com/DazWilkin/dca8c3db8879765632d4c4be8d662074   -  person DazWilkin    schedule 27.03.2019


Ответы (2)


У меня это работает. Кажется, что это может быть сочетание вещей. DazWilkin, да, я получаю несанкционированную ошибку 401, когда переключаюсь между способами входа в свою учетную запись службы. Я сделал следующие изменения.

  1. Использована Тема вместо Электронной почты в конфигурации.
  2. Используется только область AdminDirectoryUserScope вместо области AdminDirectoryUserReadonlyScope (или их комбинация).
  3. Включил домен в запрос. Я получаю 400 Bad Request без него.
  4. Я убедился, что API-интерфейсы каталогов включены по этой ссылке: https://developers.google.com/admin-sdk/directory/v1/quickstart/go . Когда я нажал на эту ссылку, мне сказали, что API уже работает. Здесь я использую те же учетные данные json, что и в некоторых производственных сценариях, написанных на других языках. В смысле, я думал, что это уже было на месте. Поэтому я не думаю, что мне нужно было делать этот шаг, но я включу его на случай, если он будет полезен для других.

Вот как сейчас выглядит мой скрипт:

package main

import (
    "fmt"
    "io/ioutil"
    "log"

    "golang.org/x/net/context"
    "golang.org/x/oauth2/google"
    directory "google.golang.org/api/admin/directory/v1"
)

func main() {
    serviceAccountFile := "/credentials.json"

    serviceAccountJSON, err := ioutil.ReadFile(serviceAccountFile)
    if err != nil {
        log.Fatalf("Could not read service account credentials file, %s => {%s}", serviceAccountFile, err)
    }

    // I want to use these options, but these cause a 401 unauthorized error
    //  config, err := google.JWTConfigFromJSON(serviceAccountJSON,
    //      directory.AdminDirectoryUserScope,
    //      directory.AdminDirectoryUserReadonlyScope,
    //  )
    config, err := google.JWTConfigFromJSON(serviceAccountJSON,
        directory.AdminDirectoryUserScope,
    )

    // Add the service account.
    //config.Email = "[email protected]" // Don't use Email, use Subject.
    config.Subject = "[email protected]"

    srv, err := directory.New(config.Client(context.Background()))

    if err != nil {
        log.Fatalf("Could not create directory service client => {%s}", err)
    }

    // Get the results.
    usersReport, err := srv.Users.List().Domain("domain.com").MaxResults(100).Do()
    if err != nil {
        log.Fatalf("Unable to retrieve users in domain: %v", err)
    }

    // Report results.
    if len(usersReport.Users) == 0 {
        fmt.Print("No users found.\n")
    } else {
        fmt.Print("Users:\n")
        for _, u := range usersReport.Users {
            fmt.Printf("%s (%s)\n", u.PrimaryEmail, u.Name.FullName)
        }
    }
}
person ad34    schedule 26.03.2019

Исправлено!

Спасибо Салу.

Вот рабочий пример Golang:

https://gist.github.com/DazWilkin/afb0413a25272dc7d855ebec5fcadcb6

Примечание

  • Строка 24 --config.Subject
  • Строка 31. Вам нужно будет указать CustomerId (IDPID), используя эту ссылку.

Вот рабочий пример Python:

https://gist.github.com/DazWilkin/dca8c3db8879765632d4c4be8d662074

person DazWilkin    schedule 27.03.2019