-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Creating JwksFetcher interface and impl v2 #4242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
7914794
d3fbad5
c90ebf7
1b2e6c7
6dbc828
6ca0471
498c858
af9175e
51c4d1b
f477905
8fa1dc8
2d18a01
1d9281e
9d277be
4c77200
4bb61d2
8c1c294
489c52d
17ddf46
8038924
1457fb1
f95e51e
18b6b9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| #include "extensions/filters/http/common/jwks_fetcher.h" | ||
|
|
||
| #include "common/common/enum_to_int.h" | ||
| #include "common/http/headers.h" | ||
| #include "common/http/utility.h" | ||
|
|
||
| #include "jwt_verify_lib/status.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Extensions { | ||
| namespace HttpFilters { | ||
| namespace Common { | ||
| namespace { | ||
| class JwksFetcherImpl : public JwksFetcher, | ||
|
nickrmc83 marked this conversation as resolved.
|
||
| public Logger::Loggable<Logger::Id::filter>, | ||
| public Http::AsyncClient::Callbacks { | ||
| private: | ||
|
nickrmc83 marked this conversation as resolved.
Outdated
|
||
| Upstream::ClusterManager& cm_; | ||
| JwksFetcher::JwksReceiver* receiver_ = nullptr; | ||
|
nickrmc83 marked this conversation as resolved.
Outdated
|
||
| const ::envoy::api::v2::core::HttpUri* uri_ = nullptr; | ||
|
nickrmc83 marked this conversation as resolved.
Outdated
|
||
| Http::AsyncClient::Request* request_ = nullptr; | ||
|
|
||
| public: | ||
| JwksFetcherImpl(Upstream::ClusterManager& cm) : cm_(cm) { ENVOY_LOG(trace, "{}", __func__); } | ||
|
|
||
| void cancel() { | ||
| if (request_) { | ||
| request_->cancel(); | ||
| request_ = nullptr; | ||
| ENVOY_LOG(debug, "fetch pubkey [uri = {}]: canceled", uri_->uri()); | ||
| } | ||
| } | ||
|
|
||
| void fetch(const ::envoy::api::v2::core::HttpUri& uri, JwksFetcher::JwksReceiver* receiver) { | ||
| ENVOY_LOG(trace, "{}", __func__); | ||
| receiver_ = receiver; | ||
| uri_ = &uri; | ||
| Http::MessagePtr message = Http::Utility::prepareHeaders(uri); | ||
| message->headers().insertMethod().value().setReference(Http::Headers::get().MethodValues.Get); | ||
| ENVOY_LOG(debug, "fetch pubkey from [uri = {}]: start", uri_->uri()); | ||
| request_ = | ||
| cm_.httpAsyncClientForCluster(uri.cluster()) | ||
| .send(std::move(message), *this, | ||
| std::chrono::milliseconds(DurationUtil::durationToMilliseconds(uri.timeout()))); | ||
| } | ||
|
|
||
| // HTTP async receive methods | ||
| void onSuccess(Http::MessagePtr&& response) { | ||
| ENVOY_LOG(trace, "{}", __func__); | ||
| request_ = nullptr; | ||
| const uint64_t status_code = Http::Utility::getResponseStatus(response->headers()); | ||
| if (status_code == enumToInt(Http::Code::OK)) { | ||
| ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: success", __func__, uri_->uri()); | ||
| if (response->body()) { | ||
| const auto len = response->body()->length(); | ||
| const auto body = std::string(static_cast<char*>(response->body()->linearize(len)), len); | ||
| auto jwks = | ||
| google::jwt_verify::Jwks::createFrom(body, google::jwt_verify::Jwks::Type::JWKS); | ||
| if (jwks->getStatus() == google::jwt_verify::Status::Ok) { | ||
| ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: succeeded", __func__, uri_->uri()); | ||
| receiver_->onJwksSuccess(std::move(jwks)); | ||
| } else { | ||
| ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: invalid jwks", __func__, uri_->uri()); | ||
| receiver_->onJwksError(JwksFetcher::JwksReceiver::Failure::invalid_jwks); | ||
| } | ||
| } else { | ||
| ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: body is empty", __func__, uri_->uri()); | ||
| receiver_->onJwksError(JwksFetcher::JwksReceiver::Failure::network); | ||
| } | ||
| } else { | ||
| ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: response status code {}", __func__, | ||
| uri_->uri(), status_code); | ||
| receiver_->onJwksError(JwksFetcher::JwksReceiver::Failure::network); | ||
| } | ||
| } | ||
|
|
||
| void onFailure(Http::AsyncClient::FailureReason reason) { | ||
|
nickrmc83 marked this conversation as resolved.
|
||
| ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: network error {}", __func__, uri_->uri(), | ||
| enumToInt(reason)); | ||
| receiver_->onJwksError(JwksFetcher::JwksReceiver::Failure::network); | ||
| } | ||
| }; | ||
| } // namespace | ||
|
|
||
| JwksFetcherPtr JwksFetcher::create(Upstream::ClusterManager& cm) { | ||
| return JwksFetcherPtr(new JwksFetcherImpl(cm)); | ||
|
nickrmc83 marked this conversation as resolved.
Outdated
|
||
| } | ||
| } // namespace Common | ||
| } // namespace HttpFilters | ||
| } // namespace Extensions | ||
| } // namespace Envoy | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #pragma once | ||
|
|
||
| #include "envoy/api/v2/core/http_uri.pb.h" | ||
| #include "envoy/common/pure.h" | ||
| #include "envoy/upstream/cluster_manager.h" | ||
|
|
||
| #include "jwt_verify_lib/jwks.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Extensions { | ||
| namespace HttpFilters { | ||
| namespace Common { | ||
|
|
||
| class JwksFetcher; | ||
| typedef std::unique_ptr<JwksFetcher> JwksFetcherPtr; | ||
| /** | ||
| * JwksFetcher interface can be used to retrieve remote JWKS | ||
| * (https://tools.ietf.org/html/rfc7517) data structures returning a concrete, | ||
| * type-safe representation. An instance of this interface is designed to | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, you answer the above question here. This is a pretty weird pattern; I would call it out by explicitly naming the class/interface
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| * retrieve a single JWKS and should not be re-used to fetch further instances. | ||
| */ | ||
| class JwksFetcher { | ||
|
nickrmc83 marked this conversation as resolved.
|
||
| public: | ||
| class JwksReceiver { | ||
| public: | ||
| enum class Failure { | ||
| unknown, | ||
|
nickrmc83 marked this conversation as resolved.
Outdated
|
||
| network, | ||
| invalid_jwks, | ||
| }; | ||
|
|
||
| virtual ~JwksReceiver(){}; | ||
| /* | ||
| * Successful retrieval callback. | ||
| * of the returned JWKS object. | ||
| * @param jwks the JWKS object retrieved. | ||
| */ | ||
| virtual void onJwksSuccess(google::jwt_verify::JwksPtr&& jwks) PURE; | ||
| /* | ||
| * Retrieval error callback. | ||
| * * @param reason the failure reason. | ||
| */ | ||
| virtual void onJwksError(Failure reason) PURE; | ||
| }; | ||
|
|
||
| virtual ~JwksFetcher(){}; | ||
|
|
||
| /* | ||
| * Cancel any inflight request. | ||
| */ | ||
| virtual void cancel() PURE; | ||
|
|
||
| /* | ||
| * Retrieve a JWKS resource from a remote HTTP host. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 2d18a01 |
||
| * @param uri the uri to retrieve the jwks from. | ||
|
nickrmc83 marked this conversation as resolved.
|
||
| */ | ||
| virtual void fetch(const ::envoy::api::v2::core::HttpUri& uri, JwksReceiver* receiver) PURE; | ||
|
nickrmc83 marked this conversation as resolved.
Outdated
|
||
|
|
||
| /* | ||
| * Factory method for creating a JwksFetcher. | ||
| * @param cm the cluster manager to use during Jwks retrieval | ||
| * @return a JwksFetcher instance | ||
| */ | ||
| static JwksFetcherPtr create(Upstream::ClusterManager& cm); | ||
| }; | ||
| } // namespace Common | ||
| } // namespace HttpFilters | ||
| } // namespace Extensions | ||
| } // namespace Envoy | ||
Uh oh!
There was an error while loading. Please reload this page.