• 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 
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