From f669aba20c66031bd4c6c74037ac662705944eb1 Mon Sep 17 00:00:00 2001 From: Mike Fedosin Date: Wed, 9 Aug 2017 13:39:18 +0300 Subject: [PATCH] Add ssl options to keycloak auth module Change-Id: I8ac595de304b627ef2f701fcf78644be854438ec --- glareclient/common/http.py | 27 ++++------------------ glareclient/common/keycloak_auth.py | 12 ++++++++-- glareclient/common/utils.py | 22 ++++++++++++++++++ glareclient/tests/unit/test_common_http.py | 5 ++-- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/glareclient/common/http.py b/glareclient/common/http.py index f757300..59efcd3 100644 --- a/glareclient/common/http.py +++ b/glareclient/common/http.py @@ -15,7 +15,6 @@ import copy import hashlib -import os import socket from keystoneauth1 import adapter @@ -28,30 +27,13 @@ from six.moves import urllib from glareclient.common import exceptions as exc from glareclient.common import keycloak_auth +from glareclient.common import utils LOG = logging.getLogger(__name__) USER_AGENT = 'python-glareclient' CHUNKSIZE = 1024 * 64 # 64kB -def get_system_ca_file(): - """Return path to system default CA file.""" - # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, - # Suse, FreeBSD/OpenBSD, MacOSX, and the bundled ca - ca_path = ['/etc/ssl/certs/ca-certificates.crt', - '/etc/pki/tls/certs/ca-bundle.crt', - '/etc/ssl/ca-bundle.pem', - '/etc/ssl/cert.pem', - '/System/Library/OpenSSL/certs/cacert.pem', - requests.certs.where()] - for ca in ca_path: - LOG.debug("Looking for ca file %s", ca) - if os.path.exists(ca): - LOG.debug("Using ca file %s", ca) - return ca - LOG.warning("System ca file could not be found.") - - def _handle_response(resp): content_type = resp.headers.get('Content-Type') if not content_type: @@ -113,7 +95,8 @@ class HTTPClient(object): if kwargs.get('insecure'): self.verify_cert = False else: - self.verify_cert = kwargs.get('cacert', get_system_ca_file()) + self.verify_cert = kwargs.get( + 'cacert', utils.get_system_ca_file()) def _safe_header(self, name, value): if name in ['X-Auth-Token', 'X-Subject-Token']: @@ -332,14 +315,14 @@ def construct_http_client(*args, **kwargs): parameters.update(kwargs) return SessionClient(**parameters) elif endpoint: - realm_name = kwargs.pop('keycloak_realm_name', None) if keycloak_auth_url: kwargs['auth_token'] = keycloak_auth.authenticate( auth_url=keycloak_auth_url, client_id=kwargs.pop('openid_client_id', None), username=kwargs.pop('keycloak_username', None), password=kwargs.pop('keycloak_password', None), - realm_name=realm_name + realm_name=kwargs.pop('keycloak_realm_name', None), + **kwargs ) else: kwargs['auth_token'] = auth_token diff --git a/glareclient/common/keycloak_auth.py b/glareclient/common/keycloak_auth.py index 5eb5587..7cd801f 100644 --- a/glareclient/common/keycloak_auth.py +++ b/glareclient/common/keycloak_auth.py @@ -15,6 +15,9 @@ import logging import pprint import requests +from six.moves import urllib + +from glareclient.common import utils LOG = logging.getLogger(__name__) @@ -29,8 +32,8 @@ def authenticate(**kwargs): :param username: User name (Optional, if None then access_token must be provided). :param password: Password (Optional). + :param cacert: SSL certificate file (Optional). :param insecure: If True, SSL certificate is not verified (Optional). - """ auth_url = kwargs.get('auth_url') client_id = kwargs.get('client_id') @@ -38,6 +41,7 @@ def authenticate(**kwargs): username = kwargs.get('username') password = kwargs.get('password') insecure = kwargs.get('insecure', False) + cacert = kwargs.get('cacert', utils.get_system_ca_file()) if not auth_url: raise ValueError('Base authentication url is not provided.') @@ -59,6 +63,10 @@ def authenticate(**kwargs): (auth_url, realm_name) ) + verify = None + if urllib.parse.urlparse(access_token_endpoint).scheme == "https": + verify = False if insecure else cacert + body = { 'grant_type': 'password', 'username': username, @@ -70,7 +78,7 @@ def authenticate(**kwargs): resp = requests.post( access_token_endpoint, data=body, - verify=not insecure + verify=verify ) try: diff --git a/glareclient/common/utils.py b/glareclient/common/utils.py index 7e2690d..7d9aa54 100644 --- a/glareclient/common/utils.py +++ b/glareclient/common/utils.py @@ -25,12 +25,16 @@ if os.name == 'nt': else: msvcrt = None +from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import importutils import requests from glareclient import exc +LOG = logging.getLogger(__name__) + + SENSITIVE_HEADERS = ('X-Auth-Token', ) @@ -173,3 +177,21 @@ def get_artifact_id(client, parsed_args): type_name=parsed_args.type_name)['id'] except exc.BadRequest as e: exit(msg=e.details) + + +def get_system_ca_file(): + """Return path to system default CA file.""" + # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, + # Suse, FreeBSD/OpenBSD, MacOSX, and the bundled ca + ca_path = ['/etc/ssl/certs/ca-certificates.crt', + '/etc/pki/tls/certs/ca-bundle.crt', + '/etc/ssl/ca-bundle.pem', + '/etc/ssl/cert.pem', + '/System/Library/OpenSSL/certs/cacert.pem', + requests.certs.where()] + for ca in ca_path: + LOG.debug("Looking for ca file %s", ca) + if os.path.exists(ca): + LOG.debug("Using ca file %s", ca) + return ca + LOG.warning("System ca file could not be found.") diff --git a/glareclient/tests/unit/test_common_http.py b/glareclient/tests/unit/test_common_http.py index 4f9801b..21c6a6c 100644 --- a/glareclient/tests/unit/test_common_http.py +++ b/glareclient/tests/unit/test_common_http.py @@ -19,6 +19,7 @@ import testtools from glareclient.common import exceptions as exc from glareclient.common import http +from glareclient.common import utils from glareclient.tests.unit import fakes @@ -420,7 +421,7 @@ class HttpClientTest(testtools.TestCase): with mock.patch('os.path.exists') as mock_os: mock_os.return_value = chosen - ca = http.get_system_ca_file() + ca = utils.get_system_ca_file() self.assertEqual(chosen, ca) mock_os.assert_called_once_with(chosen) @@ -433,7 +434,7 @@ class HttpClientTest(testtools.TestCase): client = http.HTTPClient('https://foo', cacert="NOWHERE") self.assertEqual("NOWHERE", client.verify_cert) - with mock.patch('glareclient.common.http.get_system_ca_file') as gsf: + with mock.patch('glareclient.common.utils.get_system_ca_file') as gsf: gsf.return_value = "SOMEWHERE" client = http.HTTPClient('https://foo') self.assertEqual("SOMEWHERE", client.verify_cert)