Download JWKS from the given URL with Kudu's EasyCurl wrapper.
| 652 | |
| 653 | // Download JWKS from the given URL with Kudu's EasyCurl wrapper. |
| 654 | Status JWKSSnapshot::LoadKeysFromUrl( |
| 655 | const std::string& jwks_url, bool jwks_verify_server_certificate, |
| 656 | const std::string& jwks_ca_certificate, uint64_t cur_jwks_checksum, |
| 657 | bool* is_changed) { |
| 658 | kudu::EasyCurl curl; |
| 659 | kudu::faststring dst; |
| 660 | Status status; |
| 661 | |
| 662 | curl.set_timeout( |
| 663 | kudu::MonoDelta::FromMilliseconds(FLAGS_jwks_pulling_timeout_s * 1000)); |
| 664 | curl.set_verify_peer(jwks_verify_server_certificate); |
| 665 | curl.set_ca_certificates(jwks_ca_certificate); |
| 666 | // TODO support CurlAuthType by calling kudu::EasyCurl::set_auth(). |
| 667 | KUDU_RETURN_IF_ERROR(curl.FetchURL(jwks_url, &dst), |
| 668 | Substitute("Error downloading JWKS from '$0'", jwks_url)); |
| 669 | if (dst.size() > 0) { |
| 670 | // Verify if the checksum of the downloaded JWKS has been changed. |
| 671 | jwks_checksum_ = HashUtil::FastHash64(dst.data(), dst.size(), /*seed*/ 0xcafebeef); |
| 672 | if (jwks_checksum_ == cur_jwks_checksum) return Status::OK(); |
| 673 | *is_changed = true; |
| 674 | // Append '\0' so that the in-memory object could be parsed as StringStream. |
| 675 | dst.push_back('\0'); |
| 676 | #ifndef NDEBUG |
| 677 | VLOG(3) << "JWKS: " << dst.data(); |
| 678 | #endif |
| 679 | // Parse in-memory JWKS JSON object as StringStream. |
| 680 | Document jwks_doc; |
| 681 | jwks_doc.Parse((char*)dst.data()); |
| 682 | if (jwks_doc.HasParseError()) { |
| 683 | status = Status( |
| 684 | TErrorCode::JWKS_PARSE_ERROR, GetParseError_En(jwks_doc.GetParseError())); |
| 685 | } else if (!jwks_doc.IsObject()) { |
| 686 | status = Status(TErrorCode::JWKS_PARSE_ERROR, "root element must be a JSON Object"); |
| 687 | } else if (!jwks_doc.HasMember("keys")) { |
| 688 | status = Status(TErrorCode::JWKS_PARSE_ERROR, "keys is required"); |
| 689 | } else { |
| 690 | // Load and initialize public keys. |
| 691 | JWKSetParser jwks_parser(this); |
| 692 | status = jwks_parser.Parse(jwks_doc); |
| 693 | } |
| 694 | } |
| 695 | return status; |
| 696 | } |
| 697 | |
| 698 | void JWKSSnapshot::AddHSKey(const std::string& key_id, JWTPublicKey* jwk_pub_key) { |
| 699 | if (hs_key_map_.find(key_id) == hs_key_map_.end()) { |
no test coverage detected