3 * Copyright 2015-2016 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 <grpc/support/port_platform.h>
21 #include "src/core/lib/security/credentials/composite/composite_credentials.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_join.h"
29 #include "src/core/lib/gprpp/ref_counted_ptr.h"
30 #include "src/core/lib/iomgr/polling_entity.h"
31 #include "src/core/lib/surface/api_trace.h"
33 #include <grpc/support/alloc.h>
34 #include <grpc/support/log.h>
35 #include <grpc/support/string_util.h>
37 /* -- Composite call credentials. -- */
39 static void composite_call_metadata_cb(void* arg, grpc_error_handle error);
42 struct grpc_composite_call_credentials_metadata_context {
43 grpc_composite_call_credentials_metadata_context(
44 grpc_composite_call_credentials* composite_creds,
45 grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
46 grpc_credentials_mdelem_array* md_array,
47 grpc_closure* on_request_metadata)
48 : composite_creds(composite_creds),
50 auth_md_context(auth_md_context),
52 on_request_metadata(on_request_metadata) {
53 GRPC_CLOSURE_INIT(&internal_on_request_metadata, composite_call_metadata_cb,
54 this, grpc_schedule_on_exec_ctx);
57 grpc_composite_call_credentials* composite_creds;
58 size_t creds_index = 0;
59 grpc_polling_entity* pollent;
60 grpc_auth_metadata_context auth_md_context;
61 grpc_credentials_mdelem_array* md_array;
62 grpc_closure* on_request_metadata;
63 grpc_closure internal_on_request_metadata;
67 static void composite_call_metadata_cb(void* arg, grpc_error_handle error) {
68 grpc_composite_call_credentials_metadata_context* ctx =
69 static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
70 if (error == GRPC_ERROR_NONE) {
71 const grpc_composite_call_credentials::CallCredentialsList& inner =
72 ctx->composite_creds->inner();
73 /* See if we need to get some more metadata. */
74 if (ctx->creds_index < inner.size()) {
75 if (inner[ctx->creds_index++]->get_request_metadata(
76 ctx->pollent, ctx->auth_md_context, ctx->md_array,
77 &ctx->internal_on_request_metadata, &error)) {
78 // Synchronous response, so call ourselves recursively.
79 composite_call_metadata_cb(arg, error);
80 GRPC_ERROR_UNREF(error);
86 grpc_core::ExecCtx::Run(DEBUG_LOCATION, ctx->on_request_metadata,
87 GRPC_ERROR_REF(error));
91 bool grpc_composite_call_credentials::get_request_metadata(
92 grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
93 grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
94 grpc_error_handle* error) {
95 grpc_composite_call_credentials_metadata_context* ctx;
96 ctx = new grpc_composite_call_credentials_metadata_context(
97 this, pollent, auth_md_context, md_array, on_request_metadata);
98 bool synchronous = true;
99 const CallCredentialsList& inner = ctx->composite_creds->inner();
100 while (ctx->creds_index < inner.size()) {
101 if (inner[ctx->creds_index++]->get_request_metadata(
102 ctx->pollent, ctx->auth_md_context, ctx->md_array,
103 &ctx->internal_on_request_metadata, error)) {
104 if (*error != GRPC_ERROR_NONE) break;
106 synchronous = false; // Async return.
110 if (synchronous) delete ctx;
114 void grpc_composite_call_credentials::cancel_get_request_metadata(
115 grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
116 for (size_t i = 0; i < inner_.size(); ++i) {
117 inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
119 GRPC_ERROR_UNREF(error);
122 std::string grpc_composite_call_credentials::debug_string() {
123 std::vector<std::string> outputs;
124 for (auto& inner_cred : inner_) {
125 outputs.emplace_back(inner_cred->debug_string());
127 return absl::StrCat("CompositeCallCredentials{", absl::StrJoin(outputs, ","),
131 static size_t get_creds_array_size(const grpc_call_credentials* creds,
134 ? static_cast<const grpc_composite_call_credentials*>(creds)
140 void grpc_composite_call_credentials::push_to_inner(
141 grpc_core::RefCountedPtr<grpc_call_credentials> creds, bool is_composite) {
143 inner_.push_back(std::move(creds));
146 auto composite_creds =
147 static_cast<grpc_composite_call_credentials*>(creds.get());
148 for (size_t i = 0; i < composite_creds->inner().size(); ++i) {
149 inner_.push_back(std::move(composite_creds->inner_[i]));
153 grpc_composite_call_credentials::grpc_composite_call_credentials(
154 grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
155 grpc_core::RefCountedPtr<grpc_call_credentials> creds2)
156 : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) {
157 const bool creds1_is_composite =
158 strcmp(creds1->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
159 const bool creds2_is_composite =
160 strcmp(creds2->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
161 const size_t size = get_creds_array_size(creds1.get(), creds1_is_composite) +
162 get_creds_array_size(creds2.get(), creds2_is_composite);
163 inner_.reserve(size);
164 push_to_inner(std::move(creds1), creds1_is_composite);
165 push_to_inner(std::move(creds2), creds2_is_composite);
166 min_security_level_ = GRPC_SECURITY_NONE;
167 for (size_t i = 0; i < inner_.size(); ++i) {
168 if (static_cast<int>(min_security_level_) <
169 static_cast<int>(inner_[i]->min_security_level())) {
170 min_security_level_ = inner_[i]->min_security_level();
175 static grpc_core::RefCountedPtr<grpc_call_credentials>
176 composite_call_credentials_create(
177 grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
178 grpc_core::RefCountedPtr<grpc_call_credentials> creds2) {
179 return grpc_core::MakeRefCounted<grpc_composite_call_credentials>(
180 std::move(creds1), std::move(creds2));
183 grpc_call_credentials* grpc_composite_call_credentials_create(
184 grpc_call_credentials* creds1, grpc_call_credentials* creds2,
187 "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
189 3, (creds1, creds2, reserved));
190 GPR_ASSERT(reserved == nullptr);
191 GPR_ASSERT(creds1 != nullptr);
192 GPR_ASSERT(creds2 != nullptr);
194 return composite_call_credentials_create(creds1->Ref(), creds2->Ref())
198 /* -- Composite channel credentials. -- */
200 grpc_core::RefCountedPtr<grpc_channel_security_connector>
201 grpc_composite_channel_credentials::create_security_connector(
202 grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
203 const char* target, const grpc_channel_args* args,
204 grpc_channel_args** new_args) {
205 GPR_ASSERT(inner_creds_ != nullptr && call_creds_ != nullptr);
206 /* If we are passed a call_creds, create a call composite to pass it
208 if (call_creds != nullptr) {
209 return inner_creds_->create_security_connector(
210 composite_call_credentials_create(call_creds_, std::move(call_creds)),
211 target, args, new_args);
213 return inner_creds_->create_security_connector(call_creds_, target, args,
218 grpc_channel_credentials* grpc_composite_channel_credentials_create(
219 grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
221 GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr &&
222 reserved == nullptr);
224 "grpc_composite_channel_credentials_create(channel_creds=%p, "
225 "call_creds=%p, reserved=%p)",
226 3, (channel_creds, call_creds, reserved));
227 return new grpc_composite_channel_credentials(channel_creds->Ref(),