Merge pull request #10827 from jboeuf/max_token_lifetime_cpp

Better handling of token lifetime.
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index 1ec9b97..92330d4 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -132,13 +132,17 @@
 /// services.
 std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
 
+/// Constant for maximum auth token lifetime.
+constexpr long kMaxAuthTokenLifetimeSecs = 3600;
+
 /// Builds Service Account JWT Access credentials.
 /// json_key is the JSON key string containing the client's private key.
 /// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
 /// (JWT) created with this credentials. It should not exceed
-/// \a grpc_max_auth_token_lifetime or will be cropped to this value.
+/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
 std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
-    const grpc::string& json_key, long token_lifetime_seconds);
+    const grpc::string& json_key,
+    long token_lifetime_seconds = kMaxAuthTokenLifetimeSecs);
 
 /// Builds refresh token credentials.
 /// json_refresh_token is the JSON string containing the refresh token along
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c
index 589a6f9..4357657 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.c
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c
@@ -125,6 +125,13 @@
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &jwt_vtable;
   c->key = key;
+  gpr_timespec max_token_lifetime = grpc_max_auth_token_lifetime();
+  if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) {
+    gpr_log(GPR_INFO,
+            "Cropping token lifetime to maximum allowed value (%d secs).",
+            (int)max_token_lifetime.tv_sec);
+    token_lifetime = grpc_max_auth_token_lifetime();
+  }
   c->jwt_lifetime = token_lifetime;
   gpr_mu_init(&c->cache_mu);
   jwt_reset_cache(exec_ctx, c);
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 9d419c7..a76cb04 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -816,6 +816,45 @@
   GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0);
 }
 
+static grpc_service_account_jwt_access_credentials *creds_as_jwt(
+    grpc_call_credentials *creds) {
+  GPR_ASSERT(creds != NULL);
+  GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_JWT) == 0);
+  return (grpc_service_account_jwt_access_credentials *)creds;
+}
+
+static void test_jwt_creds_lifetime(void) {
+  char *json_key_string = test_json_key_str();
+
+  // Max lifetime.
+  grpc_call_credentials *jwt_creds =
+      grpc_service_account_jwt_access_credentials_create(
+          json_key_string, grpc_max_auth_token_lifetime(), NULL);
+  GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime,
+                          grpc_max_auth_token_lifetime()) == 0);
+  grpc_call_credentials_release(jwt_creds);
+
+  // Shorter lifetime.
+  gpr_timespec token_lifetime = {10, 0, GPR_TIMESPAN};
+  GPR_ASSERT(gpr_time_cmp(grpc_max_auth_token_lifetime(), token_lifetime) > 0);
+  jwt_creds = grpc_service_account_jwt_access_credentials_create(
+      json_key_string, token_lifetime, NULL);
+  GPR_ASSERT(
+      gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime, token_lifetime) == 0);
+  grpc_call_credentials_release(jwt_creds);
+
+  // Cropped lifetime.
+  gpr_timespec add_to_max = {10, 0, GPR_TIMESPAN};
+  token_lifetime = gpr_time_add(grpc_max_auth_token_lifetime(), add_to_max);
+  jwt_creds = grpc_service_account_jwt_access_credentials_create(
+      json_key_string, token_lifetime, NULL);
+  GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime,
+                          grpc_max_auth_token_lifetime()) == 0);
+  grpc_call_credentials_release(jwt_creds);
+
+  gpr_free(json_key_string);
+}
+
 static void test_jwt_creds_success(void) {
   char *json_key_string = test_json_key_str();
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -1216,6 +1255,7 @@
   test_compute_engine_creds_failure();
   test_refresh_token_creds_success();
   test_refresh_token_creds_failure();
+  test_jwt_creds_lifetime();
   test_jwt_creds_success();
   test_jwt_creds_signing_failure();
   test_google_default_creds_auth_key();