Skip to content

Commit 3a8320a

Browse files
committed
Support client certificate/key
This change enables to specify a client certificate/key with: * usual CLI options (--os-cert/--os-key) * usual environment variables ($OS_CERT/$OS_KEY) * os-client-config Change-Id: Ibeaaa5897ae37b37c1e91f3e47076e4e8e4a8ded Closes-Bug: #1565112
1 parent a1a4706 commit 3a8320a

6 files changed

Lines changed: 80 additions & 0 deletions

File tree

doc/source/man/openstack.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ OPTIONS
114114
:option:`--verify` | :option:`--insecure`
115115
Verify or ignore server certificate (default: verify)
116116

117+
:option:`--os-cert` <certificate-file>
118+
Client certificate bundle file
119+
120+
:option:`--os-key` <key-file>
121+
Client certificate key file
122+
117123
:option:`--os-identity-api-version` <identity-api-version>
118124
Identity API version (Default: 2.0)
119125

@@ -367,6 +373,12 @@ The following environment variables can be set to alter the behaviour of :progra
367373
:envvar:`OS_CACERT`
368374
CA certificate bundle file
369375

376+
:envvar:`OS_CERT`
377+
Client certificate bundle file
378+
379+
:envvar:`OS_KEY`
380+
Client certificate key file
381+
370382
:envvar:`OS_IDENTITY_API_VERSION`
371383
Identity API version (Default: 2.0)
372384

openstackclient/common/clientmanager.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@ def __init__(
110110
self._cacert = verify
111111
self._insecure = False
112112

113+
# Set up client certificate and key
114+
# NOTE(cbrandily): This converts client certificate/key to requests
115+
# cert argument: None (no client certificate), a path
116+
# to client certificate or a tuple with client
117+
# certificate/key paths.
118+
self._cert = self._cli_options.cert
119+
if self._cert and self._cli_options.key:
120+
self._cert = self._cert, self._cli_options.key
121+
113122
# Get logging from root logger
114123
root_logger = logging.getLogger('')
115124
LOG.setLevel(root_logger.getEffectiveLevel())
@@ -194,6 +203,7 @@ def setup_auth(self, required_scope=True):
194203
auth=self.auth,
195204
session=request_session,
196205
verify=self._verify,
206+
cert=self._cert,
197207
user_agent=USER_AGENT,
198208
)
199209

openstackclient/shell.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@ def build_option_parser(self, description, version):
189189
dest='cacert',
190190
default=utils.env('OS_CACERT'),
191191
help='CA certificate bundle file (Env: OS_CACERT)')
192+
parser.add_argument(
193+
'--os-cert',
194+
metavar='<certificate-file>',
195+
dest='cert',
196+
default=utils.env('OS_CERT'),
197+
help='Client certificate bundle file (Env: OS_CERT)')
198+
parser.add_argument(
199+
'--os-key',
200+
metavar='<key-file>',
201+
dest='key',
202+
default=utils.env('OS_KEY'),
203+
help='Client certificate key file (Env: OS_KEY)')
192204
verify_group = parser.add_mutually_exclusive_group()
193205
verify_group.add_argument(
194206
'--verify',

openstackclient/tests/common/test_clientmanager.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ def __init__(self, **kwargs):
5858
self.interface = None
5959
self.url = None
6060
self.auth = {}
61+
self.cert = None
62+
self.key = None
6163
self.default_domain = 'default'
6264
self.__dict__.update(kwargs)
6365

@@ -268,6 +270,21 @@ def test_client_manager_password_verify_ca(self):
268270
self.assertEqual('cafile', client_manager._cacert)
269271
self.assertTrue(client_manager.is_network_endpoint_enabled())
270272

273+
def test_client_manager_password_no_cert(self):
274+
client_manager = clientmanager.ClientManager(
275+
cli_options=FakeOptions())
276+
self.assertIsNone(client_manager._cert)
277+
278+
def test_client_manager_password_client_cert(self):
279+
client_manager = clientmanager.ClientManager(
280+
cli_options=FakeOptions(cert='cert'))
281+
self.assertEqual('cert', client_manager._cert)
282+
283+
def test_client_manager_password_client_cert_and_key(self):
284+
client_manager = clientmanager.ClientManager(
285+
cli_options=FakeOptions(cert='cert', key='key'))
286+
self.assertEqual(('cert', 'key'), client_manager._cert)
287+
271288
def _select_auth_plugin(self, auth_params, api_version, auth_plugin_name):
272289
auth_params['auth_type'] = auth_plugin_name
273290
auth_params['identity_api_version'] = api_version

openstackclient/tests/test_shell.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
'region_name': 'occ-cloud,krikkit,occ-env',
8080
'log_file': '/tmp/test_log_file',
8181
'log_level': 'debug',
82+
'cert': 'mycert',
83+
'key': 'mickey',
8284
}
8385
}
8486
}
@@ -567,6 +569,24 @@ def test_shell_args_ca_options(self):
567569
self.assertEqual('foo', _shell.options.cacert)
568570
self.assertFalse(_shell.verify)
569571

572+
def test_shell_args_cert_options(self):
573+
_shell = make_shell()
574+
575+
# Default
576+
fake_execute(_shell, "list user")
577+
self.assertEqual('', _shell.options.cert)
578+
self.assertEqual('', _shell.options.key)
579+
580+
# --os-cert
581+
fake_execute(_shell, "--os-cert mycert list user")
582+
self.assertEqual('mycert', _shell.options.cert)
583+
self.assertEqual('', _shell.options.key)
584+
585+
# --os-key
586+
fake_execute(_shell, "--os-key mickey list user")
587+
self.assertEqual('', _shell.options.cert)
588+
self.assertEqual('mickey', _shell.options.key)
589+
570590
def test_default_env(self):
571591
flag = ""
572592
kwargs = {
@@ -670,6 +690,9 @@ def test_shell_args_cloud_public(self, config_mock, public_mock):
670690
_shell.cloud.config['region_name'],
671691
)
672692

693+
self.assertEqual('mycert', _shell.cloud.config['cert'])
694+
self.assertEqual('mickey', _shell.cloud.config['key'])
695+
673696
@mock.patch("os_client_config.config.OpenStackConfig._load_vendor_file")
674697
@mock.patch("os_client_config.config.OpenStackConfig._load_config_file")
675698
def test_shell_args_precedence(self, config_mock, vendor_mock):
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
features:
3+
- Support client certificate/key. Client certificate/key can be provided
4+
using --os-cert/--os-key options, $OS_CERT/$OS_KEY environment
5+
variables or os-client-config config.
6+
[Bug `1565112 <https://bugs.launchpad.net/bugs/1565112>`_]

0 commit comments

Comments
 (0)