diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/core/security/credentials_test.c | 22 | ||||
-rw-r--r-- | test/core/security/jwt_verifier_test.c | 565 | ||||
-rw-r--r-- | test/core/security/print_google_default_creds_token.c | 4 | ||||
-rw-r--r-- | test/core/security/verify_jwt.c | 119 | ||||
-rw-r--r-- | test/core/transport/chttp2/hpack_parser_test.c | 2 | ||||
-rw-r--r-- | test/core/transport/chttp2/hpack_table_test.c | 2 | ||||
-rw-r--r-- | test/core/transport/chttp2/stream_encoder_test.c | 2 | ||||
-rw-r--r-- | test/core/transport/metadata_test.c | 38 | ||||
-rw-r--r-- | test/cpp/end2end/end2end_test.cc | 27 | ||||
-rw-r--r-- | test/cpp/util/messages.proto | 1 |
10 files changed, 756 insertions, 26 deletions
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index 4253be6b07..e8bb730849 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -331,6 +331,27 @@ static void test_iam_creds(void) { check_iam_metadata, creds); } +static void check_access_token_metadata(void *user_data, + grpc_credentials_md *md_elems, + size_t num_md, + grpc_credentials_status status) { + grpc_credentials *c = (grpc_credentials *)user_data; + expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}}; + GPR_ASSERT(status == GRPC_CREDENTIALS_OK); + GPR_ASSERT(num_md == 1); + check_metadata(emd, md_elems, num_md); + grpc_credentials_unref(c); +} + +static void test_access_token_creds(void) { + grpc_credentials *creds = grpc_access_token_credentials_create("blah"); + GPR_ASSERT(grpc_credentials_has_request_metadata(creds)); + GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds)); + GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_OAUTH2) == 0); + grpc_credentials_get_request_metadata(creds, NULL, test_service_url, + check_access_token_metadata, creds); +} + static void check_ssl_oauth2_composite_metadata( void *user_data, grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { @@ -863,6 +884,7 @@ int main(int argc, char **argv) { test_oauth2_token_fetcher_creds_parsing_missing_token_type(); test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime(); test_iam_creds(); + test_access_token_creds(); test_ssl_oauth2_composite_creds(); test_ssl_oauth2_iam_composite_creds(); test_compute_engine_creds_success(); diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c new file mode 100644 index 0000000000..46b96d9ecb --- /dev/null +++ b/test/core/security/jwt_verifier_test.c @@ -0,0 +1,565 @@ +/* + * + * 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. + * + */ + +#include "src/core/security/jwt_verifier.h" + +#include <string.h> + +#include "src/core/httpcli/httpcli.h" +#include "src/core/security/base64.h" +#include "src/core/security/json_token.h" +#include "test/core/util/test_config.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/slice.h> +#include <grpc/support/string_util.h> + +/* This JSON key was generated with the GCE console and revoked immediately. + The identifiers have been changed as well. + Maximum size for a string literal is 509 chars in C89, yay! */ +static const char json_key_str_part1[] = + "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----" + "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE" + "qg" + "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/" + "rWBQvS4hle4LfijkP3J5BG+" + "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+" + "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/" + "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/" + "8HpCqFYM9V8f34SBWfD4fRFT+n/" + "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+"; +static const char json_key_str_part2[] = + "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+" + "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/" + "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA" + "G" + "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz" + "A" + "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+" + "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/" + "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ" + "Y" + "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", "; +static const char json_key_str_part3_for_google_email_issuer[] = + "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", " + "\"client_email\": " + "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount." + "com\", \"client_id\": " + "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent." + "com\", \"type\": \"service_account\" }"; +/* Trick our JWT library into issuing a JWT with iss=accounts.google.com. */ +static const char json_key_str_part3_for_url_issuer[] = + "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", " + "\"client_email\": \"accounts.google.com\", " + "\"client_id\": " + "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent." + "com\", \"type\": \"service_account\" }"; +static const char json_key_str_part3_for_custom_email_issuer[] = + "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", " + "\"client_email\": " + "\"foo@bar.com\", \"client_id\": " + "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent." + "com\", \"type\": \"service_account\" }"; + +static grpc_jwt_verifier_email_domain_key_url_mapping custom_mapping = { + "bar.com", "keys.bar.com/jwk" +}; + +static const char expected_user_data[] = "user data"; + +static const char good_jwk_set[] = + "{" + " \"keys\": [" + " {" + " \"kty\": \"RSA\"," + " \"alg\": \"RS256\"," + " \"use\": \"sig\"," + " \"kid\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\"," + " \"n\": " + "\"4S8myegefIeRdynuYkSqBYaOLDvU19cHKC56RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ6mxP" + "QutZC1nKNJ6D-tYFC9LiGV7gt-KOQ_cnkEb4hcMw_xF_OI1FCx6cBcM0-" + "RjiQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFU=\"," + " \"e\": \"AQAB\"" + " }" + " ]" + "}"; + +static gpr_timespec expected_lifetime = {3600, 0}; + +static const char good_google_email_keys_part1[] = + "{\"e6b5137873db8d2ef81e06a47289e6434ec8a165\": \"-----BEGIN " + "CERTIFICATE-----" + "\\nMIICATCCAWoCCQDEywLhxvHjnDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB\\nVTET" + "MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\\ncyBQdHkgTHR" + "kMB4XDTE1MDYyOTA4Mzk1MFoXDTI1MDYyNjA4Mzk1MFowRTELMAkG\\nA1UEBhMCQVUxEzARBg" + "NVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\\nIFdpZGdpdHMgUHR5IEx0ZDCBn" + "zANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4S8m\\nyegefIeRdynuYkSqBYaOLDvU19cHKC56" + "RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ\\n6mxPQutZC1nKNJ6D+tYFC9LiGV7gt+KOQ/"; + +static const char good_google_email_keys_part2[] = + "cnkEb4hcMw/xF/OI1FCx6cBcM0+" + "Rji\\nQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFUCAwEAATANBgkqhkiG9w0BAQsF\\nA" + "AOBgQBfu69FkPmBknbKNFgurPz78kbs3VNN+k/" + "PUgO5DHKskJmgK2TbtvX2VMpx\\nkftmHGzgzMzUlOtigCaGMgHWjfqjpP9uuDbahXrZBJzB8c" + "Oq7MrQF8r17qVvo3Ue\\nPjTKQMAsU8uxTEMmeuz9L6yExs0rfd6bPOrQkAoVfFfiYB3/" + "pA==\\n-----END CERTIFICATE-----\\n\"}"; + +static const char expected_audience[] = "https://foo.com"; + +static const char good_openid_config[] = + "{" + " \"issuer\": \"https://accounts.google.com\"," + " \"authorization_endpoint\": " + "\"https://accounts.google.com/o/oauth2/v2/auth\"," + " \"token_endpoint\": \"https://www.googleapis.com/oauth2/v4/token\"," + " \"userinfo_endpoint\": \"https://www.googleapis.com/oauth2/v3/userinfo\"," + " \"revocation_endpoint\": \"https://accounts.google.com/o/oauth2/revoke\"," + " \"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\"" + "}"; + +static const char expired_claims[] = + "{ \"aud\": \"https://foo.com\"," + " \"iss\": \"blah.foo.com\"," + " \"sub\": \"juju@blah.foo.com\"," + " \"jti\": \"jwtuniqueid\"," + " \"iat\": 100," /* Way back in the past... */ + " \"exp\": 120," + " \"nbf\": 60," + " \"foo\": \"bar\"}"; + +static const char claims_without_time_constraint[] = + "{ \"aud\": \"https://foo.com\"," + " \"iss\": \"blah.foo.com\"," + " \"sub\": \"juju@blah.foo.com\"," + " \"jti\": \"jwtuniqueid\"," + " \"foo\": \"bar\"}"; + +static const char invalid_claims[] = + "{ \"aud\": \"https://foo.com\"," + " \"iss\": 46," /* Issuer cannot be a number. */ + " \"sub\": \"juju@blah.foo.com\"," + " \"jti\": \"jwtuniqueid\"," + " \"foo\": \"bar\"}"; + +typedef struct { + grpc_jwt_verifier_status expected_status; + const char *expected_issuer; + const char *expected_subject; +} verifier_test_config; + +static void test_claims_success(void) { + grpc_jwt_claims *claims; + gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint); + grpc_json *json = grpc_json_parse_string_with_len( + (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); + GPR_ASSERT(json != NULL); + claims = grpc_jwt_claims_from_json(json, s); + GPR_ASSERT(claims != NULL); + GPR_ASSERT(grpc_jwt_claims_json(claims) == json); + GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0); + GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0); + GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "juju@blah.foo.com") == 0); + GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0); + GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") == + GRPC_JWT_VERIFIER_OK); + grpc_jwt_claims_destroy(claims); +} + +static void test_expired_claims_failure(void) { + grpc_jwt_claims *claims; + gpr_slice s = gpr_slice_from_copied_string(expired_claims); + grpc_json *json = grpc_json_parse_string_with_len( + (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); + gpr_timespec exp_iat = {100, 0}; + gpr_timespec exp_exp = {120, 0}; + gpr_timespec exp_nbf = {60, 0}; + GPR_ASSERT(json != NULL); + claims = grpc_jwt_claims_from_json(json, s); + GPR_ASSERT(claims != NULL); + GPR_ASSERT(grpc_jwt_claims_json(claims) == json); + GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0); + GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0); + GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "juju@blah.foo.com") == 0); + GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0); + GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_issued_at(claims), exp_iat) == 0); + GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_expires_at(claims), exp_exp) == 0); + GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_not_before(claims), exp_nbf) == 0); + + GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") == + GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE); + grpc_jwt_claims_destroy(claims); +} + +static void test_invalid_claims_failure(void) { + gpr_slice s = gpr_slice_from_copied_string(invalid_claims); + grpc_json *json = grpc_json_parse_string_with_len( + (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); + GPR_ASSERT(grpc_jwt_claims_from_json(json, s) == NULL); +} + +static void test_bad_audience_claims_failure(void) { + grpc_jwt_claims *claims; + gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint); + grpc_json *json = grpc_json_parse_string_with_len( + (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); + GPR_ASSERT(json != NULL); + claims = grpc_jwt_claims_from_json(json, s); + GPR_ASSERT(claims != NULL); + GPR_ASSERT(grpc_jwt_claims_check(claims, "https://bar.com") == + GRPC_JWT_VERIFIER_BAD_AUDIENCE); + grpc_jwt_claims_destroy(claims); +} + +static char *json_key_str(const char *last_part) { + size_t result_len = strlen(json_key_str_part1) + strlen(json_key_str_part2) + + strlen(last_part); + char *result = gpr_malloc(result_len + 1); + char *current = result; + strcpy(result, json_key_str_part1); + current += strlen(json_key_str_part1); + strcpy(current, json_key_str_part2); + current += strlen(json_key_str_part2); + strcpy(current, last_part); + return result; +} + +static char *good_google_email_keys(void) { + size_t result_len = strlen(good_google_email_keys_part1) + + strlen(good_google_email_keys_part2); + char *result = gpr_malloc(result_len + 1); + char *current = result; + strcpy(result, good_google_email_keys_part1); + current += strlen(good_google_email_keys_part1); + strcpy(current, good_google_email_keys_part2); + return result; +} + +static grpc_httpcli_response http_response(int status, char *body) { + grpc_httpcli_response response; + memset(&response, 0, sizeof(grpc_httpcli_response)); + response.status = status; + response.body = body; + response.body_length = strlen(body); + return response; +} + +static int httpcli_post_should_not_be_called( + const grpc_httpcli_request *request, const char *body_bytes, + size_t body_size, gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + GPR_ASSERT("HTTP POST should not be called" == NULL); + return 1; +} + +static int httpcli_get_google_keys_for_email( + const grpc_httpcli_request *request, gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + grpc_httpcli_response response = http_response(200, good_google_email_keys()); + GPR_ASSERT(request->use_ssl); + GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0); + GPR_ASSERT(strcmp(request->path, + "/robot/v1/metadata/x509/" + "777-abaslkan11hlb6nmim3bpspl31ud@developer." + "gserviceaccount.com") == 0); + on_response(user_data, &response); + gpr_free(response.body); + return 1; +} + +static void on_verification_success(void *user_data, + grpc_jwt_verifier_status status, + grpc_jwt_claims *claims) { + GPR_ASSERT(status == GRPC_JWT_VERIFIER_OK); + GPR_ASSERT(claims != NULL); + GPR_ASSERT(user_data == (void *)expected_user_data); + GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), expected_audience) == 0); + grpc_jwt_claims_destroy(claims); +} + +static void test_jwt_verifier_google_email_issuer_success(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0); + char *jwt = NULL; + char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer); + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); + gpr_free(key_str); + GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); + grpc_httpcli_set_override(httpcli_get_google_keys_for_email, + httpcli_post_should_not_be_called); + jwt = + grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL); + grpc_auth_json_key_destruct(&key); + GPR_ASSERT(jwt != NULL); + grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience, + on_verification_success, (void *)expected_user_data); + gpr_free(jwt); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +static int httpcli_get_custom_keys_for_email( + const grpc_httpcli_request *request, gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set)); + GPR_ASSERT(request->use_ssl); + GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0); + GPR_ASSERT(strcmp(request->path, "/jwk/foo@bar.com") == 0); + on_response(user_data, &response); + gpr_free(response.body); + return 1; +} + +static void test_jwt_verifier_custom_email_issuer_success(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(&custom_mapping, 1); + char *jwt = NULL; + char *key_str = json_key_str(json_key_str_part3_for_custom_email_issuer); + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); + gpr_free(key_str); + GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); + grpc_httpcli_set_override(httpcli_get_custom_keys_for_email, + httpcli_post_should_not_be_called); + jwt = + grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL); + grpc_auth_json_key_destruct(&key); + GPR_ASSERT(jwt != NULL); + grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience, + on_verification_success, (void *)expected_user_data); + gpr_free(jwt); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +static int httpcli_get_jwk_set( + const grpc_httpcli_request *request, gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set)); + GPR_ASSERT(request->use_ssl); + GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0); + GPR_ASSERT(strcmp(request->path, "/oauth2/v3/certs") == 0); + on_response(user_data, &response); + gpr_free(response.body); + return 1; +} + +static int httpcli_get_openid_config(const grpc_httpcli_request *request, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, + void *user_data) { + grpc_httpcli_response response = + http_response(200, gpr_strdup(good_openid_config)); + GPR_ASSERT(request->use_ssl); + GPR_ASSERT(strcmp(request->host, "accounts.google.com") == 0); + GPR_ASSERT(strcmp(request->path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0); + grpc_httpcli_set_override(httpcli_get_jwk_set, + httpcli_post_should_not_be_called); + on_response(user_data, &response); + gpr_free(response.body); + return 1; +} + +static void test_jwt_verifier_url_issuer_success(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0); + char *jwt = NULL; + char *key_str = json_key_str(json_key_str_part3_for_url_issuer); + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); + gpr_free(key_str); + GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); + grpc_httpcli_set_override(httpcli_get_openid_config, + httpcli_post_should_not_be_called); + jwt = + grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL); + grpc_auth_json_key_destruct(&key); + GPR_ASSERT(jwt != NULL); + grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience, + on_verification_success, (void *)expected_user_data); + gpr_free(jwt); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +static void on_verification_key_retrieval_error(void *user_data, + grpc_jwt_verifier_status status, + grpc_jwt_claims *claims) { + GPR_ASSERT(status == GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR); + GPR_ASSERT(claims == NULL); + GPR_ASSERT(user_data == (void *)expected_user_data); +} + +static int httpcli_get_bad_json(const grpc_httpcli_request *request, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, + void *user_data) { + grpc_httpcli_response response = + http_response(200, gpr_strdup("{\"bad\": \"stuff\"}")); + GPR_ASSERT(request->use_ssl); + on_response(user_data, &response); + gpr_free(response.body); + return 1; +} + +static void test_jwt_verifier_url_issuer_bad_config(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0); + char *jwt = NULL; + char *key_str = json_key_str(json_key_str_part3_for_url_issuer); + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); + gpr_free(key_str); + GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); + grpc_httpcli_set_override(httpcli_get_bad_json, + httpcli_post_should_not_be_called); + jwt = + grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL); + grpc_auth_json_key_destruct(&key); + GPR_ASSERT(jwt != NULL); + grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience, + on_verification_key_retrieval_error, + (void *)expected_user_data); + gpr_free(jwt); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +static void test_jwt_verifier_bad_json_key(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0); + char *jwt = NULL; + char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer); + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); + gpr_free(key_str); + GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); + grpc_httpcli_set_override(httpcli_get_bad_json, + httpcli_post_should_not_be_called); + jwt = + grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL); + grpc_auth_json_key_destruct(&key); + GPR_ASSERT(jwt != NULL); + grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience, + on_verification_key_retrieval_error, + (void *)expected_user_data); + gpr_free(jwt); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +static void corrupt_jwt_sig(char *jwt) { + gpr_slice sig; + char *bad_b64_sig; + gpr_uint8 *sig_bytes; + char *last_dot = strrchr(jwt, '.'); + GPR_ASSERT(last_dot != NULL); + sig = grpc_base64_decode(last_dot + 1, 1); + GPR_ASSERT(!GPR_SLICE_IS_EMPTY(sig)); + sig_bytes = GPR_SLICE_START_PTR(sig); + (*sig_bytes)++; /* Corrupt first byte. */ + bad_b64_sig = + grpc_base64_encode(GPR_SLICE_START_PTR(sig), GPR_SLICE_LENGTH(sig), 1, 0); + memcpy(last_dot + 1, bad_b64_sig, strlen(bad_b64_sig)); + gpr_free(bad_b64_sig); + gpr_slice_unref(sig); +} + +static void on_verification_bad_signature(void *user_data, + grpc_jwt_verifier_status status, + grpc_jwt_claims *claims) { + GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_SIGNATURE); + GPR_ASSERT(claims == NULL); + GPR_ASSERT(user_data == (void *)expected_user_data); +} + +static void test_jwt_verifier_bad_signature(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0); + char *jwt = NULL; + char *key_str = json_key_str(json_key_str_part3_for_url_issuer); + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); + gpr_free(key_str); + GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); + grpc_httpcli_set_override(httpcli_get_openid_config, + httpcli_post_should_not_be_called); + jwt = + grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL); + grpc_auth_json_key_destruct(&key); + corrupt_jwt_sig(jwt); + GPR_ASSERT(jwt != NULL); + grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience, + on_verification_bad_signature, + (void *)expected_user_data); + gpr_free(jwt); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +static int httpcli_get_should_not_be_called( + const grpc_httpcli_request *request, gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + GPR_ASSERT(0); + return 1; +} + +static void on_verification_bad_format(void *user_data, + grpc_jwt_verifier_status status, + grpc_jwt_claims *claims) { + GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_FORMAT); + GPR_ASSERT(claims == NULL); + GPR_ASSERT(user_data == (void *)expected_user_data); +} + +static void test_jwt_verifier_bad_format(void) { + grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0); + grpc_httpcli_set_override(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); + grpc_jwt_verifier_verify(verifier, NULL, "bad jwt", expected_audience, + on_verification_bad_format, + (void *)expected_user_data); + grpc_jwt_verifier_destroy(verifier); + grpc_httpcli_set_override(NULL, NULL); +} + +/* find verification key: bad jks, cannot find key in jks */ +/* bad signature custom provided email*/ +/* bad key */ + + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + test_claims_success(); + test_expired_claims_failure(); + test_invalid_claims_failure(); + test_bad_audience_claims_failure(); + test_jwt_verifier_google_email_issuer_success(); + test_jwt_verifier_custom_email_issuer_success(); + test_jwt_verifier_url_issuer_success(); + test_jwt_verifier_url_issuer_bad_config(); + test_jwt_verifier_bad_json_key(); + test_jwt_verifier_bad_signature(); + test_jwt_verifier_bad_format(); + return 0; +} + diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c index 73283c2fbd..5b55a4da13 100644 --- a/test/core/security/print_google_default_creds_token.c +++ b/test/core/security/print_google_default_creds_token.c @@ -91,13 +91,13 @@ int main(int argc, char **argv) { grpc_pollset_init(&sync.pollset); sync.is_done = 0; - grpc_credentials_get_request_metadata(creds, &sync.pollset, "", on_metadata_response, &sync); + grpc_credentials_get_request_metadata(creds, &sync.pollset, service_url, + on_metadata_response, &sync); gpr_mu_lock(GRPC_POLLSET_MU(&sync.pollset)); while (!sync.is_done) grpc_pollset_work(&sync.pollset, gpr_inf_future); gpr_mu_unlock(GRPC_POLLSET_MU(&sync.pollset)); - grpc_pollset_destroy(&sync.pollset); grpc_credentials_release(creds); end: diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c new file mode 100644 index 0000000000..e90be5de98 --- /dev/null +++ b/test/core/security/verify_jwt.c @@ -0,0 +1,119 @@ +/* + * + * 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. + * + */ + +#include <stdio.h> +#include <string.h> + +#include "src/core/security/jwt_verifier.h" +#include <grpc/grpc.h> +#include <grpc/grpc_security.h> +#include <grpc/support/alloc.h> +#include <grpc/support/cmdline.h> +#include <grpc/support/log.h> +#include <grpc/support/slice.h> +#include <grpc/support/sync.h> + +typedef struct { + grpc_pollset pollset; + int is_done; + int success; +} synchronizer; + +static void print_usage_and_exit(gpr_cmdline *cl, const char *argv0) { + char *usage = gpr_cmdline_usage_string(cl, argv0); + fprintf(stderr, "%s", usage); + gpr_free(usage); + gpr_cmdline_destroy(cl); + exit(1); +} + +static void on_jwt_verification_done(void *user_data, + grpc_jwt_verifier_status status, + grpc_jwt_claims *claims) { + synchronizer *sync = user_data; + + sync->success = (status == GRPC_JWT_VERIFIER_OK); + if (sync->success) { + char *claims_str; + GPR_ASSERT(claims != NULL); + claims_str = + grpc_json_dump_to_string((grpc_json *)grpc_jwt_claims_json(claims), 2); + printf("Claims: \n\n%s\n", claims_str); + gpr_free(claims_str); + grpc_jwt_claims_destroy(claims); + } else { + GPR_ASSERT(claims == NULL); + fprintf(stderr, "Verification failed with error %s\n", + grpc_jwt_verifier_status_to_string(status)); + } + + gpr_mu_lock(GRPC_POLLSET_MU(&sync->pollset)); + sync->is_done = 1; + grpc_pollset_kick(&sync->pollset); + gpr_mu_unlock(GRPC_POLLSET_MU(&sync->pollset)); +} + +int main(int argc, char **argv) { + synchronizer sync; + grpc_jwt_verifier *verifier; + gpr_cmdline *cl; + char *jwt = NULL; + char *aud = NULL; + + cl = gpr_cmdline_create("JWT verifier tool"); + gpr_cmdline_add_string(cl, "jwt", "JSON web token to verify", &jwt); + gpr_cmdline_add_string(cl, "aud", "Audience for the JWT", &aud); + gpr_cmdline_parse(cl, argc, argv); + if (jwt == NULL || aud == NULL) { + print_usage_and_exit(cl, argv[0]); + } + + verifier = grpc_jwt_verifier_create(NULL, 0); + + grpc_init(); + + grpc_pollset_init(&sync.pollset); + sync.is_done = 0; + + grpc_jwt_verifier_verify(verifier, &sync.pollset, jwt, aud, + on_jwt_verification_done, &sync); + + gpr_mu_lock(GRPC_POLLSET_MU(&sync.pollset)); + while (!sync.is_done) grpc_pollset_work(&sync.pollset, gpr_inf_future); + gpr_mu_unlock(GRPC_POLLSET_MU(&sync.pollset)); + + grpc_jwt_verifier_destroy(verifier); + gpr_cmdline_destroy(cl); + return !sync.success; +} + diff --git a/test/core/transport/chttp2/hpack_parser_test.c b/test/core/transport/chttp2/hpack_parser_test.c index 1d6ad2a758..3a313375a4 100644 --- a/test/core/transport/chttp2/hpack_parser_test.c +++ b/test/core/transport/chttp2/hpack_parser_test.c @@ -53,7 +53,7 @@ static void onhdr(void *ud, grpc_mdelem *md) { GPR_ASSERT(evalue); GPR_ASSERT(gpr_slice_str_cmp(md->key->slice, ekey) == 0); GPR_ASSERT(gpr_slice_str_cmp(md->value->slice, evalue) == 0); - grpc_mdelem_unref(md); + GRPC_MDELEM_UNREF(md); } static void test_vector(grpc_chttp2_hpack_parser *parser, diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c index 8b86e08168..15b37d17b6 100644 --- a/test/core/transport/chttp2/hpack_table_test.c +++ b/test/core/transport/chttp2/hpack_table_test.c @@ -167,7 +167,7 @@ static grpc_chttp2_hptbl_find_result find_simple(grpc_chttp2_hptbl *tbl, const char *value) { grpc_mdelem *md = grpc_mdelem_from_strings(tbl->mdctx, key, value); grpc_chttp2_hptbl_find_result r = grpc_chttp2_hptbl_find(tbl, md); - grpc_mdelem_unref(md); + GRPC_MDELEM_UNREF(md); return r; } diff --git a/test/core/transport/chttp2/stream_encoder_test.c b/test/core/transport/chttp2/stream_encoder_test.c index 6f2ea274fe..e6731ff195 100644 --- a/test/core/transport/chttp2/stream_encoder_test.c +++ b/test/core/transport/chttp2/stream_encoder_test.c @@ -262,7 +262,7 @@ static void chk_hdr(void *p, grpc_mdelem *el) { GPR_ASSERT(0 == gpr_slice_str_cmp(el->key->slice, st->key)); GPR_ASSERT(0 == gpr_slice_str_cmp(el->value->slice, st->value)); st->got_hdr = 1; - grpc_mdelem_unref(el); + GRPC_MDELEM_UNREF(el); } static void test_decode_random_headers_inner(int max_len) { diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c index 89deee5a40..a932e04f33 100644 --- a/test/core/transport/metadata_test.c +++ b/test/core/transport/metadata_test.c @@ -70,10 +70,10 @@ static void test_create_string(void) { GPR_ASSERT(s3 != s1); GPR_ASSERT(gpr_slice_str_cmp(s1->slice, "hello") == 0); GPR_ASSERT(gpr_slice_str_cmp(s3->slice, "very much not hello") == 0); - grpc_mdstr_unref(s1); - grpc_mdstr_unref(s2); + GRPC_MDSTR_UNREF(s1); + GRPC_MDSTR_UNREF(s2); grpc_mdctx_unref(ctx); - grpc_mdstr_unref(s3); + GRPC_MDSTR_UNREF(s3); } static void test_create_metadata(void) { @@ -93,9 +93,9 @@ static void test_create_metadata(void) { GPR_ASSERT(gpr_slice_str_cmp(m1->key->slice, "a") == 0); GPR_ASSERT(gpr_slice_str_cmp(m1->value->slice, "b") == 0); GPR_ASSERT(gpr_slice_str_cmp(m3->value->slice, "c") == 0); - grpc_mdelem_unref(m1); - grpc_mdelem_unref(m2); - grpc_mdelem_unref(m3); + GRPC_MDELEM_UNREF(m1); + GRPC_MDELEM_UNREF(m2); + GRPC_MDELEM_UNREF(m3); grpc_mdctx_unref(ctx); } @@ -112,7 +112,7 @@ static void test_create_many_ephemeral_metadata(void) { /* add, and immediately delete a bunch of different elements */ for (i = 0; i < MANY; i++) { gpr_ltoa(i, buffer); - grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", buffer)); + GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", buffer)); } /* capacity should not grow */ GPR_ASSERT(mdtab_capacity_before == @@ -140,11 +140,11 @@ static void test_create_many_persistant_metadata(void) { gpr_ltoa(i, buffer); md = grpc_mdelem_from_strings(ctx, "a", buffer); GPR_ASSERT(md == created[i]); - grpc_mdelem_unref(md); + GRPC_MDELEM_UNREF(md); } /* cleanup phase */ for (i = 0; i < MANY; i++) { - grpc_mdelem_unref(created[i]); + GRPC_MDELEM_UNREF(created[i]); } grpc_mdctx_unref(ctx); @@ -160,15 +160,15 @@ static void test_spin_creating_the_same_thing(void) { GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 0); GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 0); - grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b")); + GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", "b")); GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1); GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1); - grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b")); + GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", "b")); GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1); GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1); - grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b")); + GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", "b")); GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1); GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1); @@ -196,8 +196,8 @@ static void test_things_stick_around(void) { } for (i = 0; i < nstrs; i++) { - grpc_mdstr_ref(strs[i]); - grpc_mdstr_unref(strs[i]); + GRPC_MDSTR_REF(strs[i]); + GRPC_MDSTR_UNREF(strs[i]); } for (i = 0; i < nstrs; i++) { @@ -209,12 +209,12 @@ static void test_things_stick_around(void) { } for (i = 0; i < nstrs; i++) { - grpc_mdstr_unref(strs[shuf[i]]); + GRPC_MDSTR_UNREF(strs[shuf[i]]); for (j = i + 1; j < nstrs; j++) { gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]); test = grpc_mdstr_from_string(ctx, buffer); GPR_ASSERT(test == strs[shuf[j]]); - grpc_mdstr_unref(test); + GRPC_MDSTR_UNREF(test); gpr_free(buffer); } } @@ -237,14 +237,14 @@ static void test_slices_work(void) { str = grpc_mdstr_from_string( ctx, "123456789012345678901234567890123456789012345678901234567890"); slice = gpr_slice_ref(str->slice); - grpc_mdstr_unref(str); + GRPC_MDSTR_UNREF(str); gpr_slice_unref(slice); str = grpc_mdstr_from_string( ctx, "123456789012345678901234567890123456789012345678901234567890"); slice = gpr_slice_ref(str->slice); gpr_slice_unref(slice); - grpc_mdstr_unref(str); + GRPC_MDSTR_UNREF(str); grpc_mdctx_unref(ctx); } @@ -264,7 +264,7 @@ static void test_base64_and_huffman_works(void) { GPR_ASSERT(0 == gpr_slice_cmp(slice1, slice2)); gpr_slice_unref(slice2); - grpc_mdstr_unref(str); + GRPC_MDSTR_UNREF(str); grpc_mdctx_unref(ctx); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 60af84100a..0912b19243 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -98,12 +98,16 @@ void CheckAuthContext(T* context) { class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { public: - TestServiceImpl() : signal_client_(false) {} + TestServiceImpl() : signal_client_(false), host_(nullptr) {} + explicit TestServiceImpl(const grpc::string& host) : signal_client_(false), host_(new grpc::string(host)) {} Status Echo(ServerContext* context, const EchoRequest* request, EchoResponse* response) GRPC_OVERRIDE { response->set_message(request->message()); MaybeEchoDeadline(context, request, response); + if (host_) { + response->mutable_param()->set_host(*host_); + } if (request->has_param() && request->param().client_cancel_after_us()) { { std::unique_lock<std::mutex> lock(mu_); @@ -205,6 +209,7 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { private: bool signal_client_; std::mutex mu_; + std::unique_ptr<grpc::string> host_; }; class TestServiceImplDupPkg @@ -219,7 +224,7 @@ class TestServiceImplDupPkg class End2endTest : public ::testing::Test { protected: - End2endTest() : kMaxMessageSize_(8192), thread_pool_(2) {} + End2endTest() : kMaxMessageSize_(8192), special_service_("special"), thread_pool_(2) {} void SetUp() GRPC_OVERRIDE { int port = grpc_pick_unused_port_or_die(); @@ -229,6 +234,7 @@ class End2endTest : public ::testing::Test { builder.AddListeningPort(server_address_.str(), FakeTransportSecurityServerCredentials()); builder.RegisterService(&service_); + builder.RegisterService("special", &special_service_); builder.SetMaxMessageSize( kMaxMessageSize_); // For testing max message size. builder.RegisterService(&dup_pkg_service_); @@ -250,6 +256,7 @@ class End2endTest : public ::testing::Test { std::ostringstream server_address_; const int kMaxMessageSize_; TestServiceImpl service_; + TestServiceImpl special_service_; TestServiceImplDupPkg dup_pkg_service_; ThreadPool thread_pool_; }; @@ -268,6 +275,22 @@ static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub, } } +TEST_F(End2endTest, SimpleRpcWithHost) { + ResetStub(); + + EchoRequest request; + EchoResponse response; + request.set_message("Hello"); + + ClientContext context; + context.set_authority("special"); + Status s = stub_->Echo(&context, request, &response); + EXPECT_EQ(response.message(), request.message()); + EXPECT_TRUE(response.has_param()); + EXPECT_EQ(response.param().host(), "special"); + EXPECT_TRUE(s.ok()); +} + TEST_F(End2endTest, SimpleRpc) { ResetStub(); SendRpc(stub_.get(), 1); diff --git a/test/cpp/util/messages.proto b/test/cpp/util/messages.proto index 3940e70c9f..3708972b90 100644 --- a/test/cpp/util/messages.proto +++ b/test/cpp/util/messages.proto @@ -47,6 +47,7 @@ message EchoRequest { message ResponseParams { optional int64 request_deadline = 1; + optional string host = 2; } message EchoResponse { |