|  | @@ -24,8 +24,8 @@
 | 
	
		
			
				|  |  |  #include <stdlib.h>
 | 
	
		
			
				|  |  |  #include <string.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <grpc/grpc_security.h>
 | 
	
		
			
				|  |  |  #include <grpc/slice.h>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #include <grpc/support/alloc.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/log.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/string_util.h>
 | 
	
	
		
			
				|  | @@ -34,13 +34,16 @@
 | 
	
		
			
				|  |  |  #include "src/core/lib/gpr/env.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/gpr/string.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/gpr/tmpfile.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/gprpp/host_port.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/http/httpcli.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/iomgr/error.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/composite/composite_credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/transport/auth_filters.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/uri/uri_parser.h"
 | 
	
		
			
				|  |  |  #include "test/core/util/test_config.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  using grpc_core::internal::grpc_flush_cached_google_default_credentials;
 | 
	
	
		
			
				|  | @@ -99,15 +102,27 @@ static const char valid_oauth2_json_response[] =
 | 
	
		
			
				|  |  |      " \"expires_in\":3599, "
 | 
	
		
			
				|  |  |      " \"token_type\":\"Bearer\"}";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static const char valid_sts_json_response[] =
 | 
	
		
			
				|  |  | +    "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
 | 
	
		
			
				|  |  | +    " \"expires_in\":3599, "
 | 
	
		
			
				|  |  | +    " \"issued_token_type\":\"urn:ietf:params:oauth:token-type:access_token\", "
 | 
	
		
			
				|  |  | +    " \"token_type\":\"Bearer\"}";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static const char test_scope[] = "perm1 perm2";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static const char test_signed_jwt[] =
 | 
	
		
			
				|  |  |      "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM4YW"
 | 
	
		
			
				|  |  |      "U0MDcyZTViYTdmZDkwODg2YzcifQ";
 | 
	
		
			
				|  |  | +static const char test_signed_jwt_token_type[] =
 | 
	
		
			
				|  |  | +    "urn:ietf:params:oauth:token-type:id_token";
 | 
	
		
			
				|  |  | +static const char test_signed_jwt_path_prefix[] = "test_sign_jwt";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static const char test_service_url[] = "https://foo.com/foo.v1";
 | 
	
		
			
				|  |  |  static const char other_test_service_url[] = "https://bar.com/bar.v1";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static const char test_sts_endpoint_url[] =
 | 
	
		
			
				|  |  | +    "https://foo.com:5555/v1/token-exchange";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static const char test_method[] = "ThisIsNotAMethod";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*  -- Global state flags. -- */
 | 
	
	
		
			
				|  | @@ -657,11 +672,11 @@ static int refresh_token_httpcli_post_success(
 | 
	
		
			
				|  |  |    return 1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static int refresh_token_httpcli_post_failure(
 | 
	
		
			
				|  |  | -    const grpc_httpcli_request* request, const char* body, size_t body_size,
 | 
	
		
			
				|  |  | -    grpc_millis deadline, grpc_closure* on_done,
 | 
	
		
			
				|  |  | -    grpc_httpcli_response* response) {
 | 
	
		
			
				|  |  | -  validate_refresh_token_http_request(request, body, body_size);
 | 
	
		
			
				|  |  | +static int token_httpcli_post_failure(const grpc_httpcli_request* request,
 | 
	
		
			
				|  |  | +                                      const char* body, size_t body_size,
 | 
	
		
			
				|  |  | +                                      grpc_millis deadline,
 | 
	
		
			
				|  |  | +                                      grpc_closure* on_done,
 | 
	
		
			
				|  |  | +                                      grpc_httpcli_response* response) {
 | 
	
		
			
				|  |  |    *response = http_response(403, "Not Authorized.");
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |    return 1;
 | 
	
	
		
			
				|  | @@ -676,7 +691,7 @@ static void test_refresh_token_creds_success(void) {
 | 
	
		
			
				|  |  |    grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
 | 
	
		
			
				|  |  |        test_refresh_token_str, nullptr);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* First request: http get should be called. */
 | 
	
		
			
				|  |  | +  /* First request: http put should be called. */
 | 
	
		
			
				|  |  |    request_metadata_state* state =
 | 
	
		
			
				|  |  |        make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
 | 
	
		
			
				|  |  |    grpc_httpcli_set_override(httpcli_get_should_not_be_called,
 | 
	
	
		
			
				|  | @@ -707,10 +722,279 @@ static void test_refresh_token_creds_failure(void) {
 | 
	
		
			
				|  |  |    grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
 | 
	
		
			
				|  |  |        test_refresh_token_str, nullptr);
 | 
	
		
			
				|  |  |    grpc_httpcli_set_override(httpcli_get_should_not_be_called,
 | 
	
		
			
				|  |  | -                            refresh_token_httpcli_post_failure);
 | 
	
		
			
				|  |  | +                            token_httpcli_post_failure);
 | 
	
		
			
				|  |  | +  run_request_metadata_test(creds, auth_md_ctx, state);
 | 
	
		
			
				|  |  | +  creds->Unref();
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(nullptr, nullptr);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void test_valid_sts_creds_options(void) {
 | 
	
		
			
				|  |  | +  grpc_sts_credentials_options valid_options = {
 | 
	
		
			
				|  |  | +      test_sts_endpoint_url,        // sts_endpoint_url
 | 
	
		
			
				|  |  | +      nullptr,                      // resource
 | 
	
		
			
				|  |  | +      nullptr,                      // audience
 | 
	
		
			
				|  |  | +      nullptr,                      // scope
 | 
	
		
			
				|  |  | +      nullptr,                      // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path_prefix,  // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,   // subject_token_type
 | 
	
		
			
				|  |  | +      nullptr,                      // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                       // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  grpc_uri* sts_url;
 | 
	
		
			
				|  |  | +  grpc_error* error =
 | 
	
		
			
				|  |  | +      grpc_core::ValidateStsCredentialsOptions(&valid_options, &sts_url);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error == GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(sts_url != nullptr);
 | 
	
		
			
				|  |  | +  grpc_core::StringView host;
 | 
	
		
			
				|  |  | +  grpc_core::StringView port;
 | 
	
		
			
				|  |  | +  GPR_ASSERT(grpc_core::SplitHostPort(sts_url->authority, &host, &port));
 | 
	
		
			
				|  |  | +  GPR_ASSERT(host.cmp("foo.com") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(port.cmp("5555") == 0);
 | 
	
		
			
				|  |  | +  grpc_uri_destroy(sts_url);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void test_invalid_sts_creds_options(void) {
 | 
	
		
			
				|  |  | +  grpc_sts_credentials_options invalid_options = {
 | 
	
		
			
				|  |  | +      test_sts_endpoint_url,       // sts_endpoint_url
 | 
	
		
			
				|  |  | +      nullptr,                     // resource
 | 
	
		
			
				|  |  | +      nullptr,                     // audience
 | 
	
		
			
				|  |  | +      nullptr,                     // scope
 | 
	
		
			
				|  |  | +      nullptr,                     // requested_token_type
 | 
	
		
			
				|  |  | +      nullptr,                     // subject_token_path (Required)
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,  // subject_token_type
 | 
	
		
			
				|  |  | +      nullptr,                     // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                      // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  grpc_uri* url_should_be_null;
 | 
	
		
			
				|  |  | +  grpc_error* error = grpc_core::ValidateStsCredentialsOptions(
 | 
	
		
			
				|  |  | +      &invalid_options, &url_should_be_null);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(url_should_be_null == nullptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  invalid_options = {
 | 
	
		
			
				|  |  | +      test_sts_endpoint_url,        // sts_endpoint_url
 | 
	
		
			
				|  |  | +      nullptr,                      // resource
 | 
	
		
			
				|  |  | +      nullptr,                      // audience
 | 
	
		
			
				|  |  | +      nullptr,                      // scope
 | 
	
		
			
				|  |  | +      nullptr,                      // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path_prefix,  // subject_token_path
 | 
	
		
			
				|  |  | +      nullptr,                      // subject_token_type (Required)
 | 
	
		
			
				|  |  | +      nullptr,                      // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                       // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  error = grpc_core::ValidateStsCredentialsOptions(&invalid_options,
 | 
	
		
			
				|  |  | +                                                   &url_should_be_null);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(url_should_be_null == nullptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  invalid_options = {
 | 
	
		
			
				|  |  | +      nullptr,                      // sts_endpoint_url (Required)
 | 
	
		
			
				|  |  | +      nullptr,                      // resource
 | 
	
		
			
				|  |  | +      nullptr,                      // audience
 | 
	
		
			
				|  |  | +      nullptr,                      // scope
 | 
	
		
			
				|  |  | +      nullptr,                      // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path_prefix,  // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,   // subject_token_type (Required)
 | 
	
		
			
				|  |  | +      nullptr,                      // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                       // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  error = grpc_core::ValidateStsCredentialsOptions(&invalid_options,
 | 
	
		
			
				|  |  | +                                                   &url_should_be_null);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(url_should_be_null == nullptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  invalid_options = {
 | 
	
		
			
				|  |  | +      "not_a_valid_uri",            // sts_endpoint_url
 | 
	
		
			
				|  |  | +      nullptr,                      // resource
 | 
	
		
			
				|  |  | +      nullptr,                      // audience
 | 
	
		
			
				|  |  | +      nullptr,                      // scope
 | 
	
		
			
				|  |  | +      nullptr,                      // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path_prefix,  // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,   // subject_token_type (Required)
 | 
	
		
			
				|  |  | +      nullptr,                      // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                       // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  error = grpc_core::ValidateStsCredentialsOptions(&invalid_options,
 | 
	
		
			
				|  |  | +                                                   &url_should_be_null);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(url_should_be_null == nullptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  invalid_options = {
 | 
	
		
			
				|  |  | +      "ftp://ftp.is.not.a.valid.scheme/bar",  // sts_endpoint_url
 | 
	
		
			
				|  |  | +      nullptr,                                // resource
 | 
	
		
			
				|  |  | +      nullptr,                                // audience
 | 
	
		
			
				|  |  | +      nullptr,                                // scope
 | 
	
		
			
				|  |  | +      nullptr,                                // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path_prefix,            // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,             // subject_token_type (Required)
 | 
	
		
			
				|  |  | +      nullptr,                                // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                                 // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  error = grpc_core::ValidateStsCredentialsOptions(&invalid_options,
 | 
	
		
			
				|  |  | +                                                   &url_should_be_null);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(url_should_be_null == nullptr);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void validate_sts_token_http_request(const grpc_httpcli_request* request,
 | 
	
		
			
				|  |  | +                                            const char* body,
 | 
	
		
			
				|  |  | +                                            size_t body_size) {
 | 
	
		
			
				|  |  | +  // Check that the body is constructed properly.
 | 
	
		
			
				|  |  | +  GPR_ASSERT(body != nullptr);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(body_size != 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
 | 
	
		
			
				|  |  | +  char* get_url_equivalent;
 | 
	
		
			
				|  |  | +  gpr_asprintf(&get_url_equivalent, "%s?%s", test_sts_endpoint_url, body);
 | 
	
		
			
				|  |  | +  grpc_uri* url = grpc_uri_parse(get_url_equivalent, false);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(grpc_uri_get_query_arg(url, "resource"), "resource") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(grpc_uri_get_query_arg(url, "audience"), "audience") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(grpc_uri_get_query_arg(url, "scope"), "scope") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(grpc_uri_get_query_arg(url, "requested_token_type"),
 | 
	
		
			
				|  |  | +                    "requested_token_type") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(grpc_uri_get_query_arg(url, "subject_token"),
 | 
	
		
			
				|  |  | +                    test_signed_jwt) == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(grpc_uri_get_query_arg(url, "subject_token_type"),
 | 
	
		
			
				|  |  | +                    test_signed_jwt_token_type) == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(grpc_uri_get_query_arg(url, "actor_token") == nullptr);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(grpc_uri_get_query_arg(url, "actor_token_type") == nullptr);
 | 
	
		
			
				|  |  | +  grpc_uri_destroy(url);
 | 
	
		
			
				|  |  | +  gpr_free(get_url_equivalent);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Check the rest of the request.
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(request->http.path, "/v1/token-exchange") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(request->http.hdr_count == 1);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(strcmp(request->http.hdrs[0].value,
 | 
	
		
			
				|  |  | +                    "application/x-www-form-urlencoded") == 0);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int sts_token_httpcli_post_success(const grpc_httpcli_request* request,
 | 
	
		
			
				|  |  | +                                          const char* body, size_t body_size,
 | 
	
		
			
				|  |  | +                                          grpc_millis deadline,
 | 
	
		
			
				|  |  | +                                          grpc_closure* on_done,
 | 
	
		
			
				|  |  | +                                          grpc_httpcli_response* response) {
 | 
	
		
			
				|  |  | +  validate_sts_token_http_request(request, body, body_size);
 | 
	
		
			
				|  |  | +  *response = http_response(200, valid_sts_json_response);
 | 
	
		
			
				|  |  | +  GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  return 1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static char* write_tmp_jwt_file(void) {
 | 
	
		
			
				|  |  | +  char* path;
 | 
	
		
			
				|  |  | +  FILE* tmp = gpr_tmpfile(test_signed_jwt_path_prefix, &path);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(path != nullptr);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(tmp != nullptr);
 | 
	
		
			
				|  |  | +  size_t jwt_length = strlen(test_signed_jwt);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(fwrite(test_signed_jwt, 1, jwt_length, tmp) == jwt_length);
 | 
	
		
			
				|  |  | +  fclose(tmp);
 | 
	
		
			
				|  |  | +  return path;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void test_sts_creds_success(void) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  expected_md emd[] = {
 | 
	
		
			
				|  |  | +      {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
 | 
	
		
			
				|  |  | +  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
 | 
	
		
			
				|  |  | +                                            nullptr, nullptr};
 | 
	
		
			
				|  |  | +  char* test_signed_jwt_path = write_tmp_jwt_file();
 | 
	
		
			
				|  |  | +  grpc_sts_credentials_options valid_options = {
 | 
	
		
			
				|  |  | +      test_sts_endpoint_url,       // sts_endpoint_url
 | 
	
		
			
				|  |  | +      "resource",                  // resource
 | 
	
		
			
				|  |  | +      "audience",                  // audience
 | 
	
		
			
				|  |  | +      "scope",                     // scope
 | 
	
		
			
				|  |  | +      "requested_token_type",      // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path,        // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,  // subject_token_type
 | 
	
		
			
				|  |  | +      nullptr,                     // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                      // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  grpc_call_credentials* creds =
 | 
	
		
			
				|  |  | +      grpc_sts_credentials_create(&valid_options, nullptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* First request: http put should be called. */
 | 
	
		
			
				|  |  | +  request_metadata_state* state =
 | 
	
		
			
				|  |  | +      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(httpcli_get_should_not_be_called,
 | 
	
		
			
				|  |  | +                            sts_token_httpcli_post_success);
 | 
	
		
			
				|  |  | +  run_request_metadata_test(creds, auth_md_ctx, state);
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx::Get()->Flush();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* Second request: the cached token should be served directly. */
 | 
	
		
			
				|  |  | +  state =
 | 
	
		
			
				|  |  | +      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(httpcli_get_should_not_be_called,
 | 
	
		
			
				|  |  | +                            httpcli_post_should_not_be_called);
 | 
	
		
			
				|  |  | +  run_request_metadata_test(creds, auth_md_ctx, state);
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx::Get()->Flush();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  creds->Unref();
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(nullptr, nullptr);
 | 
	
		
			
				|  |  | +  gpr_free(test_signed_jwt_path);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void test_sts_creds_load_token_failure(void) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  request_metadata_state* state = make_request_metadata_state(
 | 
	
		
			
				|  |  | +      GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +          "Error occurred when fetching oauth2 token."),
 | 
	
		
			
				|  |  | +      nullptr, 0);
 | 
	
		
			
				|  |  | +  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
 | 
	
		
			
				|  |  | +                                            nullptr, nullptr};
 | 
	
		
			
				|  |  | +  char* test_signed_jwt_path = write_tmp_jwt_file();
 | 
	
		
			
				|  |  | +  grpc_sts_credentials_options options = {
 | 
	
		
			
				|  |  | +      test_sts_endpoint_url,       // sts_endpoint_url
 | 
	
		
			
				|  |  | +      "resource",                  // resource
 | 
	
		
			
				|  |  | +      "audience",                  // audience
 | 
	
		
			
				|  |  | +      "scope",                     // scope
 | 
	
		
			
				|  |  | +      "requested_token_type",      // requested_token_type
 | 
	
		
			
				|  |  | +      "invalid_path",              // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,  // subject_token_type
 | 
	
		
			
				|  |  | +      nullptr,                     // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                      // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  grpc_call_credentials* creds = grpc_sts_credentials_create(&options, nullptr);
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(httpcli_get_should_not_be_called,
 | 
	
		
			
				|  |  | +                            httpcli_post_should_not_be_called);
 | 
	
		
			
				|  |  | +  run_request_metadata_test(creds, auth_md_ctx, state);
 | 
	
		
			
				|  |  | +  creds->Unref();
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(nullptr, nullptr);
 | 
	
		
			
				|  |  | +  gpr_free(test_signed_jwt_path);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void test_sts_creds_http_failure(void) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  request_metadata_state* state = make_request_metadata_state(
 | 
	
		
			
				|  |  | +      GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +          "Error occurred when fetching oauth2 token."),
 | 
	
		
			
				|  |  | +      nullptr, 0);
 | 
	
		
			
				|  |  | +  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
 | 
	
		
			
				|  |  | +                                            nullptr, nullptr};
 | 
	
		
			
				|  |  | +  char* test_signed_jwt_path = write_tmp_jwt_file();
 | 
	
		
			
				|  |  | +  grpc_sts_credentials_options valid_options = {
 | 
	
		
			
				|  |  | +      test_sts_endpoint_url,       // sts_endpoint_url
 | 
	
		
			
				|  |  | +      "resource",                  // resource
 | 
	
		
			
				|  |  | +      "audience",                  // audience
 | 
	
		
			
				|  |  | +      "scope",                     // scope
 | 
	
		
			
				|  |  | +      "requested_token_type",      // requested_token_type
 | 
	
		
			
				|  |  | +      test_signed_jwt_path,        // subject_token_path
 | 
	
		
			
				|  |  | +      test_signed_jwt_token_type,  // subject_token_type
 | 
	
		
			
				|  |  | +      nullptr,                     // actor_token_path
 | 
	
		
			
				|  |  | +      nullptr                      // actor_token_type
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  grpc_call_credentials* creds =
 | 
	
		
			
				|  |  | +      grpc_sts_credentials_create(&valid_options, nullptr);
 | 
	
		
			
				|  |  | +  grpc_httpcli_set_override(httpcli_get_should_not_be_called,
 | 
	
		
			
				|  |  | +                            token_httpcli_post_failure);
 | 
	
		
			
				|  |  |    run_request_metadata_test(creds, auth_md_ctx, state);
 | 
	
		
			
				|  |  |    creds->Unref();
 | 
	
		
			
				|  |  |    grpc_httpcli_set_override(nullptr, nullptr);
 | 
	
		
			
				|  |  | +  gpr_free(test_signed_jwt_path);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void validate_jwt_encode_and_sign_params(
 | 
	
	
		
			
				|  | @@ -1288,6 +1572,11 @@ int main(int argc, char** argv) {
 | 
	
		
			
				|  |  |    test_compute_engine_creds_failure();
 | 
	
		
			
				|  |  |    test_refresh_token_creds_success();
 | 
	
		
			
				|  |  |    test_refresh_token_creds_failure();
 | 
	
		
			
				|  |  | +  test_valid_sts_creds_options();
 | 
	
		
			
				|  |  | +  test_invalid_sts_creds_options();
 | 
	
		
			
				|  |  | +  test_sts_creds_success();
 | 
	
		
			
				|  |  | +  test_sts_creds_load_token_failure();
 | 
	
		
			
				|  |  | +  test_sts_creds_http_failure();
 | 
	
		
			
				|  |  |    test_jwt_creds_lifetime();
 | 
	
		
			
				|  |  |    test_jwt_creds_success();
 | 
	
		
			
				|  |  |    test_jwt_creds_signing_failure();
 |