"Invalid JWT: Failed audience check" when using Google Api Services in GraalVM native-image

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

"Invalid JWT: Failed audience check" when using Google Api Services in GraalVM native-image

问题

我有一个简单的应用程序,通过基于HTTP的`google-api-services-logging`将消息发送到Google Cloud Logging。最初我使用了gRPC的`cloud-logging`库,但无法使其与GraalVM一起正常工作。但不幸的是,我在HTTP变体方面也遇到了困难。当在传统的Java虚拟机上执行代码时,它可以正常工作,但在运行原生映像时在运行时失败。

java.io.IOException: 获取服务账号访问令牌时出错:400 Bad Request
POST https://oauth2.googleapis.com/token
{"error":"invalid_grant","error_description":"Invalid JWT: Failed audience check."}
    at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:444)
    at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:157)
    at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:145)
    at com.google.auth.oauth2.ServiceAccountCredentials.getRequestMetadata(ServiceAccountCredentials.java:603)
    at com.google.auth.http.HttpCredentialsAdapter.initialize(HttpCredentialsAdapter.java:91)
    at com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:88)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.buildHttpRequest(AbstractGoogleClientRequest.java:422)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:541)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:474)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:591)
    ...
Caused by: com.google.api.client.http.HttpResponseException: 400 Bad Request
POST https://oauth2.googleapis.com/token
{"error":"invalid_grant","error_description":"Invalid JWT: Failed audience check."}
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
    at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:441)
    ... 35 more

native-image.properties

Args = \
  --verbose \
  --no-server \
  --no-fallback \
  --static \
  --install-exit-handlers \
  -H:+ReportExceptionStackTraces \
  -H:+TraceClassInitialization \
  -H:+PrintClassInitialization \
  -H:UseMuslC=/musl/ \
  -H:+RemoveSaturatedTypeFlows \
  --enable-https \
  --enable-http \
  --initialize-at-build-time

reflect-config.json

[
  {
    "name": "com.google.api.client.json.GenericJson",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.services.logging.v2.model.LogEntry",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.googleapis.GoogleUtils",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  }
]

resource-config.json

{
  "resources": [
    { "pattern": "^.*\\.json$" },
    { "pattern": "^.*\\.properties$" },
    { "pattern": "^.*\\.jks$" }
  ]
}

app.scala

val scopes = util.Arrays.asList(LoggingScopes.CLOUD_PLATFORM_READ_ONLY, LoggingScopes.LOGGING_WRITE)
val credentials = ServiceAccountCredentials.fromStream("service-account.json").createScoped(scopes)
val logging = new Logging.Builder(
  transport,
  JacksonFactory.getDefaultInstance,
  new HttpCredentialsAdapter(credentials)
).setApplicationName("my-project").build()

Dockerfile

FROM oracle/graalvm-ce:20.1.0-java11 as builder
...
RUN gu install native-image
...
RUN sbt assembly
RUN native-image -jar /root/target/scala-2.13/graal-test-assembly-0.1.0-SNAPSHOT.jar

FROM scratch

WORKDIR /app/

COPY --from=builder /root/graal-test-assembly-0.1.0-SNAPSHOT /app/my-native-image

CMD ["/app/my-native-image"]

我怀疑这与加密/SSL相关的特性有关,但是我试过的方法已经用尽了。


<details>
<summary>英文:</summary>

I have a simple application that sends a message to Google Cloud Logging via the HTTP based `google-api-services-logging`. I was initially using the gRPC `cloud-logging` library, but couldn&#39;t get it to work with GraalVM at all. But unfortunately, I am also struggling with the HTTP variant. The code is working fine when executed on a traditional Java VM, but fails at runtime when running the native image.

java.io.IOException: Error getting access token for service account: 400 Bad Request
POST https://oauth2.googleapis.com/token
{"error":"invalid_grant","error_description":"Invalid JWT: Failed audience check."}
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:444)
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:157)
at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:145)
at com.google.auth.oauth2.ServiceAccountCredentials.getRequestMetadata(ServiceAccountCredentials.java:603)
at com.google.auth.http.HttpCredentialsAdapter.initialize(HttpCredentialsAdapter.java:91)
at com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:88)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.buildHttpRequest(AbstractGoogleClientRequest.java:422)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:541)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:474)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:591)
...
Caused by: com.google.api.client.http.HttpResponseException: 400 Bad Request
POST https://oauth2.googleapis.com/token
{"error":"invalid_grant","error_description":"Invalid JWT: Failed audience check."}
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:441)
... 35 more


**native-image.properties**

