3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "upb/upb.hpp"
21 #include <grpc/grpc.h>
23 #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
24 #include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
25 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
26 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h"
27 #include "src/core/tsi/transport_security.h"
28 #include "src/core/tsi/transport_security_interface.h"
29 #include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
30 #include "test/core/util/test_config.h"
32 #define ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME "Hello Google"
33 #define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME "bigtable.google.api.com"
34 #define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1 "A@google.com"
35 #define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2 "B@google.com"
36 #define ALTS_HANDSHAKER_CLIENT_TEST_MAX_FRAME_SIZE (64 * 1024)
38 const size_t kHandshakerClientOpNum = 4;
39 const size_t kMaxRpcVersionMajor = 3;
40 const size_t kMaxRpcVersionMinor = 2;
41 const size_t kMinRpcVersionMajor = 2;
42 const size_t kMinRpcVersionMinor = 1;
44 using grpc_core::internal::alts_handshaker_client_get_closure_for_testing;
45 using grpc_core::internal::
46 alts_handshaker_client_get_initial_metadata_for_testing;
47 using grpc_core::internal::
48 alts_handshaker_client_get_recv_buffer_addr_for_testing;
49 using grpc_core::internal::alts_handshaker_client_get_send_buffer_for_testing;
50 using grpc_core::internal::
51 alts_handshaker_client_on_status_received_for_testing;
52 using grpc_core::internal::alts_handshaker_client_set_cb_for_testing;
53 using grpc_core::internal::alts_handshaker_client_set_grpc_caller_for_testing;
55 typedef struct alts_handshaker_client_test_config {
56 grpc_channel* channel;
57 grpc_completion_queue* cq;
58 alts_handshaker_client* client;
59 alts_handshaker_client* server;
61 } alts_handshaker_client_test_config;
63 static void validate_rpc_protocol_versions(
64 const grpc_gcp_RpcProtocolVersions* versions) {
65 GPR_ASSERT(versions != nullptr);
66 const grpc_gcp_RpcProtocolVersions_Version* max_version =
67 grpc_gcp_RpcProtocolVersions_max_rpc_version(versions);
68 const grpc_gcp_RpcProtocolVersions_Version* min_version =
69 grpc_gcp_RpcProtocolVersions_min_rpc_version(versions);
70 GPR_ASSERT(grpc_gcp_RpcProtocolVersions_Version_major(max_version) ==
72 GPR_ASSERT(grpc_gcp_RpcProtocolVersions_Version_minor(max_version) ==
74 GPR_ASSERT(grpc_gcp_RpcProtocolVersions_Version_major(min_version) ==
76 GPR_ASSERT(grpc_gcp_RpcProtocolVersions_Version_minor(min_version) ==
80 static void validate_target_identities(
81 const grpc_gcp_Identity* const* target_identities,
82 size_t target_identities_count) {
83 GPR_ASSERT(target_identities_count == 2);
84 const grpc_gcp_Identity* identity1 = target_identities[1];
85 const grpc_gcp_Identity* identity2 = target_identities[0];
86 GPR_ASSERT(upb_strview_eql(
87 grpc_gcp_Identity_service_account(identity1),
88 upb_strview_makez(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1)));
89 GPR_ASSERT(upb_strview_eql(
90 grpc_gcp_Identity_service_account(identity2),
91 upb_strview_makez(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2)));
95 * Validate if grpc operation data is correctly populated with the fields of
96 * ALTS handshaker client.
98 static bool validate_op(alts_handshaker_client* c, const grpc_op* op,
99 size_t nops, bool is_start) {
100 GPR_ASSERT(c != nullptr && op != nullptr && nops != 0);
102 grpc_op* start_op = const_cast<grpc_op*>(op);
104 ok &= (op->op == GRPC_OP_SEND_INITIAL_METADATA);
105 ok &= (op->data.send_initial_metadata.count == 0);
107 GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
108 ok &= (op->op == GRPC_OP_RECV_INITIAL_METADATA);
109 ok &= (op->data.recv_initial_metadata.recv_initial_metadata ==
110 alts_handshaker_client_get_initial_metadata_for_testing(c));
112 GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
114 ok &= (op->op == GRPC_OP_SEND_MESSAGE);
115 ok &= (op->data.send_message.send_message ==
116 alts_handshaker_client_get_send_buffer_for_testing(c));
118 GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
119 ok &= (op->op == GRPC_OP_RECV_MESSAGE);
120 ok &= (op->data.recv_message.recv_message ==
121 alts_handshaker_client_get_recv_buffer_addr_for_testing(c));
123 GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
127 static grpc_gcp_HandshakerReq* deserialize_handshaker_req(
128 grpc_byte_buffer* buffer, upb_arena* arena) {
129 GPR_ASSERT(buffer != nullptr);
130 grpc_byte_buffer_reader bbr;
131 GPR_ASSERT(grpc_byte_buffer_reader_init(&bbr, buffer));
132 grpc_slice slice = grpc_byte_buffer_reader_readall(&bbr);
133 grpc_gcp_HandshakerReq* req = grpc_gcp_handshaker_req_decode(slice, arena);
134 GPR_ASSERT(req != nullptr);
135 grpc_slice_unref(slice);
136 grpc_byte_buffer_reader_destroy(&bbr);
140 static bool is_recv_status_op(const grpc_op* op, size_t nops) {
141 if (nops == 1 && op->op == GRPC_OP_RECV_STATUS_ON_CLIENT) {
148 * A mock grpc_caller used to check if client_start, server_start, and next
149 * operations correctly handle invalid arguments. It should not be called.
151 static grpc_call_error check_must_not_be_called(grpc_call* /*call*/,
152 const grpc_op* /*ops*/,
154 grpc_closure* /*tag*/) {
159 * A mock grpc_caller used to check correct execution of client_start operation.
160 * It checks if the client_start handshaker request is populated with correct
161 * handshake_security_protocol, application_protocol, record_protocol and
162 * max_frame_size, and op is correctly populated.
164 static grpc_call_error check_client_start_success(grpc_call* /*call*/,
167 grpc_closure* closure) {
168 // RECV_STATUS ops are asserted to always succeed
169 if (is_recv_status_op(op, nops)) {
173 alts_handshaker_client* client =
174 static_cast<alts_handshaker_client*>(closure->cb_arg);
175 GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure);
176 grpc_gcp_HandshakerReq* req = deserialize_handshaker_req(
177 alts_handshaker_client_get_send_buffer_for_testing(client), arena.ptr());
178 const grpc_gcp_StartClientHandshakeReq* client_start =
179 grpc_gcp_HandshakerReq_client_start(req);
180 GPR_ASSERT(grpc_gcp_StartClientHandshakeReq_handshake_security_protocol(
181 client_start) == grpc_gcp_ALTS);
182 upb_strview const* application_protocols =
183 grpc_gcp_StartClientHandshakeReq_application_protocols(client_start,
185 GPR_ASSERT(upb_strview_eql(application_protocols[0],
186 upb_strview_makez(ALTS_APPLICATION_PROTOCOL)));
187 upb_strview const* record_protocols =
188 grpc_gcp_StartClientHandshakeReq_record_protocols(client_start, nullptr);
189 GPR_ASSERT(upb_strview_eql(record_protocols[0],
190 upb_strview_makez(ALTS_RECORD_PROTOCOL)));
191 const grpc_gcp_RpcProtocolVersions* rpc_protocol_versions =
192 grpc_gcp_StartClientHandshakeReq_rpc_versions(client_start);
193 validate_rpc_protocol_versions(rpc_protocol_versions);
194 size_t target_identities_count;
195 const grpc_gcp_Identity* const* target_identities =
196 grpc_gcp_StartClientHandshakeReq_target_identities(
197 client_start, &target_identities_count);
198 validate_target_identities(target_identities, target_identities_count);
199 GPR_ASSERT(upb_strview_eql(
200 grpc_gcp_StartClientHandshakeReq_target_name(client_start),
201 upb_strview_makez(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME)));
202 GPR_ASSERT(grpc_gcp_StartClientHandshakeReq_max_frame_size(client_start) ==
203 ALTS_HANDSHAKER_CLIENT_TEST_MAX_FRAME_SIZE);
204 GPR_ASSERT(validate_op(client, op, nops, true /* is_start */));
209 * A mock grpc_caller used to check correct execution of server_start operation.
210 * It checks if the server_start handshaker request is populated with correct
211 * handshake_security_protocol, application_protocol, record_protocol and
212 * max_frame_size, and op is correctly populated.
214 static grpc_call_error check_server_start_success(grpc_call* /*call*/,
217 grpc_closure* closure) {
218 // RECV_STATUS ops are asserted to always succeed
219 if (is_recv_status_op(op, nops)) {
223 alts_handshaker_client* client =
224 static_cast<alts_handshaker_client*>(closure->cb_arg);
225 GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure);
226 grpc_gcp_HandshakerReq* req = deserialize_handshaker_req(
227 alts_handshaker_client_get_send_buffer_for_testing(client), arena.ptr());
228 const grpc_gcp_StartServerHandshakeReq* server_start =
229 grpc_gcp_HandshakerReq_server_start(req);
230 upb_strview const* application_protocols =
231 grpc_gcp_StartServerHandshakeReq_application_protocols(server_start,
233 GPR_ASSERT(upb_strview_eql(application_protocols[0],
234 upb_strview_makez(ALTS_APPLICATION_PROTOCOL)));
235 GPR_ASSERT(grpc_gcp_StartServerHandshakeReq_handshake_parameters_size(
237 grpc_gcp_ServerHandshakeParameters* value;
238 GPR_ASSERT(grpc_gcp_StartServerHandshakeReq_handshake_parameters_get(
239 server_start, grpc_gcp_ALTS, &value));
240 upb_strview const* record_protocols =
241 grpc_gcp_ServerHandshakeParameters_record_protocols(value, nullptr);
242 GPR_ASSERT(upb_strview_eql(record_protocols[0],
243 upb_strview_makez(ALTS_RECORD_PROTOCOL)));
244 validate_rpc_protocol_versions(
245 grpc_gcp_StartServerHandshakeReq_rpc_versions(server_start));
246 GPR_ASSERT(grpc_gcp_StartServerHandshakeReq_max_frame_size(server_start) ==
247 ALTS_HANDSHAKER_CLIENT_TEST_MAX_FRAME_SIZE);
248 GPR_ASSERT(validate_op(client, op, nops, true /* is_start */));
253 * A mock grpc_caller used to check correct execution of next operation. It
254 * checks if the next handshaker request is populated with correct information,
255 * and op is correctly populated.
257 static grpc_call_error check_next_success(grpc_call* /*call*/,
258 const grpc_op* op, size_t nops,
259 grpc_closure* closure) {
261 alts_handshaker_client* client =
262 static_cast<alts_handshaker_client*>(closure->cb_arg);
263 GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure);
264 grpc_gcp_HandshakerReq* req = deserialize_handshaker_req(
265 alts_handshaker_client_get_send_buffer_for_testing(client), arena.ptr());
266 const grpc_gcp_NextHandshakeMessageReq* next =
267 grpc_gcp_HandshakerReq_next(req);
268 GPR_ASSERT(upb_strview_eql(
269 grpc_gcp_NextHandshakeMessageReq_in_bytes(next),
270 upb_strview_makez(ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME)));
271 GPR_ASSERT(validate_op(client, op, nops, false /* is_start */));
276 * A mock grpc_caller used to check if client_start, server_start, and next
277 * operations correctly handle the situation when the grpc call made to the
278 * handshaker service fails.
280 static grpc_call_error check_grpc_call_failure(grpc_call* /*call*/,
281 const grpc_op* op, size_t nops,
282 grpc_closure* /*tag*/) {
283 // RECV_STATUS ops are asserted to always succeed
284 if (is_recv_status_op(op, nops)) {
287 return GRPC_CALL_ERROR;
290 static grpc_alts_credentials_options* create_credentials_options(
292 grpc_alts_credentials_options* options =
293 is_client ? grpc_alts_credentials_client_options_create()
294 : grpc_alts_credentials_server_options_create();
296 grpc_alts_credentials_client_options_add_target_service_account(
297 options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1);
298 grpc_alts_credentials_client_options_add_target_service_account(
299 options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2);
301 grpc_gcp_rpc_protocol_versions* versions = &options->rpc_versions;
302 GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(
303 versions, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
304 GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(
305 versions, kMinRpcVersionMajor, kMinRpcVersionMinor));
309 static alts_handshaker_client_test_config* create_config() {
310 alts_handshaker_client_test_config* config =
311 static_cast<alts_handshaker_client_test_config*>(
312 gpr_zalloc(sizeof(*config)));
313 config->channel = grpc_insecure_channel_create(
314 ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, nullptr, nullptr);
315 config->cq = grpc_completion_queue_create_for_next(nullptr);
316 grpc_alts_credentials_options* client_options =
317 create_credentials_options(true /* is_client */);
318 grpc_alts_credentials_options* server_options =
319 create_credentials_options(false /* is_client */);
320 config->server = alts_grpc_handshaker_client_create(
321 nullptr, config->channel, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING,
322 nullptr, server_options,
323 grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME),
324 nullptr, nullptr, nullptr, nullptr, false,
325 ALTS_HANDSHAKER_CLIENT_TEST_MAX_FRAME_SIZE);
326 config->client = alts_grpc_handshaker_client_create(
327 nullptr, config->channel, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING,
328 nullptr, client_options,
329 grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME),
330 nullptr, nullptr, nullptr, nullptr, true,
331 ALTS_HANDSHAKER_CLIENT_TEST_MAX_FRAME_SIZE);
332 GPR_ASSERT(config->client != nullptr);
333 GPR_ASSERT(config->server != nullptr);
334 grpc_alts_credentials_options_destroy(client_options);
335 grpc_alts_credentials_options_destroy(server_options);
337 grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME);
341 static void destroy_config(alts_handshaker_client_test_config* config) {
342 if (config == nullptr) {
345 grpc_completion_queue_destroy(config->cq);
346 grpc_channel_destroy(config->channel);
347 alts_handshaker_client_destroy(config->client);
348 alts_handshaker_client_destroy(config->server);
349 grpc_slice_unref(config->out_frame);
353 static void schedule_request_invalid_arg_test() {
354 /* Initialization. */
355 alts_handshaker_client_test_config* config = create_config();
357 alts_handshaker_client_set_grpc_caller_for_testing(config->client,
358 check_must_not_be_called);
359 /* Check client_start. */
361 grpc_core::ExecCtx exec_ctx;
362 GPR_ASSERT(alts_handshaker_client_start_client(nullptr) ==
363 TSI_INVALID_ARGUMENT);
365 /* Check server_start. */
367 grpc_core::ExecCtx exec_ctx;
368 GPR_ASSERT(alts_handshaker_client_start_server(config->server, nullptr) ==
369 TSI_INVALID_ARGUMENT);
372 grpc_core::ExecCtx exec_ctx;
373 GPR_ASSERT(alts_handshaker_client_start_server(
374 nullptr, &config->out_frame) == TSI_INVALID_ARGUMENT);
378 grpc_core::ExecCtx exec_ctx;
379 GPR_ASSERT(alts_handshaker_client_next(config->client, nullptr) ==
380 TSI_INVALID_ARGUMENT);
383 grpc_core::ExecCtx exec_ctx;
384 GPR_ASSERT(alts_handshaker_client_next(nullptr, &config->out_frame) ==
385 TSI_INVALID_ARGUMENT);
387 /* Check shutdown. */
388 alts_handshaker_client_shutdown(nullptr);
390 destroy_config(config);
393 static void schedule_request_success_test() {
394 /* Initialization. */
395 alts_handshaker_client_test_config* config = create_config();
396 /* Check client_start success. */
397 alts_handshaker_client_set_grpc_caller_for_testing(
398 config->client, check_client_start_success);
400 grpc_core::ExecCtx exec_ctx;
401 GPR_ASSERT(alts_handshaker_client_start_client(config->client) == TSI_OK);
404 grpc_core::ExecCtx exec_ctx;
405 GPR_ASSERT(alts_handshaker_client_next(nullptr, &config->out_frame) ==
406 TSI_INVALID_ARGUMENT);
408 /* Check server_start success. */
409 alts_handshaker_client_set_grpc_caller_for_testing(
410 config->server, check_server_start_success);
412 grpc_core::ExecCtx exec_ctx;
413 GPR_ASSERT(alts_handshaker_client_start_server(
414 config->server, &config->out_frame) == TSI_OK);
416 /* Check client next success. */
417 alts_handshaker_client_set_grpc_caller_for_testing(config->client,
420 grpc_core::ExecCtx exec_ctx;
421 GPR_ASSERT(alts_handshaker_client_next(config->client,
422 &config->out_frame) == TSI_OK);
424 /* Check server next success. */
425 alts_handshaker_client_set_grpc_caller_for_testing(config->server,
428 grpc_core::ExecCtx exec_ctx;
429 GPR_ASSERT(alts_handshaker_client_next(config->server,
430 &config->out_frame) == TSI_OK);
434 grpc_core::ExecCtx exec_ctx;
435 alts_handshaker_client_on_status_received_for_testing(
436 config->client, GRPC_STATUS_OK, GRPC_ERROR_NONE);
437 alts_handshaker_client_on_status_received_for_testing(
438 config->server, GRPC_STATUS_OK, GRPC_ERROR_NONE);
440 destroy_config(config);
443 static void tsi_cb_assert_tsi_internal_error(
444 tsi_result status, void* /*user_data*/,
445 const unsigned char* /*bytes_to_send*/, size_t /*bytes_to_send_size*/,
446 tsi_handshaker_result* /*result*/) {
447 GPR_ASSERT(status == TSI_INTERNAL_ERROR);
450 static void schedule_request_grpc_call_failure_test() {
451 /* Initialization. */
452 alts_handshaker_client_test_config* config = create_config();
453 /* Check client_start failure. */
454 alts_handshaker_client_set_grpc_caller_for_testing(config->client,
455 check_grpc_call_failure);
457 grpc_core::ExecCtx exec_ctx;
458 // TODO(apolcyn): go back to asserting TSI_INTERNAL_ERROR as return
459 // value instead of callback status, after removing the global
460 // queue in https://github.com/grpc/grpc/pull/20722
461 alts_handshaker_client_set_cb_for_testing(config->client,
462 tsi_cb_assert_tsi_internal_error);
463 alts_handshaker_client_start_client(config->client);
465 /* Check server_start failure. */
466 alts_handshaker_client_set_grpc_caller_for_testing(config->server,
467 check_grpc_call_failure);
469 grpc_core::ExecCtx exec_ctx;
470 // TODO(apolcyn): go back to asserting TSI_INTERNAL_ERROR as return
471 // value instead of callback status, after removing the global
472 // queue in https://github.com/grpc/grpc/pull/20722
473 alts_handshaker_client_set_cb_for_testing(config->server,
474 tsi_cb_assert_tsi_internal_error);
475 alts_handshaker_client_start_server(config->server, &config->out_frame);
478 grpc_core::ExecCtx exec_ctx;
479 /* Check client next failure. */
480 GPR_ASSERT(alts_handshaker_client_next(
481 config->client, &config->out_frame) == TSI_INTERNAL_ERROR);
484 grpc_core::ExecCtx exec_ctx;
485 /* Check server next failure. */
486 GPR_ASSERT(alts_handshaker_client_next(
487 config->server, &config->out_frame) == TSI_INTERNAL_ERROR);
491 grpc_core::ExecCtx exec_ctx;
492 alts_handshaker_client_on_status_received_for_testing(
493 config->client, GRPC_STATUS_OK, GRPC_ERROR_NONE);
494 alts_handshaker_client_on_status_received_for_testing(
495 config->server, GRPC_STATUS_OK, GRPC_ERROR_NONE);
497 destroy_config(config);
500 int main(int argc, char** argv) {
501 grpc::testing::TestEnvironment env(argc, argv);
502 /* Initialization. */
504 grpc_alts_shared_resource_dedicated_init();
506 schedule_request_invalid_arg_test();
507 schedule_request_success_test();
508 schedule_request_grpc_call_failure_test();
510 grpc_alts_shared_resource_dedicated_shutdown();