blob: 586bbed778efb00f6cd90d1931f46cd671bab4bd [file] [log] [blame]
/*
*
* Copyright 2015-2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/composite/composite_credentials.h"
#include <cstring>
#include <new>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/surface/api_trace.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
/* -- Composite call credentials. -- */
static void composite_call_metadata_cb(void* arg, grpc_error* error);
namespace {
struct grpc_composite_call_credentials_metadata_context {
grpc_composite_call_credentials_metadata_context(
grpc_composite_call_credentials* composite_creds,
grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata)
: composite_creds(composite_creds),
pollent(pollent),
auth_md_context(auth_md_context),
md_array(md_array),
on_request_metadata(on_request_metadata) {
GRPC_CLOSURE_INIT(&internal_on_request_metadata, composite_call_metadata_cb,
this, grpc_schedule_on_exec_ctx);
}
grpc_composite_call_credentials* composite_creds;
size_t creds_index = 0;
grpc_polling_entity* pollent;
grpc_auth_metadata_context auth_md_context;
grpc_credentials_mdelem_array* md_array;
grpc_closure* on_request_metadata;
grpc_closure internal_on_request_metadata;
};
} // namespace
static void composite_call_metadata_cb(void* arg, grpc_error* error) {
grpc_composite_call_credentials_metadata_context* ctx =
static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
if (error == GRPC_ERROR_NONE) {
const grpc_composite_call_credentials::CallCredentialsList& inner =
ctx->composite_creds->inner();
/* See if we need to get some more metadata. */
if (ctx->creds_index < inner.size()) {
if (inner[ctx->creds_index++]->get_request_metadata(
ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, &error)) {
// Synchronous response, so call ourselves recursively.
composite_call_metadata_cb(arg, error);
GRPC_ERROR_UNREF(error);
}
return;
}
// We're done!
}
GRPC_CLOSURE_SCHED(ctx->on_request_metadata, GRPC_ERROR_REF(error));
gpr_free(ctx);
}
bool grpc_composite_call_credentials::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) {
grpc_composite_call_credentials_metadata_context* ctx;
ctx = grpc_core::New<grpc_composite_call_credentials_metadata_context>(
this, pollent, auth_md_context, md_array, on_request_metadata);
bool synchronous = true;
const CallCredentialsList& inner = ctx->composite_creds->inner();
while (ctx->creds_index < inner.size()) {
if (inner[ctx->creds_index++]->get_request_metadata(
ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, error)) {
if (*error != GRPC_ERROR_NONE) break;
} else {
synchronous = false; // Async return.
break;
}
}
if (synchronous) grpc_core::Delete(ctx);
return synchronous;
}
void grpc_composite_call_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
for (size_t i = 0; i < inner_.size(); ++i) {
inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
static size_t get_creds_array_size(const grpc_call_credentials* creds,
bool is_composite) {
return is_composite
? static_cast<const grpc_composite_call_credentials*>(creds)
->inner()
.size()
: 1;
}
void grpc_composite_call_credentials::push_to_inner(
grpc_core::RefCountedPtr<grpc_call_credentials> creds, bool is_composite) {
if (!is_composite) {
inner_.push_back(std::move(creds));
return;
}
auto composite_creds =
static_cast<grpc_composite_call_credentials*>(creds.get());
for (size_t i = 0; i < composite_creds->inner().size(); ++i) {
inner_.push_back(std::move(composite_creds->inner_[i]));
}
}
grpc_composite_call_credentials::grpc_composite_call_credentials(
grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
grpc_core::RefCountedPtr<grpc_call_credentials> creds2)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) {
const bool creds1_is_composite =
strcmp(creds1->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
const bool creds2_is_composite =
strcmp(creds2->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
const size_t size = get_creds_array_size(creds1.get(), creds1_is_composite) +
get_creds_array_size(creds2.get(), creds2_is_composite);
inner_.reserve(size);
push_to_inner(std::move(creds1), creds1_is_composite);
push_to_inner(std::move(creds2), creds2_is_composite);
}
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) {
return grpc_core::MakeRefCounted<grpc_composite_call_credentials>(
std::move(creds1), std::move(creds2));
}
grpc_call_credentials* grpc_composite_call_credentials_create(
grpc_call_credentials* creds1, grpc_call_credentials* creds2,
void* reserved) {
GRPC_API_TRACE(
"grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
"reserved=%p)",
3, (creds1, creds2, reserved));
GPR_ASSERT(reserved == nullptr);
GPR_ASSERT(creds1 != nullptr);
GPR_ASSERT(creds2 != nullptr);
return composite_call_credentials_create(creds1->Ref(), creds2->Ref())
.release();
}
/* -- Composite channel credentials. -- */
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_composite_channel_credentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) {
GPR_ASSERT(inner_creds_ != nullptr && call_creds_ != nullptr);
/* If we are passed a call_creds, create a call composite to pass it
downstream. */
if (call_creds != nullptr) {
return inner_creds_->create_security_connector(
composite_call_credentials_create(call_creds_, std::move(call_creds)),
target, args, new_args);
} else {
return inner_creds_->create_security_connector(call_creds_, target, args,
new_args);
}
}
grpc_channel_credentials* grpc_composite_channel_credentials_create(
grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
void* reserved) {
GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr &&
reserved == nullptr);
GRPC_API_TRACE(
"grpc_composite_channel_credentials_create(channel_creds=%p, "
"call_creds=%p, reserved=%p)",
3, (channel_creds, call_creds, reserved));
return grpc_core::New<grpc_composite_channel_credentials>(
channel_creds->Ref(), call_creds->Ref());
}