Args =
--verbose
--no-server
--no-fallback
--static
--install-exit-handlers
-H:+ReportExceptionStackTraces
-H:+TraceClassInitialization
-H:+PrintClassInitialization
-H:UseMuslC=/musl/
-H:+RemoveSaturatedTypeFlows
--enable-https
--enable-http
--initialize-at-build-time


**reflect-config.json**

[
{
"name": "com.google.api.client.json.GenericJson",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "com.google.api.services.logging.v2.model.LogEntry",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "com.google.api.client.googleapis.GoogleUtils",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}
]


**resource-config.json**

{
"resources": [
{ "pattern": "^.\.json$" },
{ "pattern": "^.
\.properties$" },
{ "pattern": "^.*\.jks$" }
]
}


**app.scala**
```scala
val scopes = util.Arrays.asList(LoggingScopes.CLOUD_PLATFORM_READ_ONLY, LoggingScopes.LOGGING_WRITE)
val credentials  = ServiceAccountCredentials.fromStream(&quot;service-account.json&quot;).createScoped(scopes)
val logging = new Logging.Builder(
  transport,
  JacksonFactory.getDefaultInstance,
  new HttpCredentialsAdapter(credentials)
).setApplicationName(&quot;my-project&quot;).build()

Dockerfile

FROM        oracle/graalvm-ce:20.1.0-java11 as builder
...
RUN         gu install native-image
...
RUN         sbt assembly
RUN         native-image -jar /root/target/scala-2.13/graal-test-assembly-0.1.0-SNAPSHOT.jar

FROM        scratch

WORKDIR     /app/

COPY        --from=builder /root/graal-test-assembly-0.1.0-SNAPSHOT /app/my-native-image

CMD         [&quot;/app/my-native-image&quot;]

I suspect that this is related to crypto / SSL related features, but I ran out of things to try.

答案1

得分: 4

生成的JWT令牌实际上是基本为空的,因为在序列化为JSON时通过反射遍历字段。通过向 reflect-config.json 添加相应的规则,解决了这个问题,并揭示了可以通过配置解决的进一步问题。

[
  {
    "name": "com.google.api.client.json.GenericJson",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.json.webtoken.JsonWebToken",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.json.webtoken.JsonWebToken$Header",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.json.webtoken.JsonWebToken$Payload",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.util.GenericData",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.http.UrlEncodedContent",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.json.webtoken.JsonWebSignature$Header",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.json.webtoken.JsonWebSignature",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.services.logging.v2.model.WriteLogEntriesRequest",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.services.logging.v2.model.WriteLogEntriesResponse",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.services.logging.v2.model.LogEntry",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.client.googleapis.json.GoogleJsonError",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  },
  {
    "name": "com.google.api.services.logging.v2.model.MonitoredResource",
    "allDeclaredConstructors": true,
    "allPublicConstructors": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "allDeclaredFields": true,
    "allPublicFields": true
  }
]

在Google的Java库中滥用反射确实令人头疼。他们至少可以将GraalVM原生映像配置添加到他们的库中。

你可以在这里找到适用于Google云日志记录的完整的 reflect-config.json这里

英文:

It turned out that the generated JWT token was basically empty because the fields are traversed via reflection when serializing to JSON. Adding the respective rules to reflect-config.json solved that issue and revealed further issues that could be solved by configuration.

[
{
&quot;name&quot;: &quot;com.google.api.client.json.GenericJson&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.json.webtoken.JsonWebToken&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.json.webtoken.JsonWebToken$Header&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.json.webtoken.JsonWebToken$Payload&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.util.GenericData&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.http.UrlEncodedContent&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.json.webtoken.JsonWebSignature$Header&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.json.webtoken.JsonWebSignature&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.services.logging.v2.model.WriteLogEntriesRequest&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.services.logging.v2.model.WriteLogEntriesResponse&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.services.logging.v2.model.LogEntry&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.client.googleapis.json.GoogleJsonError&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
},
{
&quot;name&quot;: &quot;com.google.api.services.logging.v2.model.MonitoredResource&quot;,
&quot;allDeclaredConstructors&quot;: true,
&quot;allPublicConstructors&quot;: true,
&quot;allDeclaredMethods&quot;: true,
&quot;allPublicMethods&quot;: true,
&quot;allDeclaredFields&quot;: true,
&quot;allPublicFields&quot;: true
}
]

The abuse of reflection in Google's Java libraries is quite a pain. The least they could do is add the GraalVM native-image configurations to their libraries.

You can find a complete reflect-config.json for google cloud logging http here.

huangapple
  • 本文由 发表于 2020年7月26日 00:58:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/63091045.html
匿名

发表评论

匿名网友

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

确定