Support 2-way SSL with Keystone server if it is configured to enforce
2-way SSL. See also https://review.openstack.org/#/c/7706/ for the corresponding review for the 2-way SSL addition to Keystone. Change-Id: If0cb46a43d663687396d93604a7139d85a4e7114
This commit is contained in:
@@ -42,13 +42,32 @@ options, it is easier to just set them as environment variables:
|
||||
|
||||
The OpenStack Identity API version.
|
||||
|
||||
.. envvar:: OS_CA_CERT
|
||||
|
||||
The location for the CA truststore (PEM formatted) for this client.
|
||||
|
||||
.. envvar:: OS_CERT
|
||||
|
||||
The location for the keystore (PEM formatted) containing the public
|
||||
key of this client. This keystore can also optionally contain the
|
||||
private key of this client.
|
||||
|
||||
.. envvar:: OS_KEY
|
||||
|
||||
The location for the keystore (PEM formatted) containing the private
|
||||
key of this client. This value can be empty if the private key is
|
||||
included in the OS_CERT file.
|
||||
|
||||
For example, in Bash you'd use::
|
||||
|
||||
export OS_USERNAME=yourname
|
||||
export OS_PASSWORD=yadayadayada
|
||||
export OS_TENANT_NAME=myproject
|
||||
export OS_AUTH_URL=http://example.com:5000/v2.0/
|
||||
export OS_AUTH_URL=http(s)://example.com:5000/v2.0/
|
||||
export OS_IDENTITY_API_VERSION=2.0
|
||||
export OS_CA_CERT=/etc/keystone/yourca.pem
|
||||
export OS_CERT=/etc/keystone/yourpublickey.pem
|
||||
export OS_KEY=/etc/keystone/yourprivatekey.pem
|
||||
|
||||
From there, all shell commands take the form::
|
||||
|
||||
|
@@ -38,8 +38,14 @@ class HTTPClient(httplib2.Http):
|
||||
|
||||
def __init__(self, username=None, tenant_id=None, tenant_name=None,
|
||||
password=None, auth_url=None, region_name=None, timeout=None,
|
||||
endpoint=None, token=None):
|
||||
super(HTTPClient, self).__init__(timeout=timeout)
|
||||
endpoint=None, token=None, cacert=None, key=None,
|
||||
cert=None):
|
||||
super(HTTPClient, self).__init__(timeout=timeout, ca_certs=cacert)
|
||||
if cert:
|
||||
if key:
|
||||
self.add_certificate(key=key, cert=cert, domain='')
|
||||
else:
|
||||
self.add_certificate(key=cert, cert=cert, domain='')
|
||||
self.username = username
|
||||
self.tenant_id = tenant_id
|
||||
self.tenant_name = tenant_name
|
||||
|
@@ -39,7 +39,7 @@ class ServiceCatalog(object):
|
||||
return token
|
||||
|
||||
def url_for(self, attr=None, filter_value=None,
|
||||
service_type='identity', endpoint_type='publicURL'):
|
||||
service_type='identity', endpoint_type='publicURL'):
|
||||
"""Fetch an endpoint from the service catalog.
|
||||
|
||||
Fetch the specified endpoint from the service catalog for
|
||||
|
@@ -127,6 +127,41 @@ class OpenStackIdentityShell(object):
|
||||
default=env('SERVICE_ENDPOINT'),
|
||||
help='Defaults to env[SERVICE_ENDPOINT]')
|
||||
|
||||
parser.add_argument('--os_cacert', metavar='<ca-certificate>',
|
||||
default=env('OS_CA_CERT'),
|
||||
help='Defaults to env[OS_CA_CERT]')
|
||||
|
||||
parser.add_argument('--os_cert', metavar='<certificate>',
|
||||
default=env('OS_CERT'),
|
||||
help='Defaults to env[OS_CERT]')
|
||||
|
||||
parser.add_argument('--os_key', metavar='<key>',
|
||||
default=env('OS_KEY'),
|
||||
help='Defaults to env[OS_KEY]')
|
||||
|
||||
# FIXME(dtroyer): The args below are here for diablo compatibility,
|
||||
# remove them in folsum cycle
|
||||
|
||||
parser.add_argument('--username',
|
||||
metavar='<auth-user-name>',
|
||||
help='Deprecated')
|
||||
|
||||
parser.add_argument('--password',
|
||||
metavar='<auth-password>',
|
||||
help='Deprecated')
|
||||
|
||||
parser.add_argument('--tenant_name',
|
||||
metavar='<tenant-name>',
|
||||
help='Deprecated')
|
||||
|
||||
parser.add_argument('--auth_url',
|
||||
metavar='<auth-url>',
|
||||
help='Deprecated')
|
||||
|
||||
parser.add_argument('--region_name',
|
||||
metavar='<region-name>',
|
||||
help='Deprecated')
|
||||
|
||||
return parser
|
||||
|
||||
def get_subcommand_parser(self, version):
|
||||
@@ -246,7 +281,10 @@ class OpenStackIdentityShell(object):
|
||||
'env[OS_AUTH_URL]')
|
||||
|
||||
if utils.isunauthenticated(args.func):
|
||||
self.cs = shell_generic.CLIENT_CLASS(endpoint=args.os_auth_url)
|
||||
self.cs = shell_generic.CLIENT_CLASS(endpoint=args.os_auth_url,
|
||||
cacert=args.os_cacert,
|
||||
key=args.os_key,
|
||||
cert=args.os_cert)
|
||||
else:
|
||||
token = None
|
||||
endpoint = None
|
||||
@@ -262,7 +300,10 @@ class OpenStackIdentityShell(object):
|
||||
endpoint=endpoint,
|
||||
password=args.os_password,
|
||||
auth_url=args.os_auth_url,
|
||||
region_name=args.os_region_name)
|
||||
region_name=args.os_region_name,
|
||||
cacert=args.os_cacert,
|
||||
key=args.os_key,
|
||||
cert=args.os_cert)
|
||||
|
||||
try:
|
||||
args.func(self.cs, args)
|
||||
|
60
tests/test_https.py
Normal file
60
tests/test_https.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import httplib2
|
||||
import mock
|
||||
|
||||
from keystoneclient import client
|
||||
from tests import utils
|
||||
|
||||
|
||||
FAKE_RESPONSE = httplib2.Response({"status": 200})
|
||||
FAKE_BODY = '{"hi": "there"}'
|
||||
MOCK_REQUEST = mock.Mock(return_value=(FAKE_RESPONSE, FAKE_BODY))
|
||||
|
||||
|
||||
def get_client():
|
||||
cl = client.HTTPClient(username="username", password="password",
|
||||
tenant_id="tenant", auth_url="auth_test",
|
||||
cacert="ca.pem", key="key.pem", cert="cert.pem")
|
||||
return cl
|
||||
|
||||
|
||||
def get_authed_client():
|
||||
cl = get_client()
|
||||
cl.management_url = "https://127.0.0.1:5000"
|
||||
cl.auth_token = "token"
|
||||
return cl
|
||||
|
||||
|
||||
class ClientTest(utils.TestCase):
|
||||
|
||||
def test_get(self):
|
||||
cl = get_authed_client()
|
||||
|
||||
@mock.patch.object(httplib2.Http, "request", MOCK_REQUEST)
|
||||
@mock.patch('time.time', mock.Mock(return_value=1234))
|
||||
def test_get_call():
|
||||
resp, body = cl.get("/hi")
|
||||
headers = {"X-Auth-Token": "token",
|
||||
"User-Agent": cl.USER_AGENT}
|
||||
MOCK_REQUEST.assert_called_with("https://127.0.0.1:5000/hi",
|
||||
"GET", headers=headers)
|
||||
# Automatic JSON parsing
|
||||
self.assertEqual(body, {"hi": "there"})
|
||||
|
||||
test_get_call()
|
||||
|
||||
def test_post(self):
|
||||
cl = get_authed_client()
|
||||
|
||||
@mock.patch.object(httplib2.Http, "request", MOCK_REQUEST)
|
||||
def test_post_call():
|
||||
cl.post("/hi", body=[1, 2, 3])
|
||||
headers = {
|
||||
"X-Auth-Token": "token",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": cl.USER_AGENT
|
||||
}
|
||||
MOCK_REQUEST.assert_called_with("https://127.0.0.1:5000/hi",
|
||||
"POST", headers=headers,
|
||||
body='[1, 2, 3]')
|
||||
|
||||
test_post_call()
|
Reference in New Issue
Block a user