• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/lib/security/credentials/jwt/jwt_verifier.h"
20 
21 #include <grpc/grpc.h>
22 #include <grpc/slice.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/string_util.h>
25 #include <gtest/gtest.h>
26 #include <string.h>
27 
28 #include "absl/strings/escaping.h"
29 #include "src/core/lib/security/credentials/jwt/json_token.h"
30 #include "src/core/util/crash.h"
31 #include "src/core/util/http_client/httpcli.h"
32 #include "src/core/util/json/json_reader.h"
33 #include "test/core/test_util/test_config.h"
34 
35 using grpc_core::Json;
36 
37 // This JSON key was generated with the GCE console and revoked immediately.
38 // The identifiers have been changed as well.
39 // Maximum size for a string literal is 509 chars in C89, yay!
40 static const char json_key_str_part1[] =
41     "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
42     "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE"
43     "qg"
44     "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
45     "rWBQvS4hle4LfijkP3J5BG+"
46     "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
47     "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
48     "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
49     "8HpCqFYM9V8f34SBWfD4fRFT+n/"
50     "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
51 static const char json_key_str_part2[] =
52     "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
53     "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
54     "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA"
55     "G"
56     "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
57     "A"
58     "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
59     "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
60     "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
61     "Y"
62     "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
63 static const char json_key_str_part3_for_google_email_issuer[] =
64     "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
65     "\"client_email\": "
66     "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
67     "com\", \"client_id\": "
68     "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
69     "com\", \"type\": \"service_account\" }";
70 // Trick our JWT library into issuing a JWT with iss=accounts.google.com.
71 static const char json_key_str_part3_for_url_issuer[] =
72     "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
73     "\"client_email\": \"accounts.google.com\", "
74     "\"client_id\": "
75     "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
76     "com\", \"type\": \"service_account\" }";
77 static const char json_key_str_part3_for_custom_email_issuer[] =
78     "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
79     "\"client_email\": "
80     "\"foo@bar.com\", \"client_id\": "
81     "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
82     "com\", \"type\": \"service_account\" }";
83 
84 static grpc_jwt_verifier_email_domain_key_url_mapping custom_mapping = {
85     "bar.com", "keys.bar.com/jwk"};
86 
87 static const char expected_user_data[] = "user data";
88 
89 static const char good_jwk_set[] =
90     "{"
91     " \"keys\": ["
92     "  {"
93     "   \"kty\": \"RSA\","
94     "   \"alg\": \"RS256\","
95     "   \"use\": \"sig\","
96     "   \"kid\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\","
97     "   \"n\": "
98     "\"4S8myegefIeRdynuYkSqBYaOLDvU19cHKC56RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ6mxP"
99     "QutZC1nKNJ6D-tYFC9LiGV7gt-KOQ_cnkEb4hcMw_xF_OI1FCx6cBcM0-"
100     "RjiQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFU=\","
101     "   \"e\": \"AQAB\""
102     "  }"
103     " ]"
104     "}";
105 
106 static gpr_timespec expected_lifetime = {3600, 0, GPR_TIMESPAN};
107 
108 static const char good_google_email_keys_part1[] =
109     "{\"e6b5137873db8d2ef81e06a47289e6434ec8a165\": \"-----BEGIN "
110     "CERTIFICATE-----"
111     "\\nMIICATCCAWoCCQDEywLhxvHjnDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB\\nVTET"
112     "MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\\ncyBQdHkgTHR"
113     "kMB4XDTE1MDYyOTA4Mzk1MFoXDTI1MDYyNjA4Mzk1MFowRTELMAkG\\nA1UEBhMCQVUxEzARBg"
114     "NVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\\nIFdpZGdpdHMgUHR5IEx0ZDCBn"
115     "zANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4S8m\\nyegefIeRdynuYkSqBYaOLDvU19cHKC56"
116     "RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ\\n6mxPQutZC1nKNJ6D+tYFC9LiGV7gt+KOQ/";
117 
118 static const char good_google_email_keys_part2[] =
119     "cnkEb4hcMw/xF/OI1FCx6cBcM0+"
120     "Rji\\nQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFUCAwEAATANBgkqhkiG9w0BAQsF\\nA"
121     "AOBgQBfu69FkPmBknbKNFgurPz78kbs3VNN+k/"
122     "PUgO5DHKskJmgK2TbtvX2VMpx\\nkftmHGzgzMzUlOtigCaGMgHWjfqjpP9uuDbahXrZBJzB8c"
123     "Oq7MrQF8r17qVvo3Ue\\nPjTKQMAsU8uxTEMmeuz9L6yExs0rfd6bPOrQkAoVfFfiYB3/"
124     "pA==\\n-----END CERTIFICATE-----\\n\"}";
125 
126 static const char expected_audience[] = "https://foo.com";
127 
128 static const char good_openid_config[] =
129     "{"
130     " \"issuer\": \"https://accounts.google.com\","
131     " \"authorization_endpoint\": "
132     "\"https://accounts.google.com/o/oauth2/v2/auth\","
133     " \"token_endpoint\": \"https://oauth2.googleapis.com/token\","
134     " \"userinfo_endpoint\": \"https://www.googleapis.com/oauth2/v3/userinfo\","
135     " \"revocation_endpoint\": \"https://oauth2.googleapis.com/revoke\","
136     " \"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\""
137     "}";
138 
139 static const char expired_claims[] =
140     "{ \"aud\": \"https://foo.com\","
141     "  \"iss\": \"blah.foo.com\","
142     "  \"sub\": \"juju@blah.foo.com\","
143     "  \"jti\": \"jwtuniqueid\","
144     "  \"iat\": 100,"  // Way back in the past...
145     "  \"exp\": 120,"
146     "  \"nbf\": 60,"
147     "  \"foo\": \"bar\"}";
148 
149 static const char claims_without_time_constraint[] =
150     "{ \"aud\": \"https://foo.com\","
151     "  \"iss\": \"blah.foo.com\","
152     "  \"sub\": \"juju@blah.foo.com\","
153     "  \"jti\": \"jwtuniqueid\","
154     "  \"foo\": \"bar\"}";
155 
156 static const char claims_with_bad_subject[] =
157     "{ \"aud\": \"https://foo.com\","
158     "  \"iss\": \"evil@blah.foo.com\","
159     "  \"sub\": \"juju@blah.foo.com\","
160     "  \"jti\": \"jwtuniqueid\","
161     "  \"foo\": \"bar\"}";
162 
163 static const char invalid_claims[] =
164     "{ \"aud\": \"https://foo.com\","
165     "  \"iss\": 46,"  // Issuer cannot be a number.
166     "  \"sub\": \"juju@blah.foo.com\","
167     "  \"jti\": \"jwtuniqueid\","
168     "  \"foo\": \"bar\"}";
169 
170 typedef struct {
171   grpc_jwt_verifier_status expected_status;
172   const char* expected_issuer;
173   const char* expected_subject;
174 } verifier_test_config;
175 
TEST(JwtVerifierTest,JwtIssuerEmailDomain)176 TEST(JwtVerifierTest, JwtIssuerEmailDomain) {
177   const char* d = grpc_jwt_issuer_email_domain("https://foo.com");
178   ASSERT_EQ(d, nullptr);
179   d = grpc_jwt_issuer_email_domain("foo.com");
180   ASSERT_EQ(d, nullptr);
181   d = grpc_jwt_issuer_email_domain("");
182   ASSERT_EQ(d, nullptr);
183   d = grpc_jwt_issuer_email_domain("@");
184   ASSERT_EQ(d, nullptr);
185   d = grpc_jwt_issuer_email_domain("bar@foo");
186   ASSERT_STREQ(d, "foo");
187   d = grpc_jwt_issuer_email_domain("bar@foo.com");
188   ASSERT_STREQ(d, "foo.com");
189   d = grpc_jwt_issuer_email_domain("bar@blah.foo.com");
190   ASSERT_STREQ(d, "foo.com");
191   d = grpc_jwt_issuer_email_domain("bar.blah@blah.foo.com");
192   ASSERT_STREQ(d, "foo.com");
193   d = grpc_jwt_issuer_email_domain("bar.blah@baz.blah.foo.com");
194   ASSERT_STREQ(d, "foo.com");
195 
196   // This is not a very good parser but make sure we do not crash on these weird
197   // inputs.
198   d = grpc_jwt_issuer_email_domain("@foo");
199   ASSERT_STREQ(d, "foo");
200   d = grpc_jwt_issuer_email_domain("bar@.");
201   ASSERT_NE(d, nullptr);
202   d = grpc_jwt_issuer_email_domain("bar@..");
203   ASSERT_NE(d, nullptr);
204   d = grpc_jwt_issuer_email_domain("bar@...");
205   ASSERT_NE(d, nullptr);
206 }
207 
TEST(JwtVerifierTest,ClaimsSuccess)208 TEST(JwtVerifierTest, ClaimsSuccess) {
209   grpc_jwt_claims* claims;
210   auto json = grpc_core::JsonParse(claims_without_time_constraint);
211   ASSERT_TRUE(json.ok()) << json.status();
212   ASSERT_EQ(json->type(), Json::Type::kObject);
213   grpc_core::ExecCtx exec_ctx;
214   claims = grpc_jwt_claims_from_json(*json);
215   ASSERT_NE(claims, nullptr);
216   ASSERT_EQ(*grpc_jwt_claims_json(claims), *json);
217   ASSERT_STREQ(grpc_jwt_claims_audience(claims), "https://foo.com");
218   ASSERT_STREQ(grpc_jwt_claims_issuer(claims), "blah.foo.com");
219   ASSERT_STREQ(grpc_jwt_claims_subject(claims), "juju@blah.foo.com");
220   ASSERT_STREQ(grpc_jwt_claims_id(claims), "jwtuniqueid");
221   ASSERT_EQ(grpc_jwt_claims_check(claims, "https://foo.com"),
222             GRPC_JWT_VERIFIER_OK);
223   grpc_jwt_claims_destroy(claims);
224 }
225 
TEST(JwtVerifierTest,ExpiredClaimsFailure)226 TEST(JwtVerifierTest, ExpiredClaimsFailure) {
227   grpc_jwt_claims* claims;
228   auto json = grpc_core::JsonParse(expired_claims);
229   ASSERT_TRUE(json.ok()) << json.status();
230   ASSERT_EQ(json->type(), Json::Type::kObject);
231   gpr_timespec exp_iat = {100, 0, GPR_CLOCK_REALTIME};
232   gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME};
233   gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME};
234   grpc_core::ExecCtx exec_ctx;
235   claims = grpc_jwt_claims_from_json(*json);
236   ASSERT_NE(claims, nullptr);
237   ASSERT_EQ(*grpc_jwt_claims_json(claims), *json);
238   ASSERT_STREQ(grpc_jwt_claims_audience(claims), "https://foo.com");
239   ASSERT_STREQ(grpc_jwt_claims_issuer(claims), "blah.foo.com");
240   ASSERT_STREQ(grpc_jwt_claims_subject(claims), "juju@blah.foo.com");
241   ASSERT_STREQ(grpc_jwt_claims_id(claims), "jwtuniqueid");
242   ASSERT_EQ(gpr_time_cmp(grpc_jwt_claims_issued_at(claims), exp_iat), 0);
243   ASSERT_EQ(gpr_time_cmp(grpc_jwt_claims_expires_at(claims), exp_exp), 0);
244   ASSERT_EQ(gpr_time_cmp(grpc_jwt_claims_not_before(claims), exp_nbf), 0);
245   ASSERT_EQ(grpc_jwt_claims_check(claims, "https://foo.com"),
246             GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE);
247   grpc_jwt_claims_destroy(claims);
248 }
249 
TEST(JwtVerifierTest,InvalidClaimsFailure)250 TEST(JwtVerifierTest, InvalidClaimsFailure) {
251   auto json = grpc_core::JsonParse(invalid_claims);
252   ASSERT_TRUE(json.ok()) << json.status();
253   ASSERT_EQ(json->type(), Json::Type::kObject);
254   grpc_core::ExecCtx exec_ctx;
255   ASSERT_EQ(grpc_jwt_claims_from_json(*json), nullptr);
256 }
257 
TEST(JwtVerifierTest,BadAudienceClaimsFailure)258 TEST(JwtVerifierTest, BadAudienceClaimsFailure) {
259   grpc_jwt_claims* claims;
260   auto json = grpc_core::JsonParse(claims_without_time_constraint);
261   ASSERT_TRUE(json.ok()) << json.status();
262   ASSERT_EQ(json->type(), Json::Type::kObject);
263   grpc_core::ExecCtx exec_ctx;
264   claims = grpc_jwt_claims_from_json(*json);
265   ASSERT_NE(claims, nullptr);
266   ASSERT_EQ(grpc_jwt_claims_check(claims, "https://bar.com"),
267             GRPC_JWT_VERIFIER_BAD_AUDIENCE);
268   grpc_jwt_claims_destroy(claims);
269 }
270 
TEST(JwtVerifierTest,BadSubjectClaimsFailure)271 TEST(JwtVerifierTest, BadSubjectClaimsFailure) {
272   grpc_jwt_claims* claims;
273   auto json = grpc_core::JsonParse(claims_with_bad_subject);
274   ASSERT_TRUE(json.ok()) << json.status();
275   ASSERT_EQ(json->type(), Json::Type::kObject);
276   grpc_core::ExecCtx exec_ctx;
277   claims = grpc_jwt_claims_from_json(*json);
278   ASSERT_NE(claims, nullptr);
279   ASSERT_EQ(grpc_jwt_claims_check(claims, "https://foo.com"),
280             GRPC_JWT_VERIFIER_BAD_SUBJECT);
281   grpc_jwt_claims_destroy(claims);
282 }
283 
json_key_str(const char * last_part)284 static char* json_key_str(const char* last_part) {
285   size_t result_len = strlen(json_key_str_part1) + strlen(json_key_str_part2) +
286                       strlen(last_part);
287   char* result = static_cast<char*>(gpr_malloc(result_len + 1));
288   char* current = result;
289   strcpy(result, json_key_str_part1);
290   current += strlen(json_key_str_part1);
291   strcpy(current, json_key_str_part2);
292   current += strlen(json_key_str_part2);
293   strcpy(current, last_part);
294   return result;
295 }
296 
good_google_email_keys(void)297 static char* good_google_email_keys(void) {
298   size_t result_len = strlen(good_google_email_keys_part1) +
299                       strlen(good_google_email_keys_part2);
300   char* result = static_cast<char*>(gpr_malloc(result_len + 1));
301   char* current = result;
302   strcpy(result, good_google_email_keys_part1);
303   current += strlen(good_google_email_keys_part1);
304   strcpy(current, good_google_email_keys_part2);
305   return result;
306 }
307 
http_response(int status,char * body)308 static grpc_http_response http_response(int status, char* body) {
309   grpc_http_response response;
310   response = {};
311   response.status = status;
312   response.body = body;
313   response.body_length = strlen(body);
314   return response;
315 }
316 
httpcli_post_should_not_be_called(const grpc_http_request *,const grpc_core::URI &,absl::string_view,grpc_core::Timestamp,grpc_closure *,grpc_http_response *)317 static int httpcli_post_should_not_be_called(
318     const grpc_http_request* /*request*/, const grpc_core::URI& /*uri*/,
319     absl::string_view /*body*/, grpc_core::Timestamp /*deadline*/,
320     grpc_closure* /*on_done*/, grpc_http_response* /*response*/) {
321   EXPECT_EQ("HTTP POST should not be called", nullptr);
322   return 1;
323 }
324 
httpcli_put_should_not_be_called(const grpc_http_request *,const grpc_core::URI &,absl::string_view,grpc_core::Timestamp,grpc_closure *,grpc_http_response *)325 static int httpcli_put_should_not_be_called(
326     const grpc_http_request* /*request*/, const grpc_core::URI& /*uri*/,
327     absl::string_view /*body*/, grpc_core::Timestamp /*deadline*/,
328     grpc_closure* /*on_done*/, grpc_http_response* /*response*/) {
329   EXPECT_EQ("HTTP PUT should not be called", nullptr);
330   return 1;
331 }
332 
httpcli_get_google_keys_for_email(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)333 static int httpcli_get_google_keys_for_email(
334     const grpc_http_request* /*request*/, const grpc_core::URI& uri,
335     grpc_core::Timestamp /*deadline*/, grpc_closure* on_done,
336     grpc_http_response* response) {
337   *response = http_response(200, good_google_email_keys());
338   EXPECT_EQ(uri.authority(), "www.googleapis.com");
339   EXPECT_EQ(uri.path(),
340             "/robot/v1/metadata/x509/"
341             "777-abaslkan11hlb6nmim3bpspl31ud@developer."
342             "gserviceaccount.com");
343   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
344   return 1;
345 }
346 
on_verification_success(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)347 static void on_verification_success(void* user_data,
348                                     grpc_jwt_verifier_status status,
349                                     grpc_jwt_claims* claims) {
350   ASSERT_EQ(status, GRPC_JWT_VERIFIER_OK);
351   ASSERT_NE(claims, nullptr);
352   ASSERT_EQ(user_data, (void*)expected_user_data);
353   ASSERT_STREQ(grpc_jwt_claims_audience(claims), expected_audience);
354   grpc_jwt_claims_destroy(claims);
355 }
356 
TEST(JwtVerifierTest,JwtVerifierGoogleEmailIssuerSuccess)357 TEST(JwtVerifierTest, JwtVerifierGoogleEmailIssuerSuccess) {
358   grpc_core::ExecCtx exec_ctx;
359   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
360   char* jwt = nullptr;
361   char* key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
362   grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
363   gpr_free(key_str);
364   ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
365   grpc_core::HttpRequest::SetOverride(httpcli_get_google_keys_for_email,
366                                       httpcli_post_should_not_be_called,
367                                       httpcli_put_should_not_be_called);
368   jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
369                                  nullptr);
370   grpc_auth_json_key_destruct(&key);
371   ASSERT_NE(jwt, nullptr);
372   grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
373                            on_verification_success,
374                            const_cast<char*>(expected_user_data));
375   grpc_jwt_verifier_destroy(verifier);
376   grpc_core::ExecCtx::Get()->Flush();
377   gpr_free(jwt);
378   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
379 }
380 
httpcli_get_custom_keys_for_email(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)381 static int httpcli_get_custom_keys_for_email(
382     const grpc_http_request* /*request*/, const grpc_core::URI& uri,
383     grpc_core::Timestamp /*deadline*/, grpc_closure* on_done,
384     grpc_http_response* response) {
385   *response = http_response(200, gpr_strdup(good_jwk_set));
386   EXPECT_EQ(uri.authority(), "keys.bar.com");
387   EXPECT_EQ(uri.path(), "/jwk/foo@bar.com");
388   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
389   return 1;
390 }
391 
TEST(JwtVerifierTest,JwtVerifierCustomEmailIssuerSuccess)392 TEST(JwtVerifierTest, JwtVerifierCustomEmailIssuerSuccess) {
393   grpc_core::ExecCtx exec_ctx;
394   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(&custom_mapping, 1);
395   char* jwt = nullptr;
396   char* key_str = json_key_str(json_key_str_part3_for_custom_email_issuer);
397   grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
398   gpr_free(key_str);
399   ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
400   grpc_core::HttpRequest::SetOverride(httpcli_get_custom_keys_for_email,
401                                       httpcli_post_should_not_be_called,
402                                       httpcli_put_should_not_be_called);
403   jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
404                                  nullptr);
405   grpc_auth_json_key_destruct(&key);
406   ASSERT_NE(jwt, nullptr);
407   grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
408                            on_verification_success,
409                            const_cast<char*>(expected_user_data));
410   grpc_jwt_verifier_destroy(verifier);
411   grpc_core::ExecCtx::Get()->Flush();
412   gpr_free(jwt);
413   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
414 }
415 
httpcli_get_jwk_set(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)416 static int httpcli_get_jwk_set(const grpc_http_request* /*request*/,
417                                const grpc_core::URI& uri,
418                                grpc_core::Timestamp /*deadline*/,
419                                grpc_closure* on_done,
420                                grpc_http_response* response) {
421   *response = http_response(200, gpr_strdup(good_jwk_set));
422   EXPECT_EQ(uri.authority(), "www.googleapis.com");
423   EXPECT_EQ(uri.path(), "/oauth2/v3/certs");
424   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
425   return 1;
426 }
427 
httpcli_get_openid_config(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)428 static int httpcli_get_openid_config(const grpc_http_request* /*request*/,
429                                      const grpc_core::URI& uri,
430                                      grpc_core::Timestamp /*deadline*/,
431                                      grpc_closure* on_done,
432                                      grpc_http_response* response) {
433   *response = http_response(200, gpr_strdup(good_openid_config));
434   EXPECT_EQ(uri.authority(), "accounts.google.com");
435   EXPECT_EQ(uri.path(), GRPC_OPENID_CONFIG_URL_SUFFIX);
436   grpc_core::HttpRequest::SetOverride(httpcli_get_jwk_set,
437                                       httpcli_post_should_not_be_called,
438                                       httpcli_put_should_not_be_called);
439   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
440   return 1;
441 }
442 
TEST(JwtVerifierTest,JwtVerifierUrlIssuerSuccess)443 TEST(JwtVerifierTest, JwtVerifierUrlIssuerSuccess) {
444   grpc_core::ExecCtx exec_ctx;
445   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
446   char* jwt = nullptr;
447   char* key_str = json_key_str(json_key_str_part3_for_url_issuer);
448   grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
449   gpr_free(key_str);
450   ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
451   grpc_core::HttpRequest::SetOverride(httpcli_get_openid_config,
452                                       httpcli_post_should_not_be_called,
453                                       httpcli_put_should_not_be_called);
454   jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
455                                  nullptr);
456   grpc_auth_json_key_destruct(&key);
457   ASSERT_NE(jwt, nullptr);
458   grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
459                            on_verification_success,
460                            const_cast<char*>(expected_user_data));
461   grpc_jwt_verifier_destroy(verifier);
462   grpc_core::ExecCtx::Get()->Flush();
463   gpr_free(jwt);
464   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
465 }
466 
on_verification_key_retrieval_error(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)467 static void on_verification_key_retrieval_error(void* user_data,
468                                                 grpc_jwt_verifier_status status,
469                                                 grpc_jwt_claims* claims) {
470   ASSERT_EQ(status, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR);
471   ASSERT_EQ(claims, nullptr);
472   ASSERT_EQ(user_data, (void*)expected_user_data);
473 }
474 
httpcli_get_bad_json(const grpc_http_request *,const grpc_core::URI &,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)475 static int httpcli_get_bad_json(const grpc_http_request* /* request */,
476                                 const grpc_core::URI& /*uri*/,
477                                 grpc_core::Timestamp /*deadline*/,
478                                 grpc_closure* on_done,
479                                 grpc_http_response* response) {
480   *response = http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
481   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
482   return 1;
483 }
484 
TEST(JwtVerifierTest,JwtVerifierUrlIssuerBadConfig)485 TEST(JwtVerifierTest, JwtVerifierUrlIssuerBadConfig) {
486   grpc_core::ExecCtx exec_ctx;
487   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
488   char* jwt = nullptr;
489   char* key_str = json_key_str(json_key_str_part3_for_url_issuer);
490   grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
491   gpr_free(key_str);
492   ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
493   grpc_core::HttpRequest::SetOverride(httpcli_get_bad_json,
494                                       httpcli_post_should_not_be_called,
495                                       httpcli_put_should_not_be_called);
496   jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
497                                  nullptr);
498   grpc_auth_json_key_destruct(&key);
499   ASSERT_NE(jwt, nullptr);
500   grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
501                            on_verification_key_retrieval_error,
502                            const_cast<char*>(expected_user_data));
503   grpc_jwt_verifier_destroy(verifier);
504   grpc_core::ExecCtx::Get()->Flush();
505   gpr_free(jwt);
506   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
507 }
508 
TEST(JwtVerifierTest,JwtVerifierBadJsonKey)509 TEST(JwtVerifierTest, JwtVerifierBadJsonKey) {
510   grpc_core::ExecCtx exec_ctx;
511   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
512   char* jwt = nullptr;
513   char* key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
514   grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
515   gpr_free(key_str);
516   ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
517   grpc_core::HttpRequest::SetOverride(httpcli_get_bad_json,
518                                       httpcli_post_should_not_be_called,
519                                       httpcli_put_should_not_be_called);
520   jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
521                                  nullptr);
522   grpc_auth_json_key_destruct(&key);
523   ASSERT_NE(jwt, nullptr);
524   grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
525                            on_verification_key_retrieval_error,
526                            const_cast<char*>(expected_user_data));
527   grpc_jwt_verifier_destroy(verifier);
528   grpc_core::ExecCtx::Get()->Flush();
529   gpr_free(jwt);
530   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
531 }
532 
corrupt_jwt_sig(char * jwt)533 static void corrupt_jwt_sig(char* jwt) {
534   char* last_dot = strrchr(jwt, '.');
535   ASSERT_NE(last_dot, nullptr);
536   std::string decoded;
537   absl::WebSafeBase64Unescape(last_dot + 1, &decoded);
538   ASSERT_FALSE(decoded.empty());
539   ++decoded[0];  // Corrupt first byte.
540   std::string bad_encoding = absl::WebSafeBase64Escape(decoded);
541   memcpy(last_dot + 1, bad_encoding.data(), bad_encoding.size());
542 }
543 
on_verification_bad_signature(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)544 static void on_verification_bad_signature(void* user_data,
545                                           grpc_jwt_verifier_status status,
546                                           grpc_jwt_claims* claims) {
547   ASSERT_EQ(status, GRPC_JWT_VERIFIER_BAD_SIGNATURE);
548   ASSERT_EQ(claims, nullptr);
549   ASSERT_EQ(user_data, (void*)expected_user_data);
550 }
551 
TEST(JwtVerifierTest,JwtVerifierBadSignature)552 TEST(JwtVerifierTest, JwtVerifierBadSignature) {
553   grpc_core::ExecCtx exec_ctx;
554   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
555   char* jwt = nullptr;
556   char* key_str = json_key_str(json_key_str_part3_for_url_issuer);
557   grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
558   gpr_free(key_str);
559   ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
560   grpc_core::HttpRequest::SetOverride(httpcli_get_openid_config,
561                                       httpcli_post_should_not_be_called,
562                                       httpcli_put_should_not_be_called);
563   jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
564                                  nullptr);
565   grpc_auth_json_key_destruct(&key);
566   corrupt_jwt_sig(jwt);
567   ASSERT_NE(jwt, nullptr);
568   grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
569                            on_verification_bad_signature,
570                            const_cast<char*>(expected_user_data));
571   gpr_free(jwt);
572   grpc_jwt_verifier_destroy(verifier);
573   grpc_core::ExecCtx::Get()->Flush();
574   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
575 }
576 
httpcli_get_should_not_be_called(const grpc_http_request *,const grpc_core::URI &,grpc_core::Timestamp,grpc_closure *,grpc_http_response *)577 static int httpcli_get_should_not_be_called(
578     const grpc_http_request* /*request*/, const grpc_core::URI& /*uri*/,
579     grpc_core::Timestamp /*deadline*/, grpc_closure* /*on_done*/,
580     grpc_http_response* /*response*/) {
581   EXPECT_TRUE(0);
582   return 1;
583 }
584 
on_verification_bad_format(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)585 static void on_verification_bad_format(void* user_data,
586                                        grpc_jwt_verifier_status status,
587                                        grpc_jwt_claims* claims) {
588   ASSERT_EQ(status, GRPC_JWT_VERIFIER_BAD_FORMAT);
589   ASSERT_EQ(claims, nullptr);
590   ASSERT_EQ(user_data, (void*)expected_user_data);
591 }
592 
TEST(JwtVerifierTest,JwtVerifierBadFormat)593 TEST(JwtVerifierTest, JwtVerifierBadFormat) {
594   grpc_core::ExecCtx exec_ctx;
595   grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
596   grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called,
597                                       httpcli_post_should_not_be_called,
598                                       httpcli_put_should_not_be_called);
599   grpc_jwt_verifier_verify(verifier, nullptr, "bad jwt", expected_audience,
600                            on_verification_bad_format,
601                            const_cast<char*>(expected_user_data));
602   grpc_jwt_verifier_destroy(verifier);
603   grpc_core::ExecCtx::Get()->Flush();
604   grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
605 }
606 
607 // find verification key: bad jks, cannot find key in jks
608 // bad signature custom provided email
609 // bad key
610 
main(int argc,char ** argv)611 int main(int argc, char** argv) {
612   grpc::testing::TestEnvironment env(&argc, argv);
613   ::testing::InitGoogleTest(&argc, argv);
614   grpc::testing::TestGrpcScope grpc_scope;
615   return RUN_ALL_TESTS();
616 }
617