API администратора Google, неверный запрос 400 invalid_grant. (используя сервисную учетную запись)
Поэтому, прежде чем показывать свой код, позвольте мне объяснить, какие шаги я предпринял для "правильной" настройки среды учетной записи службы.
- В консоли разработчика Google, создан сервисный аккаунт. (это созданный идентификатор клиента (который является длинным номером), учетная запись службы (xxxxx@xxxx.iam.gserviceaccount.com) и закрытый ключ, который я загрузил в P12.
- В консоли администратора введите идентификатор клиента с соответствующей областью действия. В моем случае я добавил
https://www.googleapis.com/auth/admin.directory.group.readonly
а такжеhttps://www.googleapis.com/auth/admin.directory.group.member.readonly
, В моем коде правильно настроить путь к закрытому ключу и другие среды.
def getDirectoryService: Directory = { val httpTransport: HttpTransport = new NetHttpTransport() val jsonFactory: JacksonFactory = new JacksonFactory() val credential: GoogleCredential = new GoogleCredential.Builder() .setTransport(httpTransport) .setJsonFactory(jsonFactory) .setServiceAccountId("xxxxx@xxxx.iam.gserviceaccount.com") .setServiceAccountScopes(util.Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_GROUP_READONLY, DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER_READONLY)) .setServiceAccountUser("admin@domain.com") .setServiceAccountPrivateKeyFromP12File( new java.io.File("/pathToKey/privatekey.p12")) .build() val service: Directory = new Directory.Builder(httpTransport, jsonFactory, null) .setHttpRequestInitializer(credential).build() service }
И тогда я пытаюсь выполнить что-то вроде этого:
service.groups().list().execute()
или же
service.groups().list("domain.com").execute()
Этот код приведет к,
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_grant"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:384)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:868)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.company.project.GoogleServiceProvider.getGroups(GoogleServiceProvider.scala:81)
at com.company.project.ProjectHandler.handle(ProjectHandler.scala:110)
at com.company.common.web.DispatcherServlet.service(DispatcherServlet.scala:40)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:224)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1174)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1106)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
at org.eclipse.jetty.server.Server.handle(Server.java:524)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:319)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:253)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
at java.lang.Thread.run(Thread.java:745)
Что я мог сделать не так? Я искал решение в течение последних двух дней и перепробовал много вещей. Одно из решений, в которых я до сих пор не уверен, - синхронизация ntp (например, как точно синхронизировать время сервера с ntp).
Любая реклама была бы очень полезна, спасибо!
ОБНОВЛЕНИЕ: я также удостоверился, что активировал Admin Directory SDK и включил делегирование всего домена на консоли разработчика.
ОБНОВЛЕНИЕ № 2: Я забыл упомянуть, что учетная запись администратора не является владельцем самого проекта. Таким образом, в основном я являюсь членом домена и создал проект, поэтому я являюсь единственным владельцем проекта и учетной записи службы (я не администратор). Но должен ли админ быть владельцем проекта и создать учетную запись службы для того, чтобы это работало должным образом???
1 ответ
Хорошо, моя проблема была в том, что в setServiceAccountUser
Я поставил адрес электронной почты группы администраторов, а не реальную учетную запись пользователя. По-видимому, это не позволяет вводить групповой адрес электронной почты (псевдоним) в setServiceAccountUser
, Таким образом, после ввода реальной учетной записи пользователя с правами администратора, это, кажется, работает.
Я все еще задаюсь вопросом, что было бы лучшей практикой все же. Как, я должен создать отдельную учетную запись пользователя с правами администратора только для проекта? Я определенно не хочу просто вставлять адрес электронной почты учетной записи администратора в мой код.