5543ad1a24467fa69fa8023deec915bd1dbee1c2
[platform/upstream/grpc.git] / src / core / lib / security / credentials / composite / composite_credentials.cc
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_handle error);
40
41 namespace {
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),
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
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);
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
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;
105     } else {
106       synchronous = false;  // Async return.
107       break;
108     }
109   }
110   if (synchronous) delete ctx;
111   return synchronous;
112 }
113
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));
118   }
119   GRPC_ERROR_UNREF(error);
120 }
121
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
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
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
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>
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
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>
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
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 }