10#define FMT_HEADER_ONLY
11#include <fmt/format.h>
18 size_t refresh_interval_s;
20 std::shared_ptr<ccf::kv::Consensus>
consensus;
21 std::shared_ptr<ccf::RPCSessions> rpcsessions;
22 std::shared_ptr<ccf::RPCMap> rpc_map;
25 std::atomic_size_t attempts;
29 size_t refresh_interval_s,
31 const std::shared_ptr<ccf::kv::Consensus>&
consensus,
32 const std::shared_ptr<ccf::RPCSessions>& rpcsessions,
33 const std::shared_ptr<ccf::RPCMap>& rpc_map,
36 refresh_interval_s(refresh_interval_s),
39 rpcsessions(rpcsessions),
41 node_sign_kp(node_sign_kp),
55 auto refresh_msg = std::make_unique<::threading::Tmsg<RefreshTimeMsg>>(
56 [](std::unique_ptr<::threading::Tmsg<RefreshTimeMsg>> msg) {
57 if (!msg->data.self.consensus->can_replicate())
60 "JWT key auto-refresh: Node is not primary, skipping");
64 msg->data.self.refresh_jwt_keys();
67 "JWT key auto-refresh: Scheduling in {}s",
68 msg->data.self.refresh_interval_s);
69 auto delay = std::chrono::seconds(msg->data.self.refresh_interval_s);
71 std::move(msg), delay);
76 "JWT key auto-refresh: Scheduling in {}s", refresh_interval_s);
77 auto delay = std::chrono::seconds(refresh_interval_s);
79 std::move(refresh_msg), delay);
84 auto refresh_msg = std::make_unique<::threading::Tmsg<RefreshTimeMsg>>(
85 [](std::unique_ptr<::threading::Tmsg<RefreshTimeMsg>> msg) {
86 if (!msg->data.self.consensus->can_replicate())
89 "JWT key one-off refresh: Node is not primary, skipping");
93 msg->data.self.refresh_jwt_keys();
98 LOG_DEBUG_FMT(
"JWT key one-off refresh: Scheduling without delay");
99 auto delay = std::chrono::seconds(0);
101 std::move(refresh_msg), delay);
104 template <
typename T>
110 "jwt_keys/refresh"));
112 http::headers::CONTENT_TYPE, http::headervalues::contenttype::JSON);
114 auto body = nlohmann::json(msg).dump();
119 auto node_session = std::make_shared<ccf::SessionContext>(
120 ccf::InvalidSessionId, node_cert.
raw());
123 std::shared_ptr<ccf::RpcHandler> search =
124 ::http::fetch_rpc_handler(ctx, this->rpc_map);
126 search->process(ctx);
138 const std::string& issuer,
139 const std::optional<std::string>& issuer_constraint,
141 std::vector<uint8_t>&& data)
143 if (status != HTTP_STATUS_OK)
146 "JWT key auto-refresh: Error while requesting JWKS: {} {}{}",
148 ccf::http_status_str(status),
151 fmt::format(
" '{}'", std::string(data.begin(), data.end())));
157 "JWT key auto-refresh: Received JWKS for issuer '{}'", issuer);
164 catch (
const std::exception& e)
167 "JWT key auto-refresh: Cannot parse JWKS for issuer '{}': {}",
179 if (issuer_constraint.has_value())
181 for (
auto& key : jwks.
keys)
183 if (!key.issuer.has_value())
185 key.issuer = issuer_constraint;
194 const std::string& issuer,
195 std::shared_ptr<::tls::CA> ca,
197 std::vector<uint8_t>&& data)
199 if (status != HTTP_STATUS_OK)
202 "JWT key auto-refresh: Error while requesting OpenID metadata: {} "
205 ccf::http_status_str(status),
208 fmt::format(
" '{}'", std::string(data.begin(), data.end())));
214 "JWT key auto-refresh: Received OpenID metadata for issuer '{}'",
217 std::string jwks_url_str;
218 nlohmann::json metadata;
221 metadata = nlohmann::json::parse(data);
222 jwks_url_str = metadata.at(
"jwks_uri").get<std::string>();
224 catch (
const std::exception& e)
227 "JWT key auto-refresh: Cannot parse OpenID metadata for issuer '{}': "
239 catch (
const std::invalid_argument& e)
242 "JWT key auto-refresh: Cannot parse jwks_uri for issuer '{}': {}",
248 auto jwks_url_port = !jwks_url.
port.empty() ? jwks_url.
port :
"443";
250 auto ca_cert = std::make_shared<::tls::Cert>(
251 ca, std::nullopt, std::nullopt, jwks_url.
host);
253 std::optional<std::string> issuer_constraint{std::nullopt};
254 const auto constraint = metadata.find(
"issuer");
255 if (constraint != metadata.end())
257 issuer_constraint = *constraint;
261 "JWT key auto-refresh: Requesting JWKS at https://{}:{}{}",
265 auto http_client = rpcsessions->create_client(ca_cert);
268 http_client->connect(
269 std::string(jwks_url.
host),
270 std::string(jwks_url_port),
271 [
this, issuer, issuer_constraint](
274 std::vector<uint8_t>&& data) {
275 handle_jwt_jwks_response(
276 issuer, issuer_constraint, status, std::move(data));
280 r.
set_header(ccf::http::headers::HOST, std::string(jwks_url.
host));
281 http_client->send_request(std::move(r));
286 auto tx = network.
tables->create_read_only_tx();
289 jwt_issuers->foreach([
this, &ca_cert_bundles](
295 "JWT key auto-refresh: Skipping issuer '{}', auto-refresh is "
305 "JWT key auto-refresh: Refreshing keys for issuer '{}'", issuer);
307 auto ca_cert_bundle_pem = ca_cert_bundles->get(ca_cert_bundle_name);
308 if (!ca_cert_bundle_pem.has_value())
311 "JWT key auto-refresh: CA cert bundle with name '{}' for issuer "
320 auto metadata_url_str = issuer +
"/.well-known/openid-configuration";
322 auto metadata_url_port =
323 !metadata_url.port.empty() ? metadata_url.port :
"443";
327 auto ca = std::make_shared<::tls::CA>(ca_pems);
328 auto ca_cert = std::make_shared<::tls::Cert>(
329 ca, std::nullopt, std::nullopt, metadata_url.host);
332 "JWT key auto-refresh: Requesting OpenID metadata at https://{}:{}{}",
336 auto http_client = rpcsessions->create_client(ca_cert);
339 http_client->connect(
340 std::string(metadata_url.host),
341 std::string(metadata_url_port),
345 std::vector<uint8_t>&& data) {
346 handle_jwt_metadata_response(issuer, ca, status, std::move(data));
350 r.
set_header(ccf::http::headers::HOST, std::string(metadata_url.host));
351 http_client->send_request(std::move(r));
359 return attempts.load();
Definition jwt_key_auto_refresh.h:16
JwtKeyAutoRefresh(size_t refresh_interval_s, NetworkState &network, const std::shared_ptr< ccf::kv::Consensus > &consensus, const std::shared_ptr< ccf::RPCSessions > &rpcsessions, const std::shared_ptr< ccf::RPCMap > &rpc_map, const ccf::crypto::KeyPairPtr &node_sign_kp, const ccf::crypto::Pem &node_cert)
Definition jwt_key_auto_refresh.h:28
void refresh_jwt_keys()
Definition jwt_key_auto_refresh.h:284
void send_refresh_jwt_keys(T msg)
Definition jwt_key_auto_refresh.h:105
void start()
Definition jwt_key_auto_refresh.h:53
size_t get_attempts() const
Definition jwt_key_auto_refresh.h:357
void handle_jwt_jwks_response(const std::string &issuer, const std::optional< std::string > &issuer_constraint, ccf::http_status status, std::vector< uint8_t > &&data)
Definition jwt_key_auto_refresh.h:137
void send_refresh_jwt_keys_error()
Definition jwt_key_auto_refresh.h:129
void handle_jwt_metadata_response(const std::string &issuer, std::shared_ptr<::tls::CA > ca, ccf::http_status status, std::vector< uint8_t > &&data)
Definition jwt_key_auto_refresh.h:193
void schedule_once()
Definition jwt_key_auto_refresh.h:82
std::vector< uint8_t > raw() const
Definition pem.h:71
void set_header(std::string k, const std::string &v)
Definition http_builder.h:45
void set_body(const std::vector< uint8_t > *b, bool overwrite_content_length=true)
Definition http_builder.h:74
Definition http_builder.h:118
std::vector< uint8_t > build_request(bool header_only=false) const
Definition http_builder.h:177
static ThreadMessaging & instance()
Definition thread_messaging.h:283
TaskQueue::TimerEntry add_task_after(std::unique_ptr< Tmsg< Payload > > msg, std::chrono::milliseconds ms)
Definition thread_messaging.h:326
#define LOG_DEBUG_FMT
Definition logger.h:357
#define LOG_FAIL_FMT
Definition logger.h:363
std::vector< ccf::crypto::Pem > split_x509_cert_bundle(const std::string_view &pem)
Definition pem.cpp:37
std::shared_ptr< KeyPair > KeyPairPtr
Definition key_pair.h:145
std::map< std::string, std::string, std::less<> > HeaderMap
Definition http_header_map.h:10
Definition app_interface.h:14
constexpr auto get_actor_prefix(ActorsType at)
Definition actors.h:31
std::string JwtIssuer
Definition jwt.h:35
llhttp_status http_status
Definition http_status.h:9
std::shared_ptr<::http::HttpRpcContext > make_rpc_context(std::shared_ptr< ccf::SessionContext > s, const std::vector< uint8_t > &packed)
Definition http_rpc_context.h:392
Definition consensus_types.h:23
URL parse_url_full(const std::string &url)
Definition http_parser.h:145
std::vector< ccf::crypto::JsonWebKeyData > keys
Definition jwt.h:93
Definition jwt_key_auto_refresh.h:47
JwtKeyAutoRefresh & self
Definition jwt_key_auto_refresh.h:50
RefreshTimeMsg(JwtKeyAutoRefresh &self_)
Definition jwt_key_auto_refresh.h:48
Definition network_state.h:12
std::shared_ptr< ccf::kv::Store > tables
Definition network_tables.h:47
const JwtIssuers jwt_issuers
Definition network_tables.h:167
const CACertBundlePEMs ca_cert_bundles
Definition network_tables.h:166
Definition node_frontend.h:120
Definition http_parser.h:136
std::string host
Definition http_parser.h:138
std::string port
Definition http_parser.h:139
std::string path
Definition http_parser.h:140