| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import os |
| import sys |
| import ssl |
| |
| from six.moves import configparser |
| |
| |
| def ssl_settings(host, config_file, env=os.environ): |
| """ |
| Function which generates SSL setting for cassandra.Cluster |
| |
| Params: |
| * host .........: hostname of Cassandra node. |
| * env ..........: environment variables. SSL factory will use, if passed, |
| SSL_CERTFILE and SSL_VALIDATE variables. |
| * config_file ..: path to cqlsh config file (usually ~/.cqlshrc). |
| SSL factory will use, if set, certfile and validate |
| options in [ssl] section, as well as host to certfile |
| mapping in [certfiles] section. |
| |
| [certfiles] section is optional, 'validate' setting in [ssl] section is |
| optional too. If validation is enabled then SSL certfile must be provided |
| either in the config file or as an environment variable. |
| Environment variables override any options set in cqlsh config file. |
| """ |
| configs = configparser.SafeConfigParser() |
| configs.read(config_file) |
| |
| def get_option(section, option): |
| try: |
| return configs.get(section, option) |
| except configparser.Error: |
| return None |
| |
| def get_best_tls_protocol(ssl_ver_str): |
| # newer python versions suggest to use PROTOCOL_TLS to negotiate the highest TLS version. |
| # older protocol versions have been deprecated: |
| # https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_TLS |
| # https://docs.python.org/3/library/ssl.html#ssl.PROTOCOL_TLS |
| if ssl_ver_str: |
| return getattr(ssl, "PROTOCOL_%s" % ssl_ver_str, None) |
| for protocol in ['PROTOCOL_TLS', 'PROTOCOL_TLSv1_2', 'PROTOCOL_TLSv1_1', 'PROTOCOL_TLSv1']: |
| if hasattr(ssl, protocol): |
| return getattr(ssl, protocol) |
| return None |
| |
| ssl_validate = env.get('SSL_VALIDATE') |
| if ssl_validate is None: |
| ssl_validate = get_option('ssl', 'validate') |
| ssl_validate = ssl_validate is None or ssl_validate.lower() != 'false' |
| |
| ssl_version_str = env.get('SSL_VERSION') |
| if ssl_version_str is None: |
| ssl_version_str = get_option('ssl', 'version') |
| |
| ssl_version = get_best_tls_protocol(ssl_version_str) |
| if ssl_version is None: |
| sys.exit("%s is not a valid SSL protocol, please use one of " |
| "TLS, TLSv1_2, TLSv1_1, or TLSv1" % (ssl_version_str,)) |
| |
| ssl_certfile = env.get('SSL_CERTFILE') |
| if ssl_certfile is None: |
| ssl_certfile = get_option('certfiles', host) |
| if ssl_certfile is None: |
| ssl_certfile = get_option('ssl', 'certfile') |
| if ssl_validate and ssl_certfile is None: |
| sys.exit("Validation is enabled; SSL transport factory requires a valid certfile " |
| "to be specified. Please provide path to the certfile in [ssl] section " |
| "as 'certfile' option in %s (or use [certfiles] section) or set SSL_CERTFILE " |
| "environment variable." % (config_file,)) |
| if ssl_certfile is not None: |
| ssl_certfile = os.path.expanduser(ssl_certfile) |
| |
| userkey = get_option('ssl', 'userkey') |
| if userkey: |
| userkey = os.path.expanduser(userkey) |
| usercert = get_option('ssl', 'usercert') |
| if usercert: |
| usercert = os.path.expanduser(usercert) |
| |
| return dict(ca_certs=ssl_certfile, |
| cert_reqs=ssl.CERT_REQUIRED if ssl_validate else ssl.CERT_NONE, |
| ssl_version=ssl_version, |
| keyfile=userkey, certfile=usercert) |