Skip to content

Commit fdf644a

Browse files
committed
share the commmon http token fetching logic between oauth2 and jwt call credentials
1 parent 41ca6a6 commit fdf644a

File tree

8 files changed

+132
-149
lines changed

8 files changed

+132
-149
lines changed

src/core/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4887,6 +4887,7 @@ grpc_cc_library(
48874887
"poll",
48884888
"pollset_set",
48894889
"ref_counted",
4890+
"status_conversion",
48904891
"sync",
48914892
"time",
48924893
"useful",

src/core/credentials/call/gcp_service_account_identity/gcp_service_account_identity_credentials.cc

Lines changed: 19 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "absl/strings/string_view.h"
2424
#include "src/core/call/metadata.h"
2525
#include "src/core/credentials/call/jwt_util.h"
26+
#include "src/core/credentials/call/token_fetcher/token_fetcher_credentials.h"
2627
#include "src/core/credentials/transport/transport_credentials.h"
2728
#include "src/core/lib/iomgr/error.h"
2829
#include "src/core/lib/transport/status_conversion.h"
@@ -36,78 +37,30 @@ namespace grpc_core {
3637
// JwtTokenFetcherCallCredentials
3738
//
3839

39-
// State held for a pending HTTP request.
40-
class JwtTokenFetcherCallCredentials::HttpFetchRequest final
41-
: public TokenFetcherCredentials::FetchRequest {
42-
public:
43-
HttpFetchRequest(
44-
JwtTokenFetcherCallCredentials* creds, Timestamp deadline,
45-
absl::AnyInvocable<
46-
void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
47-
on_done)
48-
: on_done_(std::move(on_done)) {
49-
GRPC_CLOSURE_INIT(&on_http_response_, OnHttpResponse, this, nullptr);
50-
Ref().release(); // Ref held by HTTP request callback.
51-
http_request_ = creds->StartHttpRequest(creds->pollent(), deadline,
52-
&response_, &on_http_response_);
53-
}
54-
55-
~HttpFetchRequest() override { grpc_http_response_destroy(&response_); }
56-
57-
void Orphan() override {
58-
http_request_.reset();
59-
Unref();
60-
}
61-
62-
private:
63-
static void OnHttpResponse(void* arg, grpc_error_handle error) {
64-
RefCountedPtr<HttpFetchRequest> self(static_cast<HttpFetchRequest*>(arg));
65-
if (!error.ok()) {
66-
// TODO(roth): It shouldn't be necessary to explicitly set the
67-
// status to UNAVAILABLE here. Once the HTTP client code is
68-
// migrated to stop using legacy grpc_error APIs to create
69-
// statuses, we should be able to just propagate the status as-is.
70-
self->on_done_(absl::UnavailableError(StatusToString(error)));
71-
return;
72-
}
73-
if (self->response_.status != 200) {
74-
grpc_status_code status_code =
75-
grpc_http2_status_to_grpc_status(self->response_.status);
76-
if (status_code != GRPC_STATUS_UNAVAILABLE) {
77-
status_code = GRPC_STATUS_UNAUTHENTICATED;
78-
}
79-
self->on_done_(absl::Status(static_cast<absl::StatusCode>(status_code),
80-
absl::StrCat("JWT fetch failed with status ",
81-
self->response_.status)));
82-
return;
83-
}
84-
// Return token object.
85-
absl::string_view body(self->response_.body, self->response_.body_length);
86-
auto expiration_time = GetJwtExpirationTime(body);
87-
if (!expiration_time.ok()) {
88-
self->on_done_(expiration_time.status());
89-
return;
90-
}
91-
self->on_done_(MakeRefCounted<Token>(
92-
Slice::FromCopiedString(absl::StrCat("Bearer ", body)),
93-
*expiration_time));
94-
}
95-
96-
OrphanablePtr<HttpRequest> http_request_;
97-
grpc_closure on_http_response_;
98-
grpc_http_response response_;
99-
absl::AnyInvocable<void(
100-
absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
101-
on_done_;
102-
};
103-
10440
OrphanablePtr<TokenFetcherCredentials::FetchRequest>
10541
JwtTokenFetcherCallCredentials::FetchToken(
10642
Timestamp deadline,
10743
absl::AnyInvocable<
10844
void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
10945
on_done) {
110-
return MakeOrphanable<HttpFetchRequest>(this, deadline, std::move(on_done));
46+
return MakeOrphanable<HttpTokenFetcherCredentials::HttpFetchRequest>(
47+
this, deadline,
48+
[on_done = std::move(on_done)](
49+
absl::StatusOr<grpc_http_response> response) mutable {
50+
if (!response.ok()) {
51+
on_done(response.status());
52+
return;
53+
}
54+
absl::string_view body(response->body, response->body_length);
55+
auto expiration_time = GetJwtExpirationTime(body);
56+
if (!expiration_time.ok()) {
57+
on_done(expiration_time.status());
58+
return;
59+
}
60+
on_done(MakeRefCounted<Token>(
61+
Slice::FromCopiedString(absl::StrCat("Bearer ", body)),
62+
*expiration_time));
63+
});
11164
}
11265

11366
//

src/core/credentials/call/gcp_service_account_identity/gcp_service_account_identity_credentials.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,13 @@ namespace grpc_core {
4040

4141
// A base class for JWT token fetching credentials.
4242
// Subclasses must implement StartHttpRequest().
43-
class JwtTokenFetcherCallCredentials : public TokenFetcherCredentials {
43+
class JwtTokenFetcherCallCredentials : public HttpTokenFetcherCredentials {
4444
public:
4545
OrphanablePtr<FetchRequest> FetchToken(
4646
Timestamp deadline,
4747
absl::AnyInvocable<
4848
void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
4949
on_done) final;
50-
51-
private:
52-
class HttpFetchRequest;
53-
54-
virtual OrphanablePtr<HttpRequest> StartHttpRequest(
55-
grpc_polling_entity* pollent, Timestamp deadline,
56-
grpc_http_response* response, grpc_closure* on_complete) = 0;
5750
};
5851

5952
// GCP service account identity call credentials.

src/core/credentials/call/oauth2/oauth2_credentials.cc

Lines changed: 22 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "absl/strings/string_view.h"
4545
#include "src/core/call/metadata_batch.h"
4646
#include "src/core/credentials/call/json_util.h"
47+
#include "src/core/credentials/call/token_fetcher/token_fetcher_credentials.h"
4748
#include "src/core/credentials/transport/transport_credentials.h"
4849
#include "src/core/lib/debug/trace.h"
4950
#include "src/core/lib/iomgr/error.h"
@@ -211,58 +212,6 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response(
211212

212213
namespace grpc_core {
213214

214-
// State held for a pending HTTP request.
215-
class Oauth2TokenFetcherCredentials::HttpFetchRequest final
216-
: public TokenFetcherCredentials::FetchRequest {
217-
public:
218-
HttpFetchRequest(
219-
Oauth2TokenFetcherCredentials* creds, Timestamp deadline,
220-
absl::AnyInvocable<
221-
void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
222-
on_done)
223-
: on_done_(std::move(on_done)) {
224-
GRPC_CLOSURE_INIT(&on_http_response_, OnHttpResponse, this, nullptr);
225-
Ref().release(); // Ref held by HTTP request callback.
226-
http_request_ = creds->StartHttpRequest(creds->pollent(), deadline,
227-
&response_, &on_http_response_);
228-
}
229-
230-
~HttpFetchRequest() override { grpc_http_response_destroy(&response_); }
231-
232-
void Orphan() override {
233-
http_request_.reset();
234-
Unref();
235-
}
236-
237-
private:
238-
static void OnHttpResponse(void* arg, grpc_error_handle error) {
239-
RefCountedPtr<HttpFetchRequest> self(static_cast<HttpFetchRequest*>(arg));
240-
if (!error.ok()) {
241-
self->on_done_(std::move(error));
242-
return;
243-
}
244-
// Parse oauth2 token.
245-
std::optional<Slice> access_token_value;
246-
Duration token_lifetime;
247-
grpc_credentials_status status =
248-
grpc_oauth2_token_fetcher_credentials_parse_server_response(
249-
&self->response_, &access_token_value, &token_lifetime);
250-
if (status != GRPC_CREDENTIALS_OK) {
251-
self->on_done_(absl::UnavailableError("error parsing oauth2 token"));
252-
return;
253-
}
254-
self->on_done_(MakeRefCounted<Token>(std::move(*access_token_value),
255-
Timestamp::Now() + token_lifetime));
256-
}
257-
258-
OrphanablePtr<HttpRequest> http_request_;
259-
grpc_closure on_http_response_;
260-
grpc_http_response response_;
261-
absl::AnyInvocable<void(
262-
absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
263-
on_done_;
264-
};
265-
266215
std::string Oauth2TokenFetcherCredentials::debug_string() {
267216
return "OAuth2TokenFetcherCredentials";
268217
}
@@ -278,7 +227,27 @@ Oauth2TokenFetcherCredentials::FetchToken(
278227
absl::AnyInvocable<
279228
void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
280229
on_done) {
281-
return MakeOrphanable<HttpFetchRequest>(this, deadline, std::move(on_done));
230+
return MakeOrphanable<HttpTokenFetcherCredentials::HttpFetchRequest>(
231+
this, deadline,
232+
[on_done = std::move(on_done)](
233+
absl::StatusOr<grpc_http_response> response) mutable {
234+
if (!response.ok()) {
235+
on_done(response.status());
236+
return;
237+
}
238+
// Parse oauth2 token.
239+
std::optional<Slice> access_token_value;
240+
Duration token_lifetime;
241+
grpc_credentials_status status =
242+
grpc_oauth2_token_fetcher_credentials_parse_server_response(
243+
&(*response), &access_token_value, &token_lifetime);
244+
if (status != GRPC_CREDENTIALS_OK) {
245+
on_done(absl::UnavailableError("error parsing oauth2 token"));
246+
return;
247+
}
248+
on_done(MakeRefCounted<Token>(std::move(*access_token_value),
249+
Timestamp::Now() + token_lifetime));
250+
});
282251
}
283252

284253
} // namespace grpc_core

src/core/credentials/call/oauth2/oauth2_credentials.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ namespace grpc_core {
9090

9191
// A base class for oauth2 token fetching credentials.
9292
// Subclasses must implement StartHttpRequest().
93-
class Oauth2TokenFetcherCredentials : public TokenFetcherCredentials {
93+
class Oauth2TokenFetcherCredentials : public HttpTokenFetcherCredentials {
9494
public:
9595
std::string debug_string() override;
9696

@@ -102,13 +102,7 @@ class Oauth2TokenFetcherCredentials : public TokenFetcherCredentials {
102102
void(absl::StatusOr<RefCountedPtr<TokenFetcherCredentials::Token>>)>
103103
on_done) final;
104104

105-
virtual OrphanablePtr<HttpRequest> StartHttpRequest(
106-
grpc_polling_entity* pollent, Timestamp deadline,
107-
grpc_http_response* response, grpc_closure* on_complete) = 0;
108-
109105
private:
110-
class HttpFetchRequest;
111-
112106
int cmp_impl(const grpc_call_credentials* other) const override {
113107
// TODO(yashykt): Check if we can do something better here
114108
return QsortCompare(static_cast<const grpc_call_credentials*>(this), other);

src/core/credentials/call/token_fetcher/token_fetcher_credentials.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "src/core/lib/promise/context.h"
2525
#include "src/core/lib/promise/poll.h"
2626
#include "src/core/lib/promise/promise.h"
27+
#include "src/core/lib/transport/status_conversion.h"
2728

2829
namespace grpc_core {
2930

@@ -301,4 +302,49 @@ TokenFetcherCredentials::GetRequestMetadata(
301302
};
302303
}
303304

305+
//
306+
// HttpTokenFetcherCredentials
307+
//
308+
309+
HttpTokenFetcherCredentials::HttpFetchRequest::HttpFetchRequest(
310+
HttpTokenFetcherCredentials* creds, Timestamp deadline,
311+
absl::AnyInvocable<void(absl::StatusOr<grpc_http_response>)> on_done)
312+
: on_done_(std::move(on_done)) {
313+
GRPC_CLOSURE_INIT(&on_http_response_, OnHttpResponse, this, nullptr);
314+
Ref().release(); // Ref held by HTTP request callback.
315+
http_request_ = creds->StartHttpRequest(creds->pollent(), deadline,
316+
&response_, &on_http_response_);
317+
}
318+
319+
void HttpTokenFetcherCredentials::HttpFetchRequest::Orphan() {
320+
http_request_.reset();
321+
Unref();
322+
}
323+
324+
void HttpTokenFetcherCredentials::HttpFetchRequest::OnHttpResponse(
325+
void* arg, grpc_error_handle error) {
326+
RefCountedPtr<HttpFetchRequest> self(static_cast<HttpFetchRequest*>(arg));
327+
if (!error.ok()) {
328+
// TODO(roth): It shouldn't be necessary to explicitly set the
329+
// status to UNAVAILABLE here. Once the HTTP client code is
330+
// migrated to stop using legacy grpc_error APIs to create
331+
// statuses, we should be able to just propagate the status as-is.
332+
self->on_done_(absl::UnavailableError(StatusToString(error)));
333+
return;
334+
}
335+
if (self->response_.status != 200) {
336+
grpc_status_code status_code =
337+
grpc_http2_status_to_grpc_status(self->response_.status);
338+
if (status_code != GRPC_STATUS_UNAVAILABLE) {
339+
status_code = GRPC_STATUS_UNAUTHENTICATED;
340+
}
341+
self->on_done_(
342+
absl::Status(static_cast<absl::StatusCode>(status_code),
343+
absl::StrCat("HTTP token fetch failed with status ",
344+
self->response_.status)));
345+
return;
346+
}
347+
self->on_done_(self->response_);
348+
}
349+
304350
} // namespace grpc_core

src/core/credentials/call/token_fetcher/token_fetcher_credentials.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,35 @@ class TokenFetcherCredentials : public grpc_call_credentials {
176176
grpc_polling_entity pollent_ ABSL_GUARDED_BY(&mu_);
177177
};
178178

179+
// A base class for fetching tokens via an HTTP request.
180+
class HttpTokenFetcherCredentials : public TokenFetcherCredentials {
181+
public:
182+
virtual OrphanablePtr<HttpRequest> StartHttpRequest(
183+
grpc_polling_entity* pollent, Timestamp deadline,
184+
grpc_http_response* response, grpc_closure* on_complete) = 0;
185+
186+
protected:
187+
// State held for a pending HTTP request.
188+
class HttpFetchRequest : public TokenFetcherCredentials::FetchRequest {
189+
public:
190+
// The given callback should assume the http response status has already
191+
// been checked and handle the token parsing.
192+
HttpFetchRequest(
193+
HttpTokenFetcherCredentials* creds, Timestamp deadline,
194+
absl::AnyInvocable<void(absl::StatusOr<grpc_http_response>)> on_done);
195+
~HttpFetchRequest() override { grpc_http_response_destroy(&response_); }
196+
197+
void Orphan() override;
198+
199+
private:
200+
static void OnHttpResponse(void* arg, grpc_error_handle error);
201+
OrphanablePtr<HttpRequest> http_request_;
202+
grpc_closure on_http_response_;
203+
grpc_http_response response_;
204+
absl::AnyInvocable<void(absl::StatusOr<grpc_http_response>)> on_done_;
205+
};
206+
};
207+
179208
} // namespace grpc_core
180209

181210
#endif // GRPC_SRC_CORE_CREDENTIALS_CALL_TOKEN_FETCHER_TOKEN_FETCHER_CREDENTIALS_H

0 commit comments

Comments
 (0)