Jason Fehr has posted comments on this change. ( http://gerrit.cloudera.org:8080/24448 )
Change subject: IMPALA-14799: Add oauth_servers support and tests ...................................................................... Patch Set 10: (47 comments) http://gerrit.cloudera.org:8080/#/c/24448/10//COMMIT_MSG Commit Message: http://gerrit.cloudera.org:8080/#/c/24448/10//COMMIT_MSG@37 PS10, Line 37: Co-authored-by: Cursor <[email protected]> Please don't add the "Co-authored-by" trailer since Impala uses "Assisted-by". http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/rpc/authentication.cc File be/src/rpc/authentication.cc: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/rpc/authentication.cc@824 PS10, Line 824: if (FLAGS_jwt_validate_signature) { : status = oauth_servers_mgr->GetUsername( : decoded_token.get(), matched_server_idx, &username); : } else { : DCHECK(!FLAGS_jwt_custom_claim_username.empty()); : status = JWTHelper::GetCustomClaimUsername( : decoded_token.get(), FLAGS_jwt_custom_claim_username, username); : } This block of code contains an abstraction leak that is not the best approach. It would be best to have the oauth_server_mgr take care of everything. I understand why it was written the way it was though. Let's do this -- if FLAGS_jwt_validate_signature is true, then skip the call to oauth_servers_mgr->Verify() but perform every other check. This means that every incoming JWT will need a corresponding OAuthServerConfig instance defining a JWK for that token. This approach breaks backwards compatibility, but that is ok with the Impala 5 release. http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/rpc/authentication.cc@874 PS10, Line 874: if (FLAGS_oauth_jwt_validate_signature) { : status = oauth_servers_mgr->GetUsername( : decoded_token.get(), matched_server_idx, &username); : } else { : DCHECK(!FLAGS_oauth_jwt_custom_claim_username.empty()); : status = JWTHelper::GetCustomClaimUsername( : decoded_token.get(), FLAGS_oauth_jwt_custom_claim_username, username); : } Same comment as line 831. http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/runtime/exec-env.h File be/src/runtime/exec-env.h: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/runtime/exec-env.h@110 PS8, Line 110: ~ExecEnv(); > Done. I renamed and relocated the getter as oauth_servers_mgr() alongside t Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/runtime/exec-env.h@299 PS8, Line 299: > Done. ExecEnv::oauth_servers_mgr_ is now a std::shared_ptr<OAuthServersMana Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/runtime/exec-env.cc File be/src/runtime/exec-env.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/runtime/exec-env.cc@578 PS8, Line 578: > Done. I moved oauth_servers_mgr_ initialization into the ExecEnv constructo Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/service/impala-server.cc File be/src/service/impala-server.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/service/impala-server.cc@3240 PS8, Line 3240: RETURN_IF_ERROR(ExecEnv::GetInstance()->oauth_servers_mgr()->Init()); : } : : // Initialize the client servers. > Done. I moved config construction into OAuthServersManager::Init() and now Done http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/service/impala-server.cc File be/src/service/impala-server.cc: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/service/impala-server.cc@3237 PS10, Line 3237: const bool require_oauth_servers = (FLAGS_jwt_token_auth && FLAGS_jwt_validate_signature) Need to: * also check FLAGS_oauth_token_auth * skip the check of OAuthServerConfig http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/jwt-util.h File be/src/util/jwt-util.h: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/jwt-util.h@40 PS10, Line 40: JWTHelper(); : ~JWTHelper(); : JWTHelper(const JWTHelper&) = delete; : JWTHelper& operator=(const JWTHelper&) = delete; : JWTHelper(JWTHelper&&) noexcept; : JWTHelper& operator=(JWTHelper&&) noexcept; Why were these added? They shouldn't be necesary. http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/jwt-util.cc File be/src/util/jwt-util.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/jwt-util.cc@771 PS8, Line 771: DCHECK_GT(jwks_pull_timeout_secs_, 0); : DCHECK(is_local_file || jwks_update_frequency_secs_ > 0); : std::shared_ptr<JWKSSnapshot> new_jwks = std::make_shared<JWKSSnapshot>(); : if (is_local_file) { : > Done. I removed the warning/default fallback path and now rely on validated Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/jwt-util.cc@785 PS8, Line 785: if (!status.ok()) { : LOG(ERROR) << "Failed to load JWKS: " << status; : return status; : } : D > Done. I removed the warning/default fallback for update frequency and use r Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/jwt-util.cc@812 PS8, Line 812: new_jwks = std::make_shared<JWKSSnapshot>(); : bool is_changed = false; : Status status = : new_jwks->LoadKeysFromUrl(jwks_uri_, jwks_verify_server_certificate_, : jwks_ca_certificate_, current_jwks_checksum_, &is_changed, : jwks_pull_timeout_secs_); : if (!status.ok()) { > Done. JWKSMgr::Init() now resolves these values once and UpdateJWKSThread() Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/jwt-util.cc@869 PS8, Line 869: jwks_mgr_.reset(new JWKSMgr()); : RETURN_IF_ERROR(jwks_mgr_->Init(jwks_uri, jwks_verify_server_certificate, : jwks_ca_certificate, is_local_file, jwks_pull_timeout_secs, : jwks_update_frequency_secs)); : if (!initialized_) initialized_ = true; : return Status::OK(); : } : > Done. I removed CreateJWTHelper() / DestroyJWTHelper() and switched manager Done http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/jwt-util.cc File be/src/util/jwt-util.cc: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/jwt-util.cc@803 PS10, Line 803: DCHECK_GT(jwks_update_frequency_secs_, 0); : DCHECK_GT(jwks_pull_timeout_secs_, 0); I believe the DCHECKS in JWKSMgr::Init take care of this validation which means these DCHECKS are duplicates that can be removed. http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config-test.cc File be/src/util/oauth-server-config-test.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config-test.cc@164 PS8, Line 164: FLAGS_jwks_url = "https://example.com/jwks.json"; > Done. Added BuildOAuthServerConfigsCombinesJsonLegacyJwtAndLegacyOAuth. Done http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-server-config.h File be/src/util/oauth-server-config.h: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-server-config.h@42 PS10, Line 42: /// Returns true if this server has a JWKS source configured. : bool HasJwksSource() const { : return !jwks_uri.empty(); : } This function should be deleted since it will never return `false` because the SetJwksSource() function in oauth-server-config.cc requires either the JWKS uri or path to be set. http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h File be/src/util/oauth-server-config.h: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h@17 PS8, Line 17: : #pragma once : > Done. Converted oauth-server-config.h to #pragma once. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h@37 PS8, Line 37: bool is_local_jwks = false; : int32_t jwks_pull_tim > Done. Replaced separate jwks_file_path / jwks_url with jwks_uri plus is_loc Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h@35 PS8, Line 35: bool verify_server_cert = true; : std::string jwks_uri; : bool is_local_jwks = false; : int32_t jwks_pull_timeout_secs = DEFAULT_JWKS_PULL_TIMEOUT_SECS; : int32_t jwks_update_frequency_secs = DEFAULT_JWKS_UPDATE_FREQUENCY_SECS; : std::string username_claim = "username"; : > I did not convert OAuthServerConfig to fully constructor-only immutable fie Please convert OAuthServerConfig to constructor-only immutable fields. It's better to do it right the first time. http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h@48 PS8, Line 48: /// Builds the full list of OAuth server configs from --oauth_servers plus any legacy : /// jwks_* / oauth_* startup flags. : Status BuildOAuthServerConfigs(std::vector<OAuthServerConfig>* configs > Done. Legacy file-vs-url preference behavior is now contained in legacy bui Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h@53 PS8, Line 53: : : > Done. I removed ParseOAuthServersJson() from the header and updated tests t Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.h@62 PS8, Line 62: > Done. Deprecated-flag warning helper path is now kept internal (anonymous n Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.cc File be/src/util/oauth-server-config.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-server-config.cc@31 PS8, Line 31: DECLARE_string(jwks_file_path); > Done. Removed redundant DECLARE_string(oauth_servers) Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager-test.cc File be/src/util/oauth-servers-manager-test.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager-test.cc@120 PS8, Line 120: google::FlagSaver flag_saver; > Done. Added VerifyFailsWhenOnlyWrongJwksConfigured. Done http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager-test.cc File be/src/util/oauth-servers-manager-test.cc: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager-test.cc@55 PS10, Line 55: The VerifyFailsWhenNoServersConfigured() test from patchset 8 should also be included in this file. http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager.h File be/src/util/oauth-servers-manager.h: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager.h@67 PS10, Line 67: std::shared_ptr<OAuthServersImpl> impl_; This should be a std::unique_ptr<OAuthServersImpl> since the impl_ class member variable is never directly returned. http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.h File be/src/util/oauth-servers-manager.h: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.h@17 PS8, Line 17: : #pragma once : > Done. Converted oauth-servers-manager.h to #pragma once. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.h@40 PS8, Line 40: > Done. Removed require_jwks parameter from manager init and adjusted tests t Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.h@41 PS8, Line 41: } : : size_t size() const { : DCHECK(impl_); : return impl_->size(); > Done. Inlined one-line methods (empty(), size(), config()) in the header. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.h@53 PS8, Line 53: /// Ver > Done. Converted GetUsername() from static helper to class member method. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc File be/src/util/oauth-servers-manager.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@35 PS8, Line 35: > Done. Manager now stores JWTHelper objects, not pointers. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@32 PS8, Line 32: RETURN_IF_ERROR(BuildOAuthServerConfigs(&configs)); : return InitWithConfigs(std::move(configs)); : } : : Status OAuthServersManager::InitWithConfigs(vector<OAuthServerConfig>&& configs) { : impl_ = std::make_shared<OAuthServersImpl>(); : impl_->reserve(configs.size()); : > Done (adapted with comment 18). I removed the extra struct and now use a pr Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@41 PS8, Line 41: for (OAuthServerConfig& config : configs) { : if (!config.HasJwksSource()) con > Done (using shared ownership from related comments). I removed the construc Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@50 PS8, Line 50: impl_->emplace_back(std::move(config), std::move(jwt_helper)); > Done. Removed manual reset/destructor cleanup path. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@55 PS8, Line 55: } > Done. Added DCHECK(impl_) checks in manager accessors/paths. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@59 PS8, Line 59: Status OAuthServersManager::Verify(const JWTHelper::JWTDecodedToken* decoded_token, > Done. Added corresponding DCHECK(impl_). Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@63 PS8, Line 63: DCHECK(matched_server_idx_out != nullptr); > Done. Added corresponding DCHECK(impl_). Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@88 PS8, Line 88: ername_cla > Done. Removed duplicate validation path and rely on HasJwksSource() flow. Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/oauth-servers-manager.cc@93 PS8, Line 93: > Done. Removed the test-only sleep from manager initialization. Done http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager.cc File be/src/util/oauth-servers-manager.cc: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager.cc@36 PS10, Line 36: Status OAuthServersManager::InitWithConfigs(vector<OAuthServerConfig>&& configs) { This InitWithConfigs function is unnecessary since it is only called once. Move its code into OAuthServersManager::Init and remove the function. http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/oauth-servers-manager.cc@64 PS10, Line 64: if (impl_->empty()) { : return Status("No OAuth servers are configured for token verification"); : } Is this check already performed elsewhere? http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/webserver.cc File be/src/util/webserver.cc: http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/webserver.cc@1167 PS8, Line 1167: > Done. Updated Webserver auth paths to use std::shared_ptr<OAuthServersManag Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/webserver.cc@1177 PS8, Line 1177: } : } > Done. Removed redundant matched_server_idx reset/condition in JWT web auth Done http://gerrit.cloudera.org:8080/#/c/24448/8/be/src/util/webserver.cc@1219 PS8, Line 1219: : string username; > Done. Removed redundant matched_server_idx reset/condition in OAuth web aut Done http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/webserver.cc File be/src/util/webserver.cc: http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/webserver.cc@1181 PS10, Line 1181: if (FLAGS_jwt_validate_signature) { : status = oauth_servers_mgr->GetUsername(decoded_token.get(), matched_server_idx, : &username); : } else { : DCHECK(!FLAGS_jwt_custom_claim_username.empty()); : status = JWTHelper::GetCustomClaimUsername( : decoded_token.get(), FLAGS_jwt_custom_claim_username, username); : } Same comment as https://gerrit.cloudera.org/c/24448/10/be/src/rpc/authentication.cc#831. http://gerrit.cloudera.org:8080/#/c/24448/10/be/src/util/webserver.cc@1221 PS10, Line 1221: if (FLAGS_oauth_jwt_validate_signature) { : status = oauth_servers_mgr->GetUsername(decoded_token.get(), matched_server_idx, : &username); : } else { : DCHECK(!FLAGS_oauth_jwt_custom_claim_username.empty()); : status = JWTHelper::GetCustomClaimUsername( : decoded_token.get(), FLAGS_oauth_jwt_custom_claim_username, username); : } Same comment as https://gerrit.cloudera.org/c/24448/10/be/src/rpc/authentication.cc#831. http://gerrit.cloudera.org:8080/#/c/24448/10/tests/custom_cluster/test_shell_oauth_servers_auth.py File tests/custom_cluster/test_shell_oauth_servers_auth.py: http://gerrit.cloudera.org:8080/#/c/24448/10/tests/custom_cluster/test_shell_oauth_servers_auth.py@62 PS10, Line 62: def test_jwt_auth_with_oauth_servers(self, vector): Add a similar test that sets the legacy oauth_ flags. -- To view, visit http://gerrit.cloudera.org:8080/24448 To unsubscribe, visit http://gerrit.cloudera.org:8080/settings Gerrit-Project: Impala-ASF Gerrit-Branch: master Gerrit-MessageType: comment Gerrit-Change-Id: Ib29ff36600406ba59c10f29d79cc632020f4a3f7 Gerrit-Change-Number: 24448 Gerrit-PatchSet: 10 Gerrit-Owner: Anubhav Jindal <[email protected]> Gerrit-Reviewer: Anubhav Jindal <[email protected]> Gerrit-Reviewer: Impala Public Jenkins <[email protected]> Gerrit-Reviewer: Jason Fehr <[email protected]> Gerrit-Comment-Date: Thu, 18 Jun 2026 22:10:25 +0000 Gerrit-HasComments: Yes
