1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #ifndef GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H
20 #define GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H
21 
22 #include <grpc/support/port_platform.h>
23 
24 #include <atomic>
25 #include <initializer_list>
26 #include <string>
27 #include <utility>
28 
29 #include "absl/status/statusor.h"
30 #include "absl/types/optional.h"
31 
32 #include <grpc/grpc_security.h>
33 #include <grpc/support/sync.h>
34 #include <grpc/support/time.h>
35 
36 #include "src/core/lib/gpr/useful.h"
37 #include "src/core/lib/gprpp/orphanable.h"
38 #include "src/core/lib/gprpp/ref_counted.h"
39 #include "src/core/lib/gprpp/ref_counted_ptr.h"
40 #include "src/core/lib/gprpp/time.h"
41 #include "src/core/lib/gprpp/unique_type_name.h"
42 #include "src/core/lib/http/httpcli.h"
43 #include "src/core/lib/http/parser.h"
44 #include "src/core/lib/iomgr/closure.h"
45 #include "src/core/lib/iomgr/error.h"
46 #include "src/core/lib/iomgr/polling_entity.h"
47 #include "src/core/lib/json/json.h"
48 #include "src/core/lib/promise/activity.h"
49 #include "src/core/lib/promise/arena_promise.h"
50 #include "src/core/lib/security/credentials/credentials.h"
51 #include "src/core/lib/slice/slice.h"
52 #include "src/core/lib/transport/transport.h"
53 #include "src/core/lib/uri/uri_parser.h"
54 
55 // Constants.
56 #define GRPC_STS_POST_MINIMAL_BODY_FORMAT_STRING                               \
57   "grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=%" \
58   "s&subject_token_type=%s"
59 
60 // auth_refresh_token parsing.
61 struct grpc_auth_refresh_token {
62   const char* type;
63   char* client_id;
64   char* client_secret;
65   char* refresh_token;
66 };
67 /// Returns 1 if the object is valid, 0 otherwise.
68 int grpc_auth_refresh_token_is_valid(
69     const grpc_auth_refresh_token* refresh_token);
70 
71 /// Creates a refresh token object from string. Returns an invalid object if a
72 /// parsing error has been encountered.
73 grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
74     const char* json_string);
75 
76 /// Creates a refresh token object from parsed json. Returns an invalid object
77 /// if a parsing error has been encountered.
78 grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
79     const grpc_core::Json& json);
80 
81 /// Destructs the object.
82 void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token* refresh_token);
83 
84 // -- Credentials Metadata Request. --
85 
86 struct grpc_credentials_metadata_request {
grpc_credentials_metadata_requestgrpc_credentials_metadata_request87   explicit grpc_credentials_metadata_request(
88       grpc_core::RefCountedPtr<grpc_call_credentials> creds)
89       : creds(std::move(creds)) {}
~grpc_credentials_metadata_requestgrpc_credentials_metadata_request90   ~grpc_credentials_metadata_request() {
91     grpc_http_response_destroy(&response);
92   }
93 
94   grpc_core::RefCountedPtr<grpc_call_credentials> creds;
95   grpc_http_response response;
96 };
97 
98 struct grpc_oauth2_pending_get_request_metadata
99     : public grpc_core::RefCounted<grpc_oauth2_pending_get_request_metadata> {
100   std::atomic<bool> done{false};
101   grpc_core::Waker waker;
102   grpc_polling_entity* pollent;
103   grpc_core::ClientMetadataHandle md;
104   struct grpc_oauth2_pending_get_request_metadata* next;
105   absl::StatusOr<grpc_core::Slice> result;
106 };
107 
108 // -- Oauth2 Token Fetcher credentials --
109 //
110 //  This object is a base for credentials that need to acquire an oauth2 token
111 //  from an http service.
112 
113 class grpc_oauth2_token_fetcher_credentials : public grpc_call_credentials {
114  public:
115   grpc_oauth2_token_fetcher_credentials();
116   ~grpc_oauth2_token_fetcher_credentials() override;
117 
118   grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientMetadataHandle>>
119   GetRequestMetadata(grpc_core::ClientMetadataHandle initial_metadata,
120                      const GetRequestMetadataArgs* args) override;
121 
122   void on_http_response(grpc_credentials_metadata_request* r,
123                         grpc_error_handle error);
124   std::string debug_string() override;
125 
126   grpc_core::UniqueTypeName type() const override;
127 
128  protected:
129   virtual void fetch_oauth2(grpc_credentials_metadata_request* req,
130                             grpc_polling_entity* pollent, grpc_iomgr_cb_func cb,
131                             grpc_core::Timestamp deadline) = 0;
132 
133  private:
cmp_impl(const grpc_call_credentials * other)134   int cmp_impl(const grpc_call_credentials* other) const override {
135     // TODO(yashykt): Check if we can do something better here
136     return grpc_core::QsortCompare(
137         static_cast<const grpc_call_credentials*>(this), other);
138   }
139 
140   gpr_mu mu_;
141   absl::optional<grpc_core::Slice> access_token_value_;
142   gpr_timespec token_expiration_;
143   bool token_fetch_pending_ = false;
144   grpc_oauth2_pending_get_request_metadata* pending_requests_ = nullptr;
145   grpc_polling_entity pollent_;
146 };
147 
148 // Google refresh token credentials.
149 class grpc_google_refresh_token_credentials final
150     : public grpc_oauth2_token_fetcher_credentials {
151  public:
152   explicit grpc_google_refresh_token_credentials(
153       grpc_auth_refresh_token refresh_token);
154   ~grpc_google_refresh_token_credentials() override;
155 
refresh_token()156   const grpc_auth_refresh_token& refresh_token() const {
157     return refresh_token_;
158   }
159 
160   std::string debug_string() override;
161 
162   grpc_core::UniqueTypeName type() const override;
163 
164  protected:
165   void fetch_oauth2(grpc_credentials_metadata_request* req,
166                     grpc_polling_entity* pollent, grpc_iomgr_cb_func cb,
167                     grpc_core::Timestamp deadline) override;
168 
169  private:
170   grpc_auth_refresh_token refresh_token_;
171   grpc_closure http_post_cb_closure_;
172   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request_;
173 };
174 
175 // Access token credentials.
176 class grpc_access_token_credentials final : public grpc_call_credentials {
177  public:
178   explicit grpc_access_token_credentials(const char* access_token);
179 
180   grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientMetadataHandle>>
181   GetRequestMetadata(grpc_core::ClientMetadataHandle initial_metadata,
182                      const GetRequestMetadataArgs* args) override;
183 
184   std::string debug_string() override;
185 
186   static grpc_core::UniqueTypeName Type();
187 
type()188   grpc_core::UniqueTypeName type() const override { return Type(); }
189 
190  private:
cmp_impl(const grpc_call_credentials * other)191   int cmp_impl(const grpc_call_credentials* other) const override {
192     // TODO(yashykt): Check if we can do something better here
193     return grpc_core::QsortCompare(
194         static_cast<const grpc_call_credentials*>(this), other);
195   }
196 
197   const grpc_core::Slice access_token_value_;
198 };
199 
200 // Private constructor for refresh token credentials from an already parsed
201 // refresh token. Takes ownership of the refresh token.
202 grpc_core::RefCountedPtr<grpc_call_credentials>
203 grpc_refresh_token_credentials_create_from_auth_refresh_token(
204     grpc_auth_refresh_token token);
205 
206 // Exposed for testing only.
207 grpc_credentials_status
208 grpc_oauth2_token_fetcher_credentials_parse_server_response(
209     const struct grpc_http_response* response,
210     absl::optional<grpc_core::Slice>* token_value,
211     grpc_core::Duration* token_lifetime);
212 
213 namespace grpc_core {
214 // Exposed for testing only. This function validates the options, ensuring that
215 // the required fields are set, and outputs the parsed URL of the STS token
216 // exchanged service.
217 absl::StatusOr<URI> ValidateStsCredentialsOptions(
218     const grpc_sts_credentials_options* options);
219 }  // namespace grpc_core
220 
221 #endif  // GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H
222