From cc658edf0013028875b65875bbd0dd8b2f92d995 Mon Sep 17 00:00:00 2001 From: manish-m-pillai-ksolves Date: Wed, 22 Jul 2026 16:49:26 +0530 Subject: [PATCH] [AMBARI-LDAP] Fix LDAPS end-to-end flow on Python 3 + Java 9+ Three bugs blocked the full LDAPS setup flow on Ambari 3.0: 1. serverUtils.py: Encode POST body to bytes in perform_changes_via_rest_api() Python 3's urllib requires bytes for request.data; json.dumps() returns str. 2. setupSecurity.py: Same encoding fix for both POST bodies in sync_ldap() Fixes 'POST data should be of type str' error during ambari-server sync-ldap. 3. ambari-env.sh: Add --add-opens java.naming/com.sun.jndi.ldap=ALL-UNNAMED Java 9+ module system blocked Spring LDAP's reflective access to LdapCtxFactory, causing IllegalAccessError on LDAP login via the UI. Updated 8 sync_ldap unit test assertions in TestAmbariServer.py to expect bytes instead of str, keeping the test suite consistent with the fix. Fixes: ambari-server setup-ldap, sync-ldap --all, and LDAP UI authentication. --- ambari-server/conf/unix/ambari-env.sh | 1 + .../src/main/python/ambari_server/serverUtils.py | 2 +- .../main/python/ambari_server/setupSecurity.py | 4 ++-- .../src/test/python/TestAmbariServer.py | 16 ++++++++-------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ambari-server/conf/unix/ambari-env.sh b/ambari-server/conf/unix/ambari-env.sh index 297eee3df39..4339038368d 100644 --- a/ambari-server/conf/unix/ambari-env.sh +++ b/ambari-server/conf/unix/ambari-env.sh @@ -23,6 +23,7 @@ AMBARI_JVM_ARGS="--add-opens java.base/java.lang=ALL-UNNAMED " AMBARI_JVM_ARGS+="--add-opens java.base/java.util.regex=ALL-UNNAMED " AMBARI_JVM_ARGS+="--add-opens java.base/java.util=ALL-UNNAMED " AMBARI_JVM_ARGS+="--add-opens java.base/java.lang.reflect=ALL-UNNAMED " +AMBARI_JVM_ARGS+="--add-opens java.naming/com.sun.jndi.ldap=ALL-UNNAMED " AMBARI_JVM_ARGS+="-Xms512m -Xmx2048m " AMBARI_JVM_ARGS+="-Djava.security.auth.login.config=$ROOT/etc/ambari-server/conf/krb5JAASLogin.conf " AMBARI_JVM_ARGS+="-Djava.security.krb5.conf=/etc/krb5.conf " diff --git a/ambari-server/src/main/python/ambari_server/serverUtils.py b/ambari-server/src/main/python/ambari_server/serverUtils.py index 9f75c8b092d..a11961bc665 100644 --- a/ambari-server/src/main/python/ambari_server/serverUtils.py +++ b/ambari-server/src/main/python/ambari_server/serverUtils.py @@ -262,7 +262,7 @@ def perform_changes_via_rest_api( request.add_header("Authorization", f"Basic {admin_auth}") request.add_header("X-Requested-By", "ambari") if request_data is not None: - request.data = json.dumps(request_data) + request.data = json.dumps(request_data).encode("utf-8") request.get_method = lambda: get_method with closing( diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py index 73ab89da0a9..8da2db6b29f 100644 --- a/ambari-server/src/main/python/ambari_server/setupSecurity.py +++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py @@ -626,7 +626,7 @@ def sync_ldap(options): if get_verbose(): sys.stdout.write("\nCalling API " + url + " : " + str(bodies) + "\n") - request.data = json.dumps(bodies) + request.data = json.dumps(bodies).encode("utf-8") request.get_method = lambda: "POST" try: @@ -646,7 +646,7 @@ def sync_ldap(options): request.add_header("Authorization", f"Basic {admin_auth}") request.add_header("X-Requested-By", "ambari") body = [{"LDAP": {"synced_groups": "*", "synced_users": "*"}}] - request.data = json.dumps(body) + request.data = json.dumps(body).encode("utf-8") request.get_method = lambda: "GET" request_in_progress = True diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py index 6fee1a4b2ef..5a71dbeb566 100644 --- a/ambari-server/src/test/python/TestAmbariServer.py +++ b/ambari-server/src/test/python/TestAmbariServer.py @@ -8736,7 +8736,7 @@ def test_ldap_sync_all( self.assertEqual(url, str(request.get_full_url())) self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "all"}, {"principal_type": "groups", "sync_type": "all"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "users", "sync_type": "all"}, {"principal_type": "groups", "sync_type": "all"}]}}]', request.data, ) @@ -8791,7 +8791,7 @@ def test_ldap_sync_all_post_process_existing_users( self.assertEqual(url, str(request.get_full_url())) self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "all", "post_process_existing_users": "true"}, {"principal_type": "groups", "sync_type": "all", "post_process_existing_users": "true"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "users", "sync_type": "all", "post_process_existing_users": "true"}, {"principal_type": "groups", "sync_type": "all", "post_process_existing_users": "true"}]}}]', request.data, ) @@ -8852,7 +8852,7 @@ def test_ldap_sync_users( request = urlopen_mock.call_args_list[0][0][0] self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "specific", "names": "bob, tom"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "users", "sync_type": "specific", "names": "bob, tom"}]}}]', request.data, ) @@ -8913,7 +8913,7 @@ def test_ldap_sync_users_post_process_existing_users( request = urlopen_mock.call_args_list[0][0][0] self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "specific", "names": "bob, tom", "post_process_existing_users": "true"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "users", "sync_type": "specific", "names": "bob, tom", "post_process_existing_users": "true"}]}}]', request.data, ) @@ -8974,7 +8974,7 @@ def test_ldap_sync_groups( request = urlopen_mock.call_args_list[0][0][0] self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "groups", "sync_type": "specific", "names": "group1, group2"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "groups", "sync_type": "specific", "names": "group1, group2"}]}}]', request.data, ) @@ -9035,7 +9035,7 @@ def test_ldap_sync_groups_post_process_existing_users( request = urlopen_mock.call_args_list[0][0][0] self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "groups", "sync_type": "specific", "names": "group1, group2", "post_process_existing_users": "true"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "groups", "sync_type": "specific", "names": "group1, group2", "post_process_existing_users": "true"}]}}]', request.data, ) @@ -9141,7 +9141,7 @@ def test_ldap_sync_existing( request = urlopen_mock.call_args_list[0][0][0] self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "existing"}, {"principal_type": "groups", "sync_type": "existing"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "users", "sync_type": "existing"}, {"principal_type": "groups", "sync_type": "existing"}]}}]', request.data, ) @@ -9194,7 +9194,7 @@ def test_ldap_sync_existing_post_process_existing_users( request = urlopen_mock.call_args_list[0][0][0] self.assertEqual( - '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "existing", "post_process_existing_users": "true"}, {"principal_type": "groups", "sync_type": "existing", "post_process_existing_users": "true"}]}}]', + b'[{"Event": {"specs": [{"principal_type": "users", "sync_type": "existing", "post_process_existing_users": "true"}, {"principal_type": "groups", "sync_type": "existing", "post_process_existing_users": "true"}]}}]', request.data, )