Merge pull request #2366 from nicolasnoble/upport-python

Update Python version numbers
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 8e8a896..37d66c0 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -51,6 +51,11 @@
    The creator of the credentials object is responsible for its release. */
 void grpc_credentials_release(grpc_credentials *creds);
 
+/* Environment variable that points to the google default application
+   credentials json key or refresh token. Used in the
+   grpc_google_default_credentials_create function. */
+#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
+
 /* Creates default credentials to connect to a google gRPC service.
    WARNING: Do NOT use this credentials to connect to a non-google service as
    this could result in an oauth2 token leak. */
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 8d694c2..52fd5a2 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -41,7 +41,6 @@
 #include "src/core/json/json.h"
 #include "src/core/httpcli/httpcli.h"
 #include "src/core/iomgr/iomgr.h"
-#include "src/core/security/json_token.h"
 #include "src/core/support/string.h"
 
 #include <grpc/support/alloc.h>
@@ -52,12 +51,12 @@
 
 /* -- Common. -- */
 
-typedef struct {
+struct grpc_credentials_metadata_request {
   grpc_credentials *creds;
   grpc_credentials_metadata_cb cb;
   grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
   void *user_data;
-} grpc_credentials_metadata_request;
+};
 
 static grpc_credentials_metadata_request *
 grpc_credentials_metadata_request_create(grpc_credentials *creds,
@@ -152,16 +151,6 @@
 
 /* -- Ssl credentials. -- */
 
-typedef struct {
-  grpc_credentials base;
-  grpc_ssl_config config;
-} grpc_ssl_credentials;
-
-typedef struct {
-  grpc_server_credentials base;
-  grpc_ssl_server_config config;
-} grpc_ssl_server_credentials;
-
 static void ssl_destroy(grpc_credentials *creds) {
   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
@@ -326,22 +315,6 @@
 
 /* -- Jwt credentials -- */
 
-typedef struct {
-  grpc_credentials base;
-
-  /* Have a simple cache for now with just 1 entry. We could have a map based on
-     the service_url for a more sophisticated one. */
-  gpr_mu cache_mu;
-  struct {
-    grpc_credentials_md_store *jwt_md;
-    char *service_url;
-    gpr_timespec jwt_expiration;
-  } cached;
-
-  grpc_auth_json_key key;
-  gpr_timespec jwt_lifetime;
-} grpc_jwt_credentials;
-
 static void jwt_reset_cache(grpc_jwt_credentials *c) {
   if (c->cached.jwt_md != NULL) {
     grpc_credentials_md_store_unref(c->cached.jwt_md);
@@ -424,10 +397,9 @@
     jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
     jwt_get_request_metadata, NULL};
 
-grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
-                                              gpr_timespec token_lifetime) {
+grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
+    grpc_auth_json_key key, gpr_timespec token_lifetime) {
   grpc_jwt_credentials *c;
-  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
   if (!grpc_auth_json_key_is_valid(&key)) {
     gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
     return NULL;
@@ -444,26 +416,14 @@
   return &c->base;
 }
 
+grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
+                                              gpr_timespec token_lifetime) {
+  return grpc_jwt_credentials_create_from_auth_json_key(
+      grpc_auth_json_key_create_from_string(json_key), token_lifetime);
+}
+
 /* -- Oauth2TokenFetcher credentials -- */
 
-/* This object is a base for credentials that need to acquire an oauth2 token
-   from an http service. */
-
-typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
-                                       grpc_httpcli_context *http_context,
-                                       grpc_pollset *pollset,
-                                       grpc_httpcli_response_cb response_cb,
-                                       gpr_timespec deadline);
-
-typedef struct {
-  grpc_credentials base;
-  gpr_mu mu;
-  grpc_credentials_md_store *access_token_md;
-  gpr_timespec token_expiration;
-  grpc_httpcli_context httpcli_context;
-  grpc_fetch_oauth2_func fetch_func;
-} grpc_oauth2_token_fetcher_credentials;
-
 static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
@@ -669,13 +629,6 @@
 
 /* -- ServiceAccount credentials. -- */
 
-typedef struct {
-  grpc_oauth2_token_fetcher_credentials base;
-  grpc_auth_json_key key;
-  char *scope;
-  gpr_timespec token_lifetime;
-} grpc_service_account_credentials;
-
 static void service_account_destroy(grpc_credentials *creds) {
   grpc_service_account_credentials *c =
       (grpc_service_account_credentials *)creds;
@@ -746,11 +699,6 @@
 
 /* -- RefreshToken credentials. -- */
 
-typedef struct {
-  grpc_oauth2_token_fetcher_credentials base;
-  grpc_auth_refresh_token refresh_token;
-} grpc_refresh_token_credentials;
-
 static void refresh_token_destroy(grpc_credentials *creds) {
   grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
   grpc_auth_refresh_token_destruct(&c->refresh_token);
@@ -786,12 +734,9 @@
   gpr_free(body);
 }
 
-grpc_credentials *grpc_refresh_token_credentials_create(
-    const char *json_refresh_token) {
+grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+    grpc_auth_refresh_token refresh_token) {
   grpc_refresh_token_credentials *c;
-  grpc_auth_refresh_token refresh_token =
-      grpc_auth_refresh_token_create_from_string(json_refresh_token);
-
   if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
     gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
     return NULL;
@@ -804,13 +749,13 @@
   return &c->base.base;
 }
 
-/* -- Fake Oauth2 credentials. -- */
+grpc_credentials *grpc_refresh_token_credentials_create(
+    const char *json_refresh_token) {
+  return grpc_refresh_token_credentials_create_from_auth_refresh_token(
+      grpc_auth_refresh_token_create_from_string(json_refresh_token));
+}
 
-typedef struct {
-  grpc_credentials base;
-  grpc_credentials_md_store *access_token_md;
-  int is_async;
-} grpc_fake_oauth2_credentials;
+/* -- Fake Oauth2 credentials. -- */
 
 static void fake_oauth2_destroy(grpc_credentials *creds) {
   grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
@@ -877,11 +822,6 @@
 
 /* -- Oauth2 Access Token credentials. -- */
 
-typedef struct {
-  grpc_credentials base;
-  grpc_credentials_md_store *access_token_md;
-} grpc_access_token_credentials;
-
 static void access_token_destroy(grpc_credentials *creds) {
   grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
   grpc_credentials_md_store_unref(c->access_token_md);
@@ -997,12 +937,6 @@
 /* -- Composite credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
-  grpc_credentials_array inner;
-  grpc_credentials *connector_creds;
-} grpc_composite_credentials;
-
-typedef struct {
   grpc_composite_credentials *composite_creds;
   size_t creds_index;
   grpc_credentials_md_store *md_elems;
@@ -1232,11 +1166,6 @@
 
 /* -- IAM credentials. -- */
 
-typedef struct {
-  grpc_credentials base;
-  grpc_credentials_md_store *iam_md;
-} grpc_iam_credentials;
-
 static void iam_destroy(grpc_credentials *creds) {
   grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
   grpc_credentials_md_store_unref(c->iam_md);
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 75af73a..d988901 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -39,6 +39,8 @@
 #include <grpc/grpc_security.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/httpcli/httpcli.h"
+#include "src/core/security/json_token.h"
 #include "src/core/security/security_connector.h"
 
 struct grpc_httpcli_response;
@@ -178,11 +180,22 @@
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
     const struct grpc_httpcli_response *response,
     grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
+void grpc_flush_cached_google_default_credentials(void);
 
 /* Simulates an oauth2 token fetch with the specified value for testing. */
 grpc_credentials *grpc_fake_oauth2_credentials_create(
     const char *token_md_value, int is_async);
 
+/* Private constructor for jwt credentials from an already parsed json key.
+   Takes ownership of the key. */
+grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
+    grpc_auth_json_key key, gpr_timespec token_lifetime);
+
+/* Private constructor for refresh token credentials from an already parsed
+   refresh token. Takes ownership of the refresh token. */
+grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+    grpc_auth_refresh_token token);
+
 /* --- grpc_server_credentials. --- */
 
 typedef struct {
@@ -199,4 +212,103 @@
 grpc_security_status grpc_server_credentials_create_security_connector(
     grpc_server_credentials *creds, grpc_security_connector **sc);
 
+/* -- Ssl credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_credentials;
+
+typedef struct {
+  grpc_server_credentials base;
+  grpc_ssl_server_config config;
+} grpc_ssl_server_credentials;
+
+/* -- Jwt credentials -- */
+
+typedef struct {
+  grpc_credentials base;
+
+  /* Have a simple cache for now with just 1 entry. We could have a map based on
+     the service_url for a more sophisticated one. */
+  gpr_mu cache_mu;
+  struct {
+    grpc_credentials_md_store *jwt_md;
+    char *service_url;
+    gpr_timespec jwt_expiration;
+  } cached;
+
+  grpc_auth_json_key key;
+  gpr_timespec jwt_lifetime;
+} grpc_jwt_credentials;
+
+/* -- Oauth2TokenFetcher credentials --
+
+   This object is a base for credentials that need to acquire an oauth2 token
+   from an http service. */
+
+typedef struct grpc_credentials_metadata_request
+    grpc_credentials_metadata_request;
+
+typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
+                                       grpc_httpcli_context *http_context,
+                                       grpc_pollset *pollset,
+                                       grpc_httpcli_response_cb response_cb,
+                                       gpr_timespec deadline);
+
+typedef struct {
+  grpc_credentials base;
+  gpr_mu mu;
+  grpc_credentials_md_store *access_token_md;
+  gpr_timespec token_expiration;
+  grpc_httpcli_context httpcli_context;
+  grpc_fetch_oauth2_func fetch_func;
+} grpc_oauth2_token_fetcher_credentials;
+
+/* -- ServiceAccount credentials. -- */
+
+typedef struct {
+  grpc_oauth2_token_fetcher_credentials base;
+  grpc_auth_json_key key;
+  char *scope;
+  gpr_timespec token_lifetime;
+} grpc_service_account_credentials;
+
+/* -- RefreshToken credentials. -- */
+
+typedef struct {
+  grpc_oauth2_token_fetcher_credentials base;
+  grpc_auth_refresh_token refresh_token;
+} grpc_refresh_token_credentials;
+
+/* -- Oauth2 Access Token credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_md_store *access_token_md;
+} grpc_access_token_credentials;
+
+/* -- Fake Oauth2 credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_md_store *access_token_md;
+  int is_async;
+} grpc_fake_oauth2_credentials;
+
+/* -- IAM credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_md_store *iam_md;
+} grpc_iam_credentials;
+
+/* -- Composite credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_array inner;
+  grpc_credentials *connector_creds;
+} grpc_composite_credentials;
+
 #endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 5822ce6..cd92f9d 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -46,7 +46,6 @@
 /* -- Constants. -- */
 
 #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
-#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
 
 /* -- Default credentials. -- */
 
@@ -123,36 +122,40 @@
 }
 
 /* Takes ownership of creds_path if not NULL. */
-static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
+static grpc_credentials *create_default_creds_from_path(char *creds_path) {
+  grpc_json *json = NULL;
+  grpc_auth_json_key key;
+  grpc_auth_refresh_token token;
   grpc_credentials *result = NULL;
-  gpr_slice creds_data;
+  gpr_slice creds_data = gpr_empty_slice();
   int file_ok = 0;
-  if (creds_path == NULL) return NULL;
-  creds_data = gpr_load_file(creds_path, 1, &file_ok);
-  gpr_free(creds_path);
-  if (file_ok) {
-    result = grpc_jwt_credentials_create(
-        (const char *)GPR_SLICE_START_PTR(creds_data),
-        grpc_max_auth_token_lifetime);
-    gpr_slice_unref(creds_data);
-  }
-  return result;
-}
+  if (creds_path == NULL) goto end;
+  creds_data = gpr_load_file(creds_path, 0, &file_ok);
+  if (!file_ok) goto end;
+  json = grpc_json_parse_string_with_len(
+      (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data));
+  if (json == NULL) goto end;
 
-/* Takes ownership of creds_path if not NULL. */
-static grpc_credentials *create_refresh_token_creds_from_path(
-    char *creds_path) {
-  grpc_credentials *result = NULL;
-  gpr_slice creds_data;
-  int file_ok = 0;
-  if (creds_path == NULL) return NULL;
-  creds_data = gpr_load_file(creds_path, 1, &file_ok);
-  gpr_free(creds_path);
-  if (file_ok) {
-    result = grpc_refresh_token_credentials_create(
-        (const char *)GPR_SLICE_START_PTR(creds_data));
-    gpr_slice_unref(creds_data);
+  /* First, try an auth json key. */
+  key = grpc_auth_json_key_create_from_json(json);
+  if (grpc_auth_json_key_is_valid(&key)) {
+    result = grpc_jwt_credentials_create_from_auth_json_key(
+        key, grpc_max_auth_token_lifetime);
+    goto end;
   }
+
+  /* Then try a refresh token if the auth json key was invalid. */
+  token = grpc_auth_refresh_token_create_from_json(json);
+  if (grpc_auth_refresh_token_is_valid(&token)) {
+    result =
+        grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
+    goto end;
+  }
+
+end:
+  if (creds_path != NULL) gpr_free(creds_path);
+  gpr_slice_unref(creds_data);
+  if (json != NULL) grpc_json_destroy(json);
   return result;
 }
 
@@ -170,12 +173,12 @@
   }
 
   /* First, try the environment variable. */
-  result =
-      create_jwt_creds_from_path(gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
+  result = create_default_creds_from_path(
+      gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
   if (result != NULL) goto end;
 
   /* Then the well-known file. */
-  result = create_refresh_token_creds_from_path(
+  result = create_default_creds_from_path(
       grpc_get_well_known_google_credentials_file_path());
   if (result != NULL) goto end;
 
@@ -193,11 +196,24 @@
   if (!serving_cached_credentials && result != NULL) {
     /* Blend with default ssl credentials and add a global reference so that it
        can be cached and re-served. */
-    result = grpc_composite_credentials_create(
-        grpc_ssl_credentials_create(NULL, NULL), result);
-    GPR_ASSERT(result != NULL);
-    default_credentials = grpc_credentials_ref(result);
+    grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
+    default_credentials = grpc_credentials_ref(grpc_composite_credentials_create(
+        ssl_creds, result));
+    GPR_ASSERT(default_credentials != NULL);
+    grpc_credentials_unref(ssl_creds);
+    grpc_credentials_unref(result);
+    result = default_credentials;
   }
   gpr_mu_unlock(&g_mu);
   return result;
 }
+
+void grpc_flush_cached_google_default_credentials(void) {
+  gpr_once_init(&g_once, init_default_credentials);
+  gpr_mu_lock(&g_mu);
+  if (default_credentials != NULL) {
+    grpc_credentials_unref(default_credentials);
+    default_credentials = NULL;
+  }
+  gpr_mu_unlock(&g_mu);
+}
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 6116f1d..2e2b980 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -46,17 +46,11 @@
 #include <openssl/evp.h>
 #include <openssl/pem.h>
 
-#include "src/core/json/json.h"
-
 /* --- Constants. --- */
 
 /* 1 hour max. */
 const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
 
-#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
-#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
-#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
-
 #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
 #define GRPC_JWT_TYPE "JWT"
 
@@ -66,7 +60,7 @@
 
 /* --- grpc_auth_json_key. --- */
 
-static const char *json_get_string_property(grpc_json *json,
+static const char *json_get_string_property(const grpc_json *json,
                                             const char *prop_name) {
   grpc_json *child;
   for (child = json->child; child != NULL; child = child->next) {
@@ -79,7 +73,8 @@
   return child->value;
 }
 
-static int set_json_key_string_property(grpc_json *json, const char *prop_name,
+static int set_json_key_string_property(const grpc_json *json,
+                                        const char *prop_name,
                                         char **json_key_field) {
   const char *prop_value = json_get_string_property(json, prop_name);
   if (prop_value == NULL) return 0;
@@ -92,11 +87,8 @@
          strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
 }
 
-grpc_auth_json_key grpc_auth_json_key_create_from_string(
-    const char *json_string) {
+grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) {
   grpc_auth_json_key result;
-  char *scratchpad = gpr_strdup(json_string);
-  grpc_json *json = grpc_json_parse_string(scratchpad);
   BIO *bio = NULL;
   const char *prop_value;
   int success = 0;
@@ -104,7 +96,7 @@
   memset(&result, 0, sizeof(grpc_auth_json_key));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
   if (json == NULL) {
-    gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
+    gpr_log(GPR_ERROR, "Invalid json.");
     goto end;
   }
 
@@ -142,8 +134,16 @@
 
 end:
   if (bio != NULL) BIO_free(bio);
-  if (json != NULL) grpc_json_destroy(json);
   if (!success) grpc_auth_json_key_destruct(&result);
+  return result;
+}
+
+grpc_auth_json_key grpc_auth_json_key_create_from_string(
+    const char *json_string) {
+  char *scratchpad = gpr_strdup(json_string);
+  grpc_json *json = grpc_json_parse_string(scratchpad);
+  grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json);
+  if (json != NULL) grpc_json_destroy(json);
   gpr_free(scratchpad);
   return result;
 }
@@ -342,18 +342,16 @@
          strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
 }
 
-grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
-    const char *json_string) {
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
+    const grpc_json *json) {
   grpc_auth_refresh_token result;
-  char *scratchpad = gpr_strdup(json_string);
-  grpc_json *json = grpc_json_parse_string(scratchpad);
   const char *prop_value;
   int success = 0;
 
   memset(&result, 0, sizeof(grpc_auth_refresh_token));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
   if (json == NULL) {
-    gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
+    gpr_log(GPR_ERROR, "Invalid json.");
     goto end;
   }
 
@@ -374,8 +372,17 @@
   success = 1;
 
 end:
-  if (json != NULL) grpc_json_destroy(json);
   if (!success) grpc_auth_refresh_token_destruct(&result);
+  return result;
+}
+
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
+    const char *json_string) {
+  char *scratchpad = gpr_strdup(json_string);
+  grpc_json *json = grpc_json_parse_string(scratchpad);
+  grpc_auth_refresh_token result =
+      grpc_auth_refresh_token_create_from_json(json);
+  if (json != NULL) grpc_json_destroy(json);
   gpr_free(scratchpad);
   return result;
 }
diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h
index 197796a..091dfef 100644
--- a/src/core/security/json_token.h
+++ b/src/core/security/json_token.h
@@ -37,10 +37,16 @@
 #include <grpc/support/slice.h>
 #include <openssl/rsa.h>
 
+#include "src/core/json/json.h"
+
 /* --- Constants. --- */
 
 #define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token"
 
+#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
+#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
+#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
+
 /* --- auth_json_key parsing. --- */
 
 typedef struct {
@@ -59,6 +65,10 @@
 grpc_auth_json_key grpc_auth_json_key_create_from_string(
     const char *json_string);
 
+/* Creates a json_key object from parsed json. Returns an invalid object if a
+   parsing error has been encountered. */
+grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json);
+
 /* Destructs the object. */
 void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key);
 
@@ -97,6 +107,11 @@
 grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
     const char *json_string);
 
+/* Creates a refresh token object from parsed json. Returns an invalid object if
+   a parsing error has been encountered. */
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
+    const grpc_json *json);
+
 /* Destructs the object. */
 void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
 
