This is an automated email from the ASF dual-hosted git repository.
rlevas pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new dbfc6a0 [AMBARI-24085] setup-sso in Ambari fails when SSL is enabled
dbfc6a0 is described below
commit dbfc6a045856ce1050f434c0f72810258c7075f5
Author: Robert Levas <[email protected]>
AuthorDate: Tue Jun 12 18:10:31 2018 -0400
[AMBARI-24085] setup-sso in Ambari fails when SSL is enabled
---
.../src/main/python/ambari_server/serverUpgrade.py | 4 +-
.../src/main/python/ambari_server/serverUtils.py | 75 ++++++++++++++++++++--
.../src/main/python/ambari_server/setupSecurity.py | 9 +--
ambari-server/src/test/python/TestServerUpgrade.py | 4 +-
ambari-server/src/test/python/TestServerUtils.py | 39 ++++++++++-
5 files changed, 116 insertions(+), 15 deletions(-)
diff --git a/ambari-server/src/main/python/ambari_server/serverUpgrade.py
b/ambari-server/src/main/python/ambari_server/serverUpgrade.py
index 4f7d77a..297c853 100644
--- a/ambari-server/src/main/python/ambari_server/serverUpgrade.py
+++ b/ambari-server/src/main/python/ambari_server/serverUpgrade.py
@@ -46,7 +46,7 @@ from ambari_server.serverConfiguration import configDefaults,
get_resources_loca
from ambari_server.setupSecurity import adjust_directory_permissions, \
generate_env, ensure_can_start_under_current_user
from ambari_server.utils import compare_versions, get_json_url_from_repo_file,
update_latest_in_repoinfos_for_all_stacks
-from ambari_server.serverUtils import is_server_runing,
get_ambari_server_api_base
+from ambari_server.serverUtils import is_server_runing,
get_ambari_server_api_base, get_ssl_context
from ambari_server.userInput import get_validated_string_input,
get_prompt_default, read_password, get_YN_input
from ambari_server.serverClassPath import ServerClassPath
from ambari_server.setupMpacks import replay_mpack_logs
@@ -391,7 +391,7 @@ def set_current(options):
request.get_method = lambda: 'PUT'
try:
- response = urllib2.urlopen(request)
+ response = urllib2.urlopen(request, context=get_ssl_context(properties))
except urllib2.HTTPError, e:
code = e.getcode()
content = e.read()
diff --git a/ambari-server/src/main/python/ambari_server/serverUtils.py
b/ambari-server/src/main/python/ambari_server/serverUtils.py
index 7df85ed..be9fcde 100644
--- a/ambari-server/src/main/python/ambari_server/serverUtils.py
+++ b/ambari-server/src/main/python/ambari_server/serverUtils.py
@@ -20,6 +20,7 @@ limitations under the License.
import base64
import os
import socket
+import ssl
import urllib2
from contextlib import closing
@@ -133,10 +134,7 @@ def get_ambari_server_api_base(properties):
if api_port_prop is not None and api_port_prop != '':
api_port = api_port_prop
- api_ssl = False
- api_ssl_prop = properties.get_property(SSL_API)
- if api_ssl_prop is not None:
- api_ssl = api_ssl_prop.lower() == "true"
+ api_ssl = is_api_ssl_enabled(properties)
if api_ssl:
api_host = socket.getfqdn()
@@ -203,7 +201,7 @@ def get_json_via_rest_api(properties, admin_login,
admin_password, entry_point):
print_info_msg("Fetching information from Ambari's REST API")
- with closing(urllib2.urlopen(request)) as response:
+ with closing(urllib2.urlopen(request, context=get_ssl_context(properties)))
as response:
response_status_code = response.getcode()
json_data = None
print_info_msg(
@@ -226,9 +224,74 @@ def perform_changes_via_rest_api(properties, admin_login,
admin_password, url_po
request.add_data(json.dumps(request_data))
request.get_method = lambda: get_method
- with closing(urllib2.urlopen(request)) as response:
+ with closing(urllib2.urlopen(request, context=get_ssl_context(properties)))
as response:
response_status_code = response.getcode()
if response_status_code not in (200, 201):
err = 'Error while performing changes via Ambari REST API. Http status
code - ' + str(
response_status_code)
raise FatalException(1, err)
+
+
+def get_ssl_context(properties, requested_protocol=None):
+ """
+ If needed, creates an SSL context that does not validate the SSL certificate
provided by the server.
+
+ If api.ssl is not True, then return None, else create a new SSL context with
either the requested
+ protocol or the best one that is available for the version of Python being
used.
+
+ :param properties the Ambari server configuration data
+ :param requested_protocol: the requested SSL/TLS protocol; None to choose
the protocol dynamically
+ :rtype ssl.SSLContext
+ :return: a permissive SSLContext or None
+ """
+
+ if not is_api_ssl_enabled(properties):
+ return None
+
+ if requested_protocol:
+ protocol = requested_protocol
+ else:
+ if hasattr(ssl, 'PROTOCOL_TLS'):
+ # https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_TLS
+ # Selects the highest protocol version that both the client and server
support.
+ protocol = ssl.PROTOCOL_TLS
+ elif hasattr(ssl, 'PROTOCOL_TLSv1_2'):
+ # https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_TLSv1_2
+ # Selects TLS version 1.2 as the channel encryption protocol.
+ protocol = ssl.PROTOCOL_TLSv1_2
+ elif hasattr(ssl, 'PROTOCOL_TLSv1_1'):
+ # https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_TLSv1_1
+ # Selects TLS version 1.1 as the channel encryption protocol
+ protocol = ssl.PROTOCOL_TLSv1_1
+ elif hasattr(ssl, 'PROTOCOL_TLSv1'):
+ # https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_TLSv1
+ # Selects TLS version 1.0 as the channel encryption protocol
+ protocol = ssl.PROTOCOL_TLSv1
+ else:
+ protocol = None
+
+ if protocol:
+ context = ssl.SSLContext(protocol)
+ else:
+ context = ssl.create_default_context()
+
+ # if _https_verify_certificates is vaild, force this to be False
+ if hasattr(context, '_https_verify_certificates'):
+ context._https_verify_certificates(False)
+
+ return context
+
+
+def is_api_ssl_enabled(properties):
+ """
+ Determines if the Ambari REST API uses SSL or not.
+
+ :param properties: the Ambari server configuration data
+ :return: True, if the Ambari REST API uses SSL; otherwise False
+ """
+ ssl_enabled = False
+ api_ssl_prop = properties.get_property(SSL_API)
+ if api_ssl_prop is not None:
+ ssl_enabled = api_ssl_prop.lower() == "true"
+
+ return ssl_enabled
\ No newline at end of file
diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py
b/ambari-server/src/main/python/ambari_server/setupSecurity.py
index 956468c..87f09ed 100644
--- a/ambari-server/src/main/python/ambari_server/setupSecurity.py
+++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py
@@ -50,7 +50,8 @@ from ambari_server.serverConfiguration import configDefaults,
parse_properties_f
SSL_TRUSTSTORE_PASSWORD_PROPERTY, SSL_TRUSTSTORE_PATH_PROPERTY,
SSL_TRUSTSTORE_TYPE_PROPERTY, \
SSL_API, SSL_API_PORT, DEFAULT_SSL_API_PORT, CLIENT_API_PORT,
JDK_NAME_PROPERTY, JCE_NAME_PROPERTY, JAVA_HOME_PROPERTY, \
get_resources_location, SECURITY_MASTER_KEY_LOCATION, SETUP_OR_UPGRADE_MSG,
CHECK_AMBARI_KRB_JAAS_CONFIGURATION_PROPERTY
-from ambari_server.serverUtils import is_server_runing,
get_ambari_server_api_base, get_ambari_admin_username_password_pair,
perform_changes_via_rest_api
+from ambari_server.serverUtils import is_server_runing,
get_ambari_server_api_base, \
+ get_ambari_admin_username_password_pair, perform_changes_via_rest_api,
get_ssl_context
from ambari_server.setupActions import SETUP_ACTION, LDAP_SETUP_ACTION
from ambari_server.userInput import get_validated_string_input,
get_prompt_default, read_password, get_YN_input, quit_if_has_answer
from ambari_server.serverClassPath import ServerClassPath
@@ -296,7 +297,7 @@ def getLdapPropertyFromDB(properties, admin_login,
admin_password, property_name
sys.stdout.flush()
try:
- with closing(urllib2.urlopen(request)) as response:
+ with closing(urllib2.urlopen(request,
context=get_ssl_context(properties))) as response:
response_status_code = response.getcode()
if response_status_code != 200:
request_in_progress = False
@@ -398,7 +399,7 @@ def sync_ldap(options):
request.get_method = lambda: 'POST'
try:
- response = urllib2.urlopen(request)
+ response = urllib2.urlopen(request, context=get_ssl_context(properties))
except Exception as e:
err = 'Sync event creation failed. Error details: %s' % e
raise FatalException(1, err)
@@ -423,7 +424,7 @@ def sync_ldap(options):
sys.stdout.flush()
try:
- response = urllib2.urlopen(request)
+ response = urllib2.urlopen(request, context=get_ssl_context(properties))
except Exception as e:
request_in_progress = False
err = 'Sync event check failed. Error details: %s' % e
diff --git a/ambari-server/src/test/python/TestServerUpgrade.py
b/ambari-server/src/test/python/TestServerUpgrade.py
index d944e0d..ad621ff 100644
--- a/ambari-server/src/test/python/TestServerUpgrade.py
+++ b/ambari-server/src/test/python/TestServerUpgrade.py
@@ -86,7 +86,7 @@ class TestServerUpgrade(TestCase):
get_validated_string_input_mock.return_value = 'dummy_string'
p = get_ambari_properties_mock.return_value
- p.get_property.side_effect = ["8080", "false"]
+ p.get_property.side_effect = ["8080", "false", "false"]
get_ambari_server_api_base_mock.return_value =
'http://127.0.0.1:8080/api/v1/'
get_verbose_mock.retun_value = False
@@ -140,7 +140,7 @@ class TestServerUpgrade(TestCase):
get_validated_string_input_mock.return_value = 'dummy_string'
p = get_ambari_properties_mock.return_value
- p.get_property.side_effect = ["8080", "false"]
+ p.get_property.side_effect = ["8080", "false", "false"]
get_ambari_server_api_base_mock.return_value =
'http://127.0.0.1:8080/api/v1/'
get_verbose_mock.retun_value = False
diff --git a/ambari-server/src/test/python/TestServerUtils.py
b/ambari-server/src/test/python/TestServerUtils.py
index 3da98e4..cb548a0 100644
--- a/ambari-server/src/test/python/TestServerUtils.py
+++ b/ambari-server/src/test/python/TestServerUtils.py
@@ -23,6 +23,7 @@ from mock.mock import patch, MagicMock
from unittest import TestCase
import platform
import socket
+import ssl
from ambari_commons import os_utils
os_utils.search_file = MagicMock(return_value="/tmp/ambari.properties")
@@ -34,7 +35,8 @@ with patch.object(platform, "linux_distribution",
return_value = MagicMock(retur
with patch("os.path.isdir", return_value = MagicMock(return_value=True)):
with patch("os.access", return_value = MagicMock(return_value=True)):
with patch.object(os_utils, "parse_log4j_file",
return_value={'ambari.log.dir': '/var/log/ambari-server'}):
- from ambari_server.serverUtils import get_ambari_server_api_base,
get_ambari_admin_username_password_pair
+ from ambari_server.serverUtils import get_ambari_server_api_base,
get_ambari_admin_username_password_pair, \
+ is_api_ssl_enabled, get_ssl_context
from ambari_server.serverConfiguration import CLIENT_API_PORT,
CLIENT_API_PORT_PROPERTY, SSL_API, DEFAULT_SSL_API_PORT, SSL_API_PORT
@patch.object(platform, "linux_distribution", new =
MagicMock(return_value=('Redhat', '6.4', 'Final')))
@@ -98,6 +100,41 @@ class TestServerUtils(TestCase):
self.assertEquals(user, user_name)
self.assertEquals(pw, password)
+ def test_is_api_ssl_enabled(self):
+ properties = FakeProperties({
+ SSL_API: "true"
+ })
+ self.assertTrue(is_api_ssl_enabled(properties))
+
+ properties = FakeProperties({
+ SSL_API: "false"
+ })
+ self.assertFalse(is_api_ssl_enabled(properties))
+
+ properties = FakeProperties({
+ SSL_API: None
+ })
+ self.assertFalse(is_api_ssl_enabled(properties))
+
+
+ def test_get_ssl_context(self):
+ properties = FakeProperties({
+ SSL_API: "true"
+ })
+ context = get_ssl_context(properties)
+ self.assertIsNotNone(context)
+
+ context = get_ssl_context(properties, ssl.PROTOCOL_TLSv1)
+ self.assertIsNotNone(context)
+ self.assertEqual(ssl.PROTOCOL_TLSv1, context.protocol)
+
+ properties = FakeProperties({
+ SSL_API: "false"
+ })
+ context = get_ssl_context(properties)
+ self.assertIsNone(context)
+
+
class FakeProperties(object):
def __init__(self, prop_map):
self.prop_map = prop_map
--
To stop receiving notification emails like this one, please contact
[email protected].