• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 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 #include <grpc/support/port_platform.h>
17 
18 #include "src/core/lib/security/credentials/external/file_external_account_credentials.h"
19 
20 #include <fstream>
21 
22 #include "src/core/lib/iomgr/load_file.h"
23 #include "src/core/lib/slice/slice_internal.h"
24 #include "src/core/lib/slice/slice_utils.h"
25 
26 namespace grpc_core {
27 
28 RefCountedPtr<FileExternalAccountCredentials>
Create(Options options,std::vector<std::string> scopes,grpc_error_handle * error)29 FileExternalAccountCredentials::Create(Options options,
30                                        std::vector<std::string> scopes,
31                                        grpc_error_handle* error) {
32   auto creds = MakeRefCounted<FileExternalAccountCredentials>(
33       std::move(options), std::move(scopes), error);
34   if (*error == GRPC_ERROR_NONE) {
35     return creds;
36   } else {
37     return nullptr;
38   }
39 }
40 
FileExternalAccountCredentials(Options options,std::vector<std::string> scopes,grpc_error_handle * error)41 FileExternalAccountCredentials::FileExternalAccountCredentials(
42     Options options, std::vector<std::string> scopes, grpc_error_handle* error)
43     : ExternalAccountCredentials(options, std::move(scopes)) {
44   auto it = options.credential_source.object_value().find("file");
45   if (it == options.credential_source.object_value().end()) {
46     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("file field not present.");
47     return;
48   }
49   if (it->second.type() != Json::Type::STRING) {
50     *error =
51         GRPC_ERROR_CREATE_FROM_STATIC_STRING("file field must be a string.");
52     return;
53   }
54   file_ = it->second.string_value();
55   it = options.credential_source.object_value().find("format");
56   if (it != options.credential_source.object_value().end()) {
57     const Json& format_json = it->second;
58     if (format_json.type() != Json::Type::OBJECT) {
59       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
60           "The JSON value of credential source format is not an object.");
61       return;
62     }
63     auto format_it = format_json.object_value().find("type");
64     if (format_it == format_json.object_value().end()) {
65       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
66           "format.type field not present.");
67       return;
68     }
69     if (format_it->second.type() != Json::Type::STRING) {
70       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
71           "format.type field must be a string.");
72       return;
73     }
74     format_type_ = format_it->second.string_value();
75     if (format_type_ == "json") {
76       format_it = format_json.object_value().find("subject_token_field_name");
77       if (format_it == format_json.object_value().end()) {
78         *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
79             "format.subject_token_field_name field must be present if the "
80             "format is in Json.");
81         return;
82       }
83       if (format_it->second.type() != Json::Type::STRING) {
84         *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
85             "format.subject_token_field_name field must be a string.");
86         return;
87       }
88       format_subject_token_field_name_ = format_it->second.string_value();
89     }
90   }
91 }
92 
RetrieveSubjectToken(HTTPRequestContext *,const Options &,std::function<void (std::string,grpc_error_handle)> cb)93 void FileExternalAccountCredentials::RetrieveSubjectToken(
94     HTTPRequestContext* /*ctx*/, const Options& /*options*/,
95     std::function<void(std::string, grpc_error_handle)> cb) {
96   struct SliceWrapper {
97     ~SliceWrapper() { grpc_slice_unref_internal(slice); }
98     grpc_slice slice = grpc_empty_slice();
99   };
100   SliceWrapper content_slice;
101   // To retrieve the subject token, we read the file every time we make a
102   // request because it may have changed since the last request.
103   grpc_error_handle error =
104       grpc_load_file(file_.c_str(), 0, &content_slice.slice);
105   if (error != GRPC_ERROR_NONE) {
106     cb("", error);
107     return;
108   }
109   absl::string_view content = StringViewFromSlice(content_slice.slice);
110   if (format_type_ == "json") {
111     Json content_json = Json::Parse(content, &error);
112     if (error != GRPC_ERROR_NONE || content_json.type() != Json::Type::OBJECT) {
113       cb("", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
114                  "The content of the file is not a valid json object."));
115       GRPC_ERROR_UNREF(error);
116       return;
117     }
118     auto content_it =
119         content_json.object_value().find(format_subject_token_field_name_);
120     if (content_it == content_json.object_value().end()) {
121       cb("", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
122                  "Subject token field not present."));
123       return;
124     }
125     if (content_it->second.type() != Json::Type::STRING) {
126       cb("", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
127                  "Subject token field must be a string."));
128       return;
129     }
130     cb(content_it->second.string_value(), GRPC_ERROR_NONE);
131     return;
132   }
133   cb(std::string(content), GRPC_ERROR_NONE);
134 }
135 
136 }  // namespace grpc_core
137