mirror of https://github.com/grpc/grpc.git
parent
384a6f8d51
commit
4c93d36d08
19 changed files with 449 additions and 4 deletions
@ -0,0 +1,211 @@ |
||||
//
|
||||
// Copyright 2020 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/external/url_external_account_credentials.h" |
||||
|
||||
#include "absl/strings/str_format.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
RefCountedPtr<UrlExternalAccountCredentials> |
||||
UrlExternalAccountCredentials::Create(ExternalAccountCredentialsOptions options, |
||||
std::vector<std::string> scopes, |
||||
grpc_error** error) { |
||||
auto creds = MakeRefCounted<UrlExternalAccountCredentials>( |
||||
std::move(options), std::move(scopes), error); |
||||
if (*error == GRPC_ERROR_NONE) { |
||||
return creds; |
||||
} else { |
||||
return nullptr; |
||||
} |
||||
} |
||||
|
||||
UrlExternalAccountCredentials::UrlExternalAccountCredentials( |
||||
ExternalAccountCredentialsOptions options, std::vector<std::string> scopes, |
||||
grpc_error** error) |
||||
: ExternalAccountCredentials(options, std::move(scopes)) { |
||||
auto it = options.credential_source.object_value().find("url"); |
||||
if (it == options.credential_source.object_value().end()) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("url field not present."); |
||||
return; |
||||
} |
||||
if (it->second.type() != Json::Type::STRING) { |
||||
*error = |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("url field must be a string."); |
||||
return; |
||||
} |
||||
grpc_uri* url = grpc_uri_parse(it->second.string_value(), false); |
||||
if (url == nullptr) { |
||||
*error = |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid credential source url."); |
||||
return; |
||||
} |
||||
url_ = url; |
||||
it = options.credential_source.object_value().find("headers"); |
||||
if (it != options.credential_source.object_value().end()) { |
||||
if (it->second.type() != Json::Type::OBJECT) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"The JSON value of credential source headers is not an object."); |
||||
return; |
||||
} |
||||
for (auto const& header : it->second.object_value()) { |
||||
headers_[header.first] = header.second.string_value(); |
||||
} |
||||
} |
||||
it = options.credential_source.object_value().find("format"); |
||||
if (it != options.credential_source.object_value().end()) { |
||||
const Json& format_json = it->second; |
||||
if (format_json.type() != Json::Type::OBJECT) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"The JSON value of credential source format is not an object."); |
||||
return; |
||||
} |
||||
auto format_it = format_json.object_value().find("type"); |
||||
if (format_it == format_json.object_value().end()) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"format.type field not present."); |
||||
return; |
||||
} |
||||
if (format_it->second.type() != Json::Type::STRING) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"format.type field must be a string."); |
||||
return; |
||||
} |
||||
format_type_ = format_it->second.string_value(); |
||||
if (format_type_ == "json") { |
||||
format_it = format_json.object_value().find("subject_token_field_name"); |
||||
if (format_it == format_json.object_value().end()) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"format.subject_token_field_name field must be present if the " |
||||
"format is in Json."); |
||||
return; |
||||
} |
||||
if (format_it->second.type() != Json::Type::STRING) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"format.subject_token_field_name field must be a string."); |
||||
return; |
||||
} |
||||
format_subject_token_field_name_ = format_it->second.string_value(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
UrlExternalAccountCredentials::~UrlExternalAccountCredentials() { |
||||
grpc_uri_destroy(url_); |
||||
} |
||||
|
||||
void UrlExternalAccountCredentials::RetrieveSubjectToken( |
||||
HTTPRequestContext* ctx, const ExternalAccountCredentialsOptions& options, |
||||
std::function<void(std::string, grpc_error*)> cb) { |
||||
if (ctx == nullptr) { |
||||
FinishRetrieveSubjectToken( |
||||
"", |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Missing HTTPRequestContext to start subject token retrieval.")); |
||||
return; |
||||
} |
||||
ctx_ = ctx; |
||||
cb_ = cb; |
||||
grpc_httpcli_request request; |
||||
memset(&request, 0, sizeof(grpc_httpcli_request)); |
||||
request.host = const_cast<char*>(url_->authority); |
||||
request.http.path = gpr_strdup(url_->path); |
||||
grpc_http_header* headers = nullptr; |
||||
request.http.hdr_count = headers_.size(); |
||||
headers = static_cast<grpc_http_header*>( |
||||
gpr_malloc(sizeof(grpc_http_header) * request.http.hdr_count)); |
||||
int i = 0; |
||||
for (auto const& header : headers_) { |
||||
headers[i].key = gpr_strdup(header.first.c_str()); |
||||
headers[i].value = gpr_strdup(header.second.c_str()); |
||||
++i; |
||||
} |
||||
request.http.hdrs = headers; |
||||
request.handshaker = (strcmp(url_->scheme, "https") == 0) |
||||
? &grpc_httpcli_ssl |
||||
: &grpc_httpcli_plaintext; |
||||
grpc_resource_quota* resource_quota = |
||||
grpc_resource_quota_create("external_account_credentials"); |
||||
grpc_http_response_destroy(&ctx_->response); |
||||
ctx_->response = {}; |
||||
GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveSubjectToken, this, nullptr); |
||||
grpc_httpcli_get(ctx_->httpcli_context, ctx_->pollent, resource_quota, |
||||
&request, ctx_->deadline, &ctx_->closure, &ctx_->response); |
||||
grpc_resource_quota_unref_internal(resource_quota); |
||||
grpc_http_request_destroy(&request.http); |
||||
} |
||||
|
||||
void UrlExternalAccountCredentials::OnRetrieveSubjectToken(void* arg, |
||||
grpc_error* error) { |
||||
UrlExternalAccountCredentials* self = |
||||
static_cast<UrlExternalAccountCredentials*>(arg); |
||||
self->OnRetrieveSubjectTokenInternal(GRPC_ERROR_REF(error)); |
||||
} |
||||
|
||||
void UrlExternalAccountCredentials::OnRetrieveSubjectTokenInternal( |
||||
grpc_error* error) { |
||||
if (error != GRPC_ERROR_NONE) { |
||||
FinishRetrieveSubjectToken("", error); |
||||
return; |
||||
} |
||||
absl::string_view response_body(ctx_->response.body, |
||||
ctx_->response.body_length); |
||||
if (format_type_ == "json") { |
||||
grpc_error* error = GRPC_ERROR_NONE; |
||||
Json response_json = Json::Parse(response_body, &error); |
||||
if (error != GRPC_ERROR_NONE || |
||||
response_json.type() != Json::Type::OBJECT) { |
||||
FinishRetrieveSubjectToken( |
||||
"", GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"The format of response is not a valid json object.")); |
||||
return; |
||||
} |
||||
auto response_it = |
||||
response_json.object_value().find(format_subject_token_field_name_); |
||||
if (response_it == response_json.object_value().end()) { |
||||
FinishRetrieveSubjectToken("", GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Subject token field not present.")); |
||||
return; |
||||
} |
||||
if (response_it->second.type() != Json::Type::STRING) { |
||||
FinishRetrieveSubjectToken("", |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Subject token field must be a string.")); |
||||
return; |
||||
} |
||||
FinishRetrieveSubjectToken(response_it->second.string_value(), error); |
||||
return; |
||||
} |
||||
FinishRetrieveSubjectToken(std::string(response_body), GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
void UrlExternalAccountCredentials::FinishRetrieveSubjectToken( |
||||
std::string subject_token, grpc_error* error) { |
||||
// Reset context
|
||||
ctx_ = nullptr; |
||||
// Move object state into local variables.
|
||||
auto cb = cb_; |
||||
cb_ = nullptr; |
||||
// Invoke the callback.
|
||||
if (error != GRPC_ERROR_NONE) { |
||||
cb("", error); |
||||
} else { |
||||
cb(subject_token, GRPC_ERROR_NONE); |
||||
} |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,59 @@ |
||||
//
|
||||
// Copyright 2020 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.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_URL_EXTERNAL_ACCOUNT_CREDENTIALS_H |
||||
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_URL_EXTERNAL_ACCOUNT_CREDENTIALS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/credentials/external/external_account_credentials.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
class UrlExternalAccountCredentials final : public ExternalAccountCredentials { |
||||
public: |
||||
static RefCountedPtr<UrlExternalAccountCredentials> Create( |
||||
ExternalAccountCredentialsOptions options, |
||||
std::vector<std::string> scopes, grpc_error** error); |
||||
|
||||
UrlExternalAccountCredentials(ExternalAccountCredentialsOptions options, |
||||
std::vector<std::string> scopes, |
||||
grpc_error** error); |
||||
~UrlExternalAccountCredentials() override; |
||||
|
||||
private: |
||||
void RetrieveSubjectToken( |
||||
HTTPRequestContext* ctx, const ExternalAccountCredentialsOptions& options, |
||||
std::function<void(std::string, grpc_error*)> cb) override; |
||||
|
||||
static void OnRetrieveSubjectToken(void* arg, grpc_error* error); |
||||
void OnRetrieveSubjectTokenInternal(grpc_error* error); |
||||
|
||||
void FinishRetrieveSubjectToken(std::string subject_token, grpc_error* error); |
||||
|
||||
// Fields of credential source
|
||||
grpc_uri* url_ = nullptr; |
||||
std::map<std::string, std::string> headers_; |
||||
std::string format_type_; |
||||
std::string format_subject_token_field_name_; |
||||
|
||||
HTTPRequestContext* ctx_ = nullptr; |
||||
std::function<void(std::string, grpc_error*)> cb_ = nullptr; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_URL_EXTERNAL_ACCOUNT_CREDENTIALS_H
|
Loading…
Reference in new issue