1 /*
2 *
3 * Copyright 2015-2016 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 <grpc/support/port_platform.h>
20
21 #include "src/core/lib/security/credentials/composite/composite_credentials.h"
22
23 #include <cstring>
24 #include <new>
25 #include <vector>
26
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"
32
33 #include <grpc/support/alloc.h>
34 #include <grpc/support/log.h>
35 #include <grpc/support/string_util.h>
36
37 /* -- Composite call credentials. -- */
38
39 static void composite_call_metadata_cb(void* arg, grpc_error* error);
40
41 namespace {
42 struct grpc_composite_call_credentials_metadata_context {
grpc_composite_call_credentials_metadata_context__anon15365aad0111::grpc_composite_call_credentials_metadata_context43 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),
49 pollent(pollent),
50 auth_md_context(auth_md_context),
51 md_array(md_array),
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);
55 }
56
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;
64 };
65 } // namespace
66
composite_call_metadata_cb(void * arg,grpc_error * error)67 static void composite_call_metadata_cb(void* arg, grpc_error* 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);
81 }
82 return;
83 }
84 // We're done!
85 }
86 grpc_core::ExecCtx::Run(DEBUG_LOCATION, ctx->on_request_metadata,
87 GRPC_ERROR_REF(error));
88 delete ctx;
89 }
90
get_request_metadata(grpc_polling_entity * pollent,grpc_auth_metadata_context auth_md_context,grpc_credentials_mdelem_array * md_array,grpc_closure * on_request_metadata,grpc_error ** 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** 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;
105 } else {
106 synchronous = false; // Async return.
107 break;
108 }
109 }
110 if (synchronous) delete ctx;
111 return synchronous;
112 }
113
cancel_get_request_metadata(grpc_credentials_mdelem_array * md_array,grpc_error * error)114 void grpc_composite_call_credentials::cancel_get_request_metadata(
115 grpc_credentials_mdelem_array* md_array, grpc_error* error) {
116 for (size_t i = 0; i < inner_.size(); ++i) {
117 inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
118 }
119 GRPC_ERROR_UNREF(error);
120 }
121
debug_string()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());
126 }
127 return absl::StrCat("CompositeCallCredentials{", absl::StrJoin(outputs, ","),
128 "}");
129 }
130
get_creds_array_size(const grpc_call_credentials * creds,bool is_composite)131 static size_t get_creds_array_size(const grpc_call_credentials* creds,
132 bool is_composite) {
133 return is_composite
134 ? static_cast<const grpc_composite_call_credentials*>(creds)
135 ->inner()
136 .size()
137 : 1;
138 }
139
push_to_inner(grpc_core::RefCountedPtr<grpc_call_credentials> creds,bool is_composite)140 void grpc_composite_call_credentials::push_to_inner(
141 grpc_core::RefCountedPtr<grpc_call_credentials> creds, bool is_composite) {
142 if (!is_composite) {
143 inner_.push_back(std::move(creds));
144 return;
145 }
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]));
150 }
151 }
152
grpc_composite_call_credentials(grpc_core::RefCountedPtr<grpc_call_credentials> creds1,grpc_core::RefCountedPtr<grpc_call_credentials> creds2)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();
171 }
172 }
173 }
174
175 static grpc_core::RefCountedPtr<grpc_call_credentials>
composite_call_credentials_create(grpc_core::RefCountedPtr<grpc_call_credentials> creds1,grpc_core::RefCountedPtr<grpc_call_credentials> creds2)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));
181 }
182
grpc_composite_call_credentials_create(grpc_call_credentials * creds1,grpc_call_credentials * creds2,void * reserved)183 grpc_call_credentials* grpc_composite_call_credentials_create(
184 grpc_call_credentials* creds1, grpc_call_credentials* creds2,
185 void* reserved) {
186 GRPC_API_TRACE(
187 "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
188 "reserved=%p)",
189 3, (creds1, creds2, reserved));
190 GPR_ASSERT(reserved == nullptr);
191 GPR_ASSERT(creds1 != nullptr);
192 GPR_ASSERT(creds2 != nullptr);
193
194 return composite_call_credentials_create(creds1->Ref(), creds2->Ref())
195 .release();
196 }
197
198 /* -- Composite channel credentials. -- */
199
200 grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,const char * target,const grpc_channel_args * args,grpc_channel_args ** new_args)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
207 downstream. */
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);
212 } else {
213 return inner_creds_->create_security_connector(call_creds_, target, args,
214 new_args);
215 }
216 }
217
grpc_composite_channel_credentials_create(grpc_channel_credentials * channel_creds,grpc_call_credentials * call_creds,void * reserved)218 grpc_channel_credentials* grpc_composite_channel_credentials_create(
219 grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
220 void* reserved) {
221 GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr &&
222 reserved == nullptr);
223 GRPC_API_TRACE(
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(),
228 call_creds->Ref());
229 }
230