Hi, I'm trying to get my Google Cloud Endpoints project with gRPC working with an OAuth2.0 authentication provider using GoogleCredentials
I followed the steps in this tutorial and could make an authenticated request by generating the jwt token and setting the audience and issuer etc
But we need to use GoogleCredentials for authentication and I have tried making the client request in several ways but it did not work out
Below is the relevant piece of my Client code along with my api_config_auth.yaml file
CLIENT:
public class ReporterClient {
public static void main(String[] args) throws Exception {
// Create gRPC stub.
ReporterGrpc.ReporterBlockingStub reporterBlockingStub = createReporterStub(host, port);
getParams(reporterBlockingStub, domain, type, objectName, data);
}
// Send Request to Server
public static void getParams(ReporterGrpc.ReporterBlockingStub reporterBlockingStub,String domain, String type, String objectName, String data) {
GenerateReportRequest request = GenerateReportRequest.newBuilder().setDomain(domain).setType(type).setObjectName(objectName).setData(data).build();
GenerateReportResponse response = reporterBlockingStub.generateReport(request);
}
// Version 1: Without scopes
public static ReporterGrpc.ReporterBlockingStub createReporterStub(String host, int port) throws Exception {
Channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();
GoogleCredentials googleCredentials = Environment.get().computeEngineDefaultCredentials();
return ReporterGrpc.newBlockingStub(channel)
.withCallCredentials(MoreCallCredentials
.from(googleCredentials));
}
// Version 2: With scopes
public static ReporterGrpc.ReporterBlockingStub createReporterStubTry(String host, int port) throws Exception {
Channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();
List<String> scopes = new ArrayList<>();
scopes.add("https://MY_SERVICE_CONFIGURATION_NAME”);
GoogleCredentials googleCredentials = Environment.get().computeEngineDefaultCredentials().createScoped(scopes);
return ReporterGrpc.newBlockingStub(channel)
.withCallCredentials(MoreCallCredentials
.from(googleCredentials));
}
}
YAML File : API_CONFIG_AUTH.yaml:
# Reporter gRPC API configuration.
type: google.api.Service
config_version: 3
# Name of the service configuration.
name: MY_SERVICE_CONFIGURATION_NAME
# API title to appear in the user interface (Google Cloud Console).
title: Reporter gRPC API
apis:
- name: reporter.Reporter
# API usage restrictions.
usage:
rules:
# GenerateReport method can be called without an API Key.
- selector: reporter.Reporter.GenerateReport
allow_unregistered_calls: true
# Request authentication.
authentication:
providers:
- id: google_service_account
# Replace SERVICE-ACCOUNT-ID with your service account's email address.
issuer: MY_SERVICE_ACCOUNT_ID
jwks_uri: https://www.googleapis.com/robot/v1/metadata/x509/MY_SERVICE_ACCOUNT_ID
rules:
# This auth rule will apply to all methods.
- selector: "*"
requirements:
- provider_id: google_service_account
// Error for Version 1: Without scopes
Exception in thread "main" io.grpc.StatusRuntimeException: PERMISSION_DENIED: JWT validation failed: Audience not allowed
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:212)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:193)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:126)
at com.soliduslink.vault.reporter.endpoints.ReporterGrpc$ReporterBlockingStub.generateReport(ReporterGrpc.java:138)
at com.soliduslink.vault.reporter.endpoints.ReporterClient.getParams(ReporterClient.java:143)
at com.soliduslink.vault.reporter.endpoints.ReporterClient.main(ReporterClient.java:118)
// Error for Version 2: With scopes
Exception in thread "main" io.grpc.StatusRuntimeException: UNAUTHENTICATED
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:212)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:193)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:126)
at com.soliduslink.vault.reporter.endpoints.ReporterGrpc$ReporterBlockingStub.generateReport(ReporterGrpc.java:138)
at com.soliduslink.vault.reporter.endpoints.ReporterClient.getParams(ReporterClient.java:143)
at com.soliduslink.vault.reporter.endpoints.ReporterClient.main(ReporterClient.java:118)
Caused by: java.io.IOException: Error parsing token refresh response. Expected value access_token not found.
at com.google.auth.oauth2.OAuth2Utils.validateString(OAuth2Utils.java:116)
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:371)
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:149)
at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:135)
at io.grpc.auth.GoogleAuthLibraryCallCredentials$1.run(GoogleAuthLibraryCallCredentials.java:95)
at io.grpc.stub.ClientCalls$ThreadlessExecutor.waitAndDrain(ClientCalls.java:575)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:120)
Thanks a lot for your comments!
Update on the issue:
We have modified our Client to use ServiceAccountJwtAccessCredentials
public static ReporterGrpc.ReporterBlockingStub createReporterStub(String host, int port) throws Exception {
Channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();
ServiceAccountJwtAccessCredentials serviceAccountJwtAccessCredentials = Environment.get().computeEngineDefaultCredentials();
return ReporterGrpc.newBlockingStub(channel).withCallCredentials(
new GoogleAuthLibraryCallCredentials(serviceAccountJwtAccessCredentials));
}
It works but with a change in the class GoogleAuthLibraryCallCredentials.java ,
Currently the audience that is set by ServiceAccountJwtAccessCredentials is being overwritten by the above line: ReporterGrpc.newBlockingStub(channel).withCallCredentials(new GoogleAuthLibraryCallCredentials(serviceAccountJwtAccessCredentials))
So instead of the audience (SERVICE_CONFIGURATION_NAME) that we set, we are obtaining a string like : https://35.195.24.28:80/reporter.Reporter
Which is being constructed by https://github.com/grpc/grpc-java/blob/master/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java#L123
After we changed the uri passed to null at : https://github.com/grpc/grpc-java/blob/master/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java#L98 , we were able to point to the right audience:
Map<String, List<String>> metadata = creds.getRequestMetadata(uri) -> Map<String, List<String>> metadata = creds.getRequestMetadata(null)
Now the ServiceAccountJwtAccessCredentials picks up the right audience from this line:
if (uri == null) {
if (defaultAudience != null) {
uri = defaultAudience;
} else {
……
}
}
Is this working as intended or did we miss something? We did expect the GoogleAuthLibraryCallCredentials.java to overwrite the audience we set.
We were wondering whether ServiceAccountJwtAccessCredentials class is compatible with CallCredentials class or if there is another wrapper available to pass the ServiceAccountJwtAccessCredentials.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/7d00a112-24e1-43ef-b50e-671204014601%40googlegroups.com.--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
So instead of the audience (SERVICE_CONFIGURATION_NAME) that we set, we are obtaining a string like : https://35.195.24.28:80/reporter.Reporter
Btw, would it be possible to have the gRPC client on AppEngine? ManagedChannelBuilder is not supported in AppEngine restricted environment.
even if we set domain name the audience would look like https://{domain_name}/reporter.Reporter. however, the ESP would expect the audience to be "https://reporter.endpoints.{projectid}.cloud.goog". are we missing something here?
Besides the audience problem, we have a bigger issue to make a gRPC client on AppEngine. The problem is ManagedChannelBuilder is not supported on AppEngine restricted environment. Do you know if https://cloud.google.com/endpoints/docs/grpc/transcoding is the right way to go. something like we build a HTTP/JSON request on AppEngine to call a gRPC backend.
That's great to know 1.6 can support gRPC client on GAE!We're using GAE Java 7. so basically we should add<dependency><groupId>io.grpc</groupId><artifactId>grpc-okhttp</artifactId><version>1.6.0</version></dependency>and<dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId><version>1.6.0</version></dependency>to our dependencies to fix the ManagedChannelBuilder issue, right?
BTW, the highest version onhas 1.6.0 been released?