Quiero invocar una nube de ejecución desde una aplicación externa. La aplicación externa está escrito en Kotlin (Java) y se ejecutan en el JDK 11 JVM. Autentica utilizando una cuenta de servicio
ServiceAccountCredentials.fromStream(serviceAccount).createScoped("https://www.googleapis.com/auth/cloud-platform")
en la cuenta de servicio es un archivo JSON válida. He probado los permisos para invocar una nube de gestión para la cuenta de servicio dentro de la consola de Google Cloud.
No he encontrado una API oficial, así que utiliza Google GoogleNetHttpTransport de ejecutar una solicitud HTTP POST. Para invocar la carrera nube He tratado de utilizar el HttpCredentialsAdapter
transport.createRequestFactory(HttpCredentialsAdapter(googleCredentials))
.buildPostRequest(GenericUrl(url), JsonHttpContent(JacksonFactory(), data))
He intentado utilizar el token de acceso o directamente
val headers = HttpHeaders()
googleCredentials.refreshIfExpired()
headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
postRequest.headers = headers
Y he tratado de usar una cuenta de servicio de chorro y el uso de la solicitud de metadatos jwt
val headers = HttpHeaders()
jwtCredentials = ServiceAccountJwtAccessCredentials.fromStream(serviceAccount)
jwtCredentials.getRequestMetadata(URI(url)).forEach {
headers.set(it.key, it.value)
}
postRequest.headers = headers
En todos estos casos se devuelve este error
[20:35:00 WARN]: Exception in thread "TestThread" com.google.api.client.http.HttpResponseException: 401 Unauthorized
[20:35:00 WARN]: at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
[20:35:00 WARN]: at ***.CloudRun$invoke$3.invokeSuspend(CloudRun.kt:34)
[20:35:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[20:35:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[20:35:00 WARN]: at java.base/java.lang.Thread.run(Thread.java:834)
Gracias por su ayuda por adelantado
Me pasé un tiempo en la biblioteca OAuth2 Java y el problema es el siguiente. La clase ServiceAccountCredentials
añadir una AccessToken
como la autorización, y la clase ServiceAccountJwtAccessCredentials
añadir una firma automática identity token
.
Voy a entrar más profundamente en ella, pero por ahora se puede establecer la cabecera manualmente
String myUri = "https://.....";
Credentials credentials = ServiceAccountCredentials
.fromStream(resourceLoader.getResource("classpath:./key.json")
.getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");
String token = ((IdTokenProvider)credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory();
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization","Bearer " + token);
request.setHeaders(headers);
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
Las piezas están aquí, pero no trabajan juntos.
EDITAR
Después de algún cambio en GitHub, un Google me proporcione la solución. Ahora la cabecera se aprovisiona automáticamente con un ID firmado Token
Credentials credentials = ServiceAccountCredentials
.fromStream(resourceLoader.getResource("classpath:./key.json")
.getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");
IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
.setIdTokenProvider((ServiceAccountCredentials)credentials)
.setTargetAudience(myUri).build();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));