1 //
2 // Copyright 2022 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "src/core/lib/security/credentials/call_creds_util.h"
18
19 #include <grpc/support/port_platform.h>
20 #include <grpc/support/string_util.h>
21 #include <string.h>
22
23 #include "absl/log/check.h"
24 #include "absl/log/log.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27 #include "src/core/lib/security/context/security_context.h"
28 #include "src/core/lib/security/security_connector/security_connector.h"
29 #include "src/core/lib/transport/metadata_batch.h"
30 #include "src/core/util/ref_counted_ptr.h"
31
32 namespace grpc_core {
33
34 namespace {
35
36 struct ServiceUrlAndMethod {
37 std::string service_url;
38 absl::string_view method_name;
39 };
40
MakeServiceUrlAndMethod(const ClientMetadataHandle & initial_metadata,const grpc_call_credentials::GetRequestMetadataArgs * args)41 ServiceUrlAndMethod MakeServiceUrlAndMethod(
42 const ClientMetadataHandle& initial_metadata,
43 const grpc_call_credentials::GetRequestMetadataArgs* args) {
44 DCHECK(initial_metadata->get_pointer(HttpPathMetadata()) != nullptr);
45 auto service =
46 initial_metadata->get_pointer(HttpPathMetadata())->as_string_view();
47 auto last_slash = service.find_last_of('/');
48 absl::string_view method_name;
49 if (last_slash == absl::string_view::npos) {
50 LOG(ERROR) << "No '/' found in fully qualified method name";
51 service = "";
52 method_name = "";
53 } else if (last_slash == 0) {
54 method_name = "";
55 } else {
56 method_name = service.substr(last_slash + 1);
57 service = service.substr(0, last_slash);
58 }
59 DCHECK(initial_metadata->get_pointer(HttpAuthorityMetadata()) != nullptr);
60 auto host_and_port =
61 initial_metadata->get_pointer(HttpAuthorityMetadata())->as_string_view();
62 absl::string_view url_scheme = args->security_connector->url_scheme();
63 if (url_scheme == GRPC_SSL_URL_SCHEME) {
64 // Remove the port if it is 443.
65 auto port_delimiter = host_and_port.find_last_of(':');
66 if (port_delimiter != absl::string_view::npos &&
67 host_and_port.substr(port_delimiter + 1) == "443") {
68 host_and_port = host_and_port.substr(0, port_delimiter);
69 }
70 }
71 return ServiceUrlAndMethod{
72 absl::StrCat(url_scheme, "://", host_and_port, service), method_name};
73 }
74
75 } // namespace
76
MakeJwtServiceUrl(const ClientMetadataHandle & initial_metadata,const grpc_call_credentials::GetRequestMetadataArgs * args)77 std::string MakeJwtServiceUrl(
78 const ClientMetadataHandle& initial_metadata,
79 const grpc_call_credentials::GetRequestMetadataArgs* args) {
80 return MakeServiceUrlAndMethod(initial_metadata, args).service_url;
81 }
82
MakePluginAuthMetadataContext(const ClientMetadataHandle & initial_metadata,const grpc_call_credentials::GetRequestMetadataArgs * args)83 grpc_auth_metadata_context MakePluginAuthMetadataContext(
84 const ClientMetadataHandle& initial_metadata,
85 const grpc_call_credentials::GetRequestMetadataArgs* args) {
86 auto fields = MakeServiceUrlAndMethod(initial_metadata, args);
87 grpc_auth_metadata_context ctx;
88 memset(&ctx, 0, sizeof(ctx));
89 ctx.channel_auth_context = args->auth_context != nullptr
90 ? args->auth_context->Ref().release()
91 : nullptr;
92 ctx.service_url = gpr_strdup(fields.service_url.c_str());
93 ctx.method_name = gpr_strdup(std::string(fields.method_name).c_str());
94 return ctx;
95 }
96
97 } // namespace grpc_core
98