• 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 ** error)29 FileExternalAccountCredentials::Create(Options options,
30                                        std::vector<std::string> scopes,
31                                        grpc_error** 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 ** error)41 FileExternalAccountCredentials::FileExternalAccountCredentials(
42     Options options, std::vector<std::string> scopes, grpc_error** 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 * ctx,const Options & options,std::function<void (std::string,grpc_error *)> cb)93 void FileExternalAccountCredentials::RetrieveSubjectToken(
94     HTTPRequestContext* ctx, const Options& options,
95     std::function<void(std::string, grpc_error*)> 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* error = grpc_load_file(file_.c_str(), 0, &content_slice.slice);
104   if (error != GRPC_ERROR_NONE) {
105     cb("", error);
106     return;
107   }
108   absl::string_view content = StringViewFromSlice(content_slice.slice);
109   if (format_type_ == "json") {
110     Json content_json = Json::Parse(content, &error);
111     if (error != GRPC_ERROR_NONE || content_json.type() != Json::Type::OBJECT) {
112       cb("", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
113                  "The content of the file is not a valid json object."));
114       GRPC_ERROR_UNREF(error);
115       return;
116     }
117     auto content_it =
118         content_json.object_value().find(format_subject_token_field_name_);
119     if (content_it == content_json.object_value().end()) {
120       cb("", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
121                  "Subject token field not present."));
122       return;
123     }
124     if (content_it->second.type() != Json::Type::STRING) {
125       cb("", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
126                  "Subject token field must be a string."));
127       return;
128     }
129     cb(content_it->second.string_value(), GRPC_ERROR_NONE);
130     return;
131   }
132   cb(std::string(content), GRPC_ERROR_NONE);
133 }
134 
135 }  // namespace grpc_core
136