Merge "Migrate the keystone.common.cms to keystoneclient"

This commit is contained in:
Jenkins
2013-11-26 08:04:33 +00:00
committed by Gerrit Code Review
5 changed files with 86 additions and 9 deletions

View File

@@ -12,10 +12,20 @@
# License for the specific language governing permissions and limitations
# under the License.
import hashlib
"""Certificate signing functions.
Call set_subprocess() with the subprocess module. Either Python's
subprocess or eventlet.green.subprocess can be used.
If set_subprocess() is not called, this module will pick Python's subprocess
or eventlet.green.subprocess based on if os module is patched by eventlet.
"""
import hashlib
import logging
from keystoneclient import exceptions
subprocess = None
LOG = logging.getLogger(__name__)
@@ -38,10 +48,20 @@ def _ensure_subprocess():
import subprocess # noqa
def set_subprocess(_subprocess=None):
"""Set subprocess module to use.
The subprocess could be eventlet.green.subprocess if using eventlet,
or Python's subprocess otherwise.
"""
global subprocess
subprocess = _subprocess
def cms_verify(formatted, signing_cert_file_name, ca_file_name):
"""Verifies the signature of the contents IAW CMS syntax.
:raises: subprocess.CalledProcessError
:raises: CertificateConfigError if certificate is not configured properly.
"""
_ensure_subprocess()
process = subprocess.Popen(["openssl", "cms", "-verify",
@@ -55,9 +75,23 @@ def cms_verify(formatted, signing_cert_file_name, ca_file_name):
stderr=subprocess.PIPE)
output, err = process.communicate(formatted)
retcode = process.poll()
if retcode:
# Do not log errors, as some happen in the positive thread
# instead, catch them in the calling code and log them there.
# Do not log errors, as some happen in the positive thread
# instead, catch them in the calling code and log them there.
# When invoke the openssl with not exist file, return code 2
# and error msg will be returned.
# You can get more from
# http://www.openssl.org/docs/apps/cms.html#EXIT_CODES
#
# $ openssl cms -verify -certfile not_exist_file -CAfile \
# not_exist_file -inform PEM -nosmimecap -nodetach \
# -nocerts -noattr
# Error opening certificate file not_exist_file
#
if retcode == 2:
raise exceptions.CertificateConfigError(err)
elif retcode:
# NOTE(dmllr): Python 2.6 compatibility:
# CalledProcessError did not have output keyword argument
e = subprocess.CalledProcessError(retcode, "openssl")

View File

@@ -20,3 +20,12 @@ Exception definitions.
#flake8: noqa
from keystoneclient.apiclient.exceptions import *
class CertificateConfigError(Exception):
"""Error reading the certificate"""
def __init__(self, output):
self.output = output
msg = ("Unable to load certificate. "
"Ensure your system is configured properly.")
super(CertificateConfigError, self).__init__(msg)

View File

@@ -157,6 +157,7 @@ import netaddr
import six
from keystoneclient.common import cms
from keystoneclient import exceptions
from keystoneclient.middleware import memcache_crypt
from keystoneclient.openstack.common import jsonutils
from keystoneclient.openstack.common import memorycache
@@ -1158,7 +1159,7 @@ class AuthProtocol(object):
try:
output = cms.cms_verify(data, self.signing_cert_file_name,
self.signing_ca_file_name)
except cms.subprocess.CalledProcessError as err:
except exceptions.CertificateConfigError as err:
if self.cert_file_missing(err.output,
self.signing_cert_file_name):
self.fetch_signing_cert()
@@ -1167,8 +1168,10 @@ class AuthProtocol(object):
self.signing_ca_file_name):
self.fetch_ca_cert()
continue
raise
except cms.subprocess.CalledProcessError as err:
self.LOG.warning('Verify error: %s' % err)
raise err
raise
return output
def verify_signed_token(self, signed_text):
@@ -1266,8 +1269,10 @@ class AuthProtocol(object):
with open(self.signing_cert_file_name, 'w') as certfile:
certfile.write(data)
if response.status_code != 200:
raise exceptions.CertificateConfigError(response.text)
try:
#todo check response
try:
write_cert_file(response.text)
except IOError:
@@ -1282,8 +1287,10 @@ class AuthProtocol(object):
path = self.auth_admin_prefix.rstrip('/') + '/v2.0/certificates/ca'
response = self._http_request('GET', path)
if response.status_code != 200:
raise exceptions.CertificateConfigError(response.text)
try:
#todo check response
with open(self.signing_ca_file_name, 'w') as certfile:
certfile.write(response.text)
except (AssertionError, KeyError):

View File

@@ -31,6 +31,7 @@ import mock
import webob
from keystoneclient.common import cms
from keystoneclient import exceptions
from keystoneclient.middleware import auth_token
from keystoneclient.openstack.common import jsonutils
from keystoneclient.openstack.common import memorycache
@@ -886,7 +887,7 @@ class CertDownloadMiddlewareTest(BaseAuthTokenMiddlewareTest):
httpretty.register_uri(httpretty.GET,
"%s/v2.0/certificates/signing" % BASE_URI,
status=404)
self.assertRaises(cms.subprocess.CalledProcessError,
self.assertRaises(exceptions.CertificateConfigError,
self.middleware.verify_signed_token,
client_fixtures.SIGNED_TOKEN_SCOPED)

View File

@@ -0,0 +1,26 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Licensed 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.
from keystoneclient.common import cms
from keystoneclient import exceptions
from keystoneclient.tests import utils
class CMSTest(utils.TestCase):
def test_cms_verify(self):
self.assertRaises(exceptions.CertificateConfigError,
cms.cms_verify,
'data',
'no_exist_cert_file',
'no_exist_ca_file')