diff --git a/src/node/health_check/health.js b/src/node/health_check/health.js
new file mode 100644
index 0000000..87e0019
--- /dev/null
+++ b/src/node/health_check/health.js
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+'use strict';
+
+var grpc = require('../');
+
+var _ = require('lodash');
+
+var health_proto = grpc.load(__dirname + '/health.proto');
+
+var HealthClient = health_proto.grpc.health.v1alpha.Health;
+
+function HealthImplementation(statusMap) {
+  this.statusMap = _.clone(statusMap);
+}
+
+HealthImplementation.prototype.setStatus = function(host, service, status) {
+  if (!this.statusMap[host]) {
+    this.statusMap[host] = {};
+  }
+  this.statusMap[host][service] = status;
+};
+
+HealthImplementation.prototype.check = function(call, callback){
+  var host = call.request.host;
+  var service = call.request.service;
+  var status = _.get(this.statusMap, [host, service], null);
+  if (status === null) {
+    callback({code:grpc.status.NOT_FOUND});
+  } else {
+    callback(null, {status: status});
+  }
+};
+
+module.exports = {
+  Client: HealthClient,
+  service: HealthClient.service,
+  Implementation: HealthImplementation
+};
diff --git a/src/node/health_check/health.proto b/src/node/health_check/health.proto
new file mode 100644
index 0000000..d31df1e
--- /dev/null
+++ b/src/node/health_check/health.proto
@@ -0,0 +1,50 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package grpc.health.v1alpha;
+
+message HealthCheckRequest {
+  string host = 1;
+  string service = 2;
+}
+
+message HealthCheckResponse {
+  enum ServingStatus {
+    UNKNOWN = 0;
+    SERVING = 1;
+    NOT_SERVING = 2;
+  }
+  ServingStatus status = 1;
+}
+
+service Health {
+  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
\ No newline at end of file
diff --git a/src/node/src/server.js b/src/node/src/server.js
index c6cf9e7..9ac428f 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -634,7 +634,8 @@
         }
         var serialize = attrs.responseSerialize;
         var deserialize = attrs.requestDeserialize;
-        server.register(attrs.path, service_handlers[service_name][name],
+        server.register(attrs.path, _.bind(service_handlers[service_name][name],
+                                           service_handlers[service_name]),
                         serialize, deserialize, method_type);
       });
     }, this);
diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js
new file mode 100644
index 0000000..4d1a508
--- /dev/null
+++ b/src/node/test/health_test.js
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+'use strict';
+
+var assert = require('assert');
+
+var health = require('../health_check/health.js');
+
+var grpc = require('../');
+
+describe('Health Checking', function() {
+  var statusMap = {
+    '': {
+      '': 'SERVING',
+      'grpc.test.TestService': 'NOT_SERVING',
+    },
+    virtual_host: {
+      'grpc.test.TestService': 'SERVING'
+    }
+  };
+  var HealthServer = grpc.buildServer([health.service]);
+  var healthServer = new HealthServer({
+    'grpc.health.v1alpha.Health': new health.Implementation(statusMap)
+  });
+  var healthClient;
+  before(function() {
+    var port_num = healthServer.bind('0.0.0.0:0');
+    healthServer.listen();
+    healthClient = new health.Client('localhost:' + port_num);
+  });
+  after(function() {
+    healthServer.shutdown();
+  });
+  it('should say an enabled service is SERVING', function(done) {
+    healthClient.check({service: ''}, function(err, response) {
+      assert.ifError(err);
+      assert.strictEqual(response.status, 'SERVING');
+      done();
+    });
+  });
+  it('should say that a disabled service is NOT_SERVING', function(done) {
+    healthClient.check({service: 'grpc.test.TestService'},
+                       function(err, response) {
+                         assert.ifError(err);
+                         assert.strictEqual(response.status, 'NOT_SERVING');
+                         done();
+                       });
+  });
+  it('should say that a service on another host is SERVING', function(done) {
+    healthClient.check({host: 'virtual_host', service: 'grpc.test.TestService'},
+                       function(err, response) {
+                         assert.ifError(err);
+                         assert.strictEqual(response.status, 'SERVING');
+                         done();
+                       });
+  });
+  it('should get NOT_FOUND if the service is not registered', function(done) {
+    healthClient.check({service: 'not_registered'}, function(err, response) {
+      assert(err);
+      assert.strictEqual(err.code, grpc.status.NOT_FOUND);
+      done();
+    });
+  });
+  it('should get NOT_FOUND if the host is not registered', function(done) {
+    healthClient.check({host: 'wrong_host', service: 'grpc.test.TestService'},
+                       function(err, response) {
+                         assert(err);
+                         assert.strictEqual(err.code, grpc.status.NOT_FOUND);
+                         done();
+                       });
+  });
+});
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index e8bb730..d3fea96 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -37,12 +37,17 @@
 
 #include "src/core/httpcli/httpcli.h"
 #include "src/core/security/json_token.h"
+#include "src/core/support/env.h"
+#include "src/core/support/file.h"
 #include "src/core/support/string.h"
+
+#include "test/core/util/test_config.h"
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include "test/core/util/test_config.h"
+
 #include <openssl/rsa.h>
 
 static const char test_iam_authorization_token[] = "blahblahblhahb";
@@ -868,6 +873,68 @@
   grpc_jwt_encode_and_sign_set_override(NULL);
 }
 
+static void set_google_default_creds_env_var_with_file_contents(
+    const char *file_prefix, const char *contents) {
+  size_t contents_len = strlen(contents);
+  char *creds_file_name;
+  FILE *creds_file = gpr_tmpfile(file_prefix, &creds_file_name);
+  GPR_ASSERT(creds_file_name != NULL);
+  GPR_ASSERT(creds_file != NULL);
+  GPR_ASSERT(fwrite(contents, 1, contents_len, creds_file) == contents_len);
+  fclose(creds_file);
+  gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
+  gpr_free(creds_file_name);
+}
+
+static grpc_credentials *composite_inner_creds(grpc_credentials *creds,
+                                               const char *inner_creds_type) {
+  size_t i;
+  grpc_composite_credentials *composite;
+  GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
+  composite = (grpc_composite_credentials *)creds;
+  for (i = 0; i < composite->inner.num_creds; i++) {
+    grpc_credentials *c = composite->inner.creds_array[i];
+    if (strcmp(c->type, inner_creds_type) == 0) return c;
+  }
+  GPR_ASSERT(0); /* Not found. */
+}
+
+static void test_google_default_creds_auth_key(void) {
+  grpc_jwt_credentials *jwt;
+  grpc_credentials *creds;
+  char *json_key = test_json_key_str();
+  grpc_flush_cached_google_default_credentials();
+  set_google_default_creds_env_var_with_file_contents(
+      "json_key_google_default_creds", json_key);
+  gpr_free(json_key);
+  creds = grpc_google_default_credentials_create();
+  GPR_ASSERT(creds != NULL);
+  jwt = (grpc_jwt_credentials *)composite_inner_creds(
+      creds, GRPC_CREDENTIALS_TYPE_JWT);
+  GPR_ASSERT(
+      strcmp(jwt->key.client_id,
+             "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
+      0);
+  grpc_credentials_unref(creds);
+  gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+}
+
+static void test_google_default_creds_access_token(void) {
+  grpc_refresh_token_credentials *refresh;
+  grpc_credentials *creds;
+  grpc_flush_cached_google_default_credentials();
+  set_google_default_creds_env_var_with_file_contents(
+      "refresh_token_google_default_creds", test_refresh_token_str);
+  creds = grpc_google_default_credentials_create();
+  GPR_ASSERT(creds != NULL);
+  refresh = (grpc_refresh_token_credentials *)composite_inner_creds(
+      creds, GRPC_CREDENTIALS_TYPE_OAUTH2);
+  GPR_ASSERT(strcmp(refresh->refresh_token.client_id,
+                    "32555999999.apps.googleusercontent.com") == 0);
+  grpc_credentials_unref(creds);
+  gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_empty_md_store();
@@ -896,5 +963,7 @@
   test_service_account_creds_signing_failure();
   test_jwt_creds_success();
   test_jwt_creds_signing_failure();
+  test_google_default_creds_auth_key();
+  test_google_default_creds_access_token();
   return 0;
 }
diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc
index 6f8fb8f..a1819dc 100644
--- a/test/cpp/common/secure_auth_context_test.cc
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -59,12 +59,12 @@
 
   SecureAuthContext context(ctx);
   std::vector<grpc::string> peer_identity = context.GetPeerIdentity();
-  EXPECT_EQ(2, peer_identity.size());
+  EXPECT_EQ(2u, peer_identity.size());
   EXPECT_EQ("chapi", peer_identity[0]);
   EXPECT_EQ("chapo", peer_identity[1]);
   EXPECT_EQ("name", context.GetPeerIdentityPropertyName());
   std::vector<grpc::string> bar = context.FindPropertyValues("foo");
-  EXPECT_EQ(1, bar.size());
+  EXPECT_EQ(1u, bar.size());
   EXPECT_EQ("bar", bar[0]);
 }
 
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 0912b19..3791d15 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -88,7 +88,7 @@
   std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
   std::vector<grpc::string> fake =
       auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1, fake.size());
+  EXPECT_EQ(1u, fake.size());
   EXPECT_EQ("fake", fake[0]);
   EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
   EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());