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 17 #ifndef GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_EXTERNAL_ACCOUNT_CREDENTIALS_H 18 #define GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_EXTERNAL_ACCOUNT_CREDENTIALS_H 19 20 #include <grpc/event_engine/event_engine.h> 21 #include <grpc/support/port_platform.h> 22 #include <stdint.h> 23 24 #include <functional> 25 #include <memory> 26 #include <string> 27 #include <vector> 28 29 #include "absl/strings/string_view.h" 30 #include "src/core/lib/iomgr/closure.h" 31 #include "src/core/lib/iomgr/error.h" 32 #include "src/core/lib/iomgr/polling_entity.h" 33 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h" 34 #include "src/core/lib/security/credentials/token_fetcher/token_fetcher_credentials.h" 35 #include "src/core/util/http_client/httpcli.h" 36 #include "src/core/util/http_client/parser.h" 37 #include "src/core/util/json/json.h" 38 #include "src/core/util/orphanable.h" 39 #include "src/core/util/ref_counted_ptr.h" 40 #include "src/core/util/time.h" 41 42 namespace grpc_core { 43 44 // Base external account credentials. The base class implements common logic for 45 // exchanging external account credentials for GCP access token to authorize 46 // requests to GCP APIs. The specific logic of retrieving subject token is 47 // implemented in subclasses. 48 class ExternalAccountCredentials : public TokenFetcherCredentials { 49 public: 50 struct ServiceAccountImpersonation { 51 int32_t token_lifetime_seconds; 52 }; 53 // External account credentials json interface. 54 struct Options { 55 std::string type; 56 std::string audience; 57 std::string subject_token_type; 58 std::string service_account_impersonation_url; 59 ServiceAccountImpersonation service_account_impersonation; 60 std::string token_url; 61 std::string token_info_url; 62 Json credential_source; 63 std::string quota_project_id; 64 std::string client_id; 65 std::string client_secret; 66 std::string workforce_pool_user_project; 67 }; 68 69 static absl::StatusOr<RefCountedPtr<ExternalAccountCredentials>> Create( 70 const Json& json, std::vector<std::string> scopes, 71 std::shared_ptr<grpc_event_engine::experimental::EventEngine> 72 event_engine = nullptr); 73 74 ExternalAccountCredentials( 75 Options options, std::vector<std::string> scopes, 76 std::shared_ptr<grpc_event_engine::experimental::EventEngine> 77 event_engine = nullptr); 78 ~ExternalAccountCredentials() override; 79 80 protected: 81 // A base class for a cancellable fetch operation. 82 class FetchBody : public InternallyRefCounted<FetchBody> { 83 public: FetchBody(absl::AnyInvocable<void (absl::StatusOr<std::string>)> on_done)84 explicit FetchBody( 85 absl::AnyInvocable<void(absl::StatusOr<std::string>)> on_done) 86 : on_done_(std::move(on_done)) {} 87 Orphan()88 void Orphan() override { 89 Shutdown(); 90 Unref(); 91 } 92 93 protected: 94 // The subclass must call this when the fetch is complete, even if 95 // cancelled. Finish(absl::StatusOr<std::string> result)96 void Finish(absl::StatusOr<std::string> result) { 97 std::exchange(on_done_, nullptr)(std::move(result)); 98 } 99 100 private: 101 virtual void Shutdown() = 0; 102 103 absl::AnyInvocable<void(absl::StatusOr<std::string>)> on_done_; 104 }; 105 106 // A simple no-op implementation, used for async execution of the 107 // on_done callback. 108 class NoOpFetchBody final : public FetchBody { 109 public: 110 NoOpFetchBody(grpc_event_engine::experimental::EventEngine& event_engine, 111 absl::AnyInvocable<void(absl::StatusOr<std::string>)> on_done, 112 absl::StatusOr<std::string> result); 113 114 private: Shutdown()115 void Shutdown() override {} 116 }; 117 118 // An implementation for HTTP requests. 119 class HttpFetchBody final : public FetchBody { 120 public: 121 HttpFetchBody( 122 absl::FunctionRef<OrphanablePtr<HttpRequest>(grpc_http_response*, 123 grpc_closure*)> 124 start_http_request, 125 absl::AnyInvocable<void(absl::StatusOr<std::string>)> on_done); 126 ~HttpFetchBody()127 ~HttpFetchBody() override { grpc_http_response_destroy(&response_); } 128 129 private: Shutdown()130 void Shutdown() override { http_request_.reset(); } 131 132 static void OnHttpResponse(void* arg, grpc_error_handle error); 133 134 OrphanablePtr<HttpRequest> http_request_; 135 grpc_http_response response_; 136 grpc_closure on_http_response_; 137 }; 138 139 // An implementation of TokenFetcherCredentials::FetchRequest that 140 // executes a series of FetchBody operations to ultimately get to a 141 // token result. 142 class ExternalFetchRequest : public FetchRequest { 143 public: 144 ExternalFetchRequest( 145 ExternalAccountCredentials* creds, Timestamp deadline, 146 absl::AnyInvocable< 147 void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)> 148 on_done); 149 150 void Orphan() override; 151 152 protected: deadline()153 Timestamp deadline() const { return deadline_; } pollent()154 grpc_polling_entity* pollent() const { return creds_->pollent(); } options()155 const Options& options() const { return creds_->options_; } 156 157 private: 158 void ExchangeToken(absl::StatusOr<std::string> subject_token); 159 void MaybeImpersonateServiceAccount( 160 absl::StatusOr<std::string> response_body); 161 void OnImpersonateServiceAccount(absl::StatusOr<std::string> response_body); 162 163 void FinishTokenFetch(absl::StatusOr<std::string> response_body); 164 165 // If status is non-OK or we've been shut down, calls FinishTokenFetch() 166 // and returns true. 167 bool MaybeFailLocked(absl::Status status) 168 ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_); 169 170 ExternalAccountCredentials* creds_; 171 Timestamp deadline_; 172 absl::AnyInvocable<void( 173 absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)> 174 on_done_; 175 176 Mutex mu_; 177 OrphanablePtr<FetchBody> fetch_body_ ABSL_GUARDED_BY(&mu_); 178 }; 179 180 virtual absl::string_view CredentialSourceType(); 181 182 std::string MetricsHeaderValue(); 183 audience()184 absl::string_view audience() const { return options_.audience; } 185 186 private: 187 OrphanablePtr<FetchRequest> FetchToken( 188 Timestamp deadline, 189 absl::AnyInvocable<void(absl::StatusOr<RefCountedPtr<Token>>)> on_done) 190 final; 191 192 // Subclasses of ExternalAccountCredentials need to override this 193 // method to implement the specific-subject token retrieval logic. 194 // The caller will save the resulting FetchBody object, which will 195 // be orphaned upon cancellation. The FetchBody object must 196 // eventually invoke on_done. 197 virtual OrphanablePtr<FetchBody> RetrieveSubjectToken( 198 Timestamp deadline, 199 absl::AnyInvocable<void(absl::StatusOr<std::string>)> on_done) = 0; 200 201 Options options_; 202 std::vector<std::string> scopes_; 203 }; 204 205 } // namespace grpc_core 206 207 #endif // GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_EXTERNAL_ACCOUNT_CREDENTIALS_H 208