File 0001-Add-workaround-for-OSError-raised-by-Popen.communica.patch of Package python-keystoneclient
diff -ruN a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py
--- a/keystoneclient/common/cms.py 2013-10-09 21:46:20.000000000 +0200
+++ b/keystoneclient/common/cms.py 2013-10-14 09:52:06.493270055 +0200
@@ -38,6 +38,36 @@
import subprocess # noqa
+def _fake_openssl_error(files):
+ err = 'Error while writing to pipe.'
+ try:
+ for try_file in files:
+ with open(try_file, 'r'):
+ pass
+ except IOError as e:
+ err = ("Hit OSError while launching openssl. "
+ "Likely due to %s: %s") % (try_file, e.strerror)
+
+ return err
+
+
+def _process_communicate_check_oserror(process, text, files):
+ """Wrapper around process.communicate that checks for OSError."""
+
+ try:
+ output, err = process.communicate(text)
+ except OSError:
+ # this shouldn't happen, but does when Python is old
+ # http://bugs.python.org/issue10963
+ output = ""
+ err = _fake_openssl_error(files)
+ retcode = -1
+ else:
+ retcode = process.poll()
+
+ return output, err, retcode
+
+
def cms_verify(formatted, signing_cert_file_name, ca_file_name):
"""Verifies the signature of the contents IAW CMS syntax.
@@ -53,8 +83,10 @@
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
- output, err = process.communicate(formatted)
- retcode = process.poll()
+
+ output, err, retcode = _process_communicate_check_oserror(
+ process, formatted, (signing_cert_file_name, ca_file_name))
+
if retcode:
# Do not log errors, as some happen in the positive thread
# instead, catch them in the calling code and log them there.
@@ -150,8 +182,10 @@
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
- output, err = process.communicate(text)
- retcode = process.poll()
+
+ output, err, retcode = _process_communicate_check_oserror(
+ process, text, (signing_cert_file_name, signing_key_file_name))
+
if retcode or "Error" in err:
LOG.error('Signing error: %s' % err)
raise subprocess.CalledProcessError(retcode, "openssl")
diff -ruN a/keystoneclient/tests/client_fixtures.py b/keystoneclient/tests/client_fixtures.py
--- a/keystoneclient/tests/client_fixtures.py 2013-10-09 21:46:20.000000000 +0200
+++ b/keystoneclient/tests/client_fixtures.py 2013-10-14 09:52:06.109272165 +0200
@@ -26,7 +26,7 @@
ROOTDIR = os.path.dirname(CLIENTDIR)
CERTDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'certs')
CMSDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'cms')
-
+KEYDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'private')
# @TODO(mordred) This should become a testresources resource attached to the
# class
@@ -49,9 +49,17 @@
REVOCATION_LIST = jsonutils.loads(f.read())
with open(os.path.join(CMSDIR, 'revocation_list.pem')) as f:
SIGNED_REVOCATION_LIST = jsonutils.dumps({'signed': f.read()})
-with open(os.path.join(CERTDIR, 'signing_cert.pem')) as f:
+
+SIGNING_CERT_FILE = os.path.join(CERTDIR, 'signing_cert.pem')
+with open(SIGNING_CERT_FILE) as f:
SIGNING_CERT = f.read()
-with open(os.path.join(CERTDIR, 'cacert.pem')) as f:
+
+SIGNING_KEY_FILE = os.path.join(KEYDIR, 'signing_key.pem')
+with open(SIGNING_KEY_FILE) as f:
+ SIGNING_KEY = f.read()
+
+SIGNING_CA_FILE = os.path.join(CERTDIR, 'cacert.pem')
+with open(SIGNING_CA_FILE) as f:
SIGNING_CA = f.read()
UUID_TOKEN_DEFAULT = "ec6c0710ec2f471498484c1b53ab4f9d"
diff -ruN a/keystoneclient/tests/test_auth_token_middleware.py b/keystoneclient/tests/test_auth_token_middleware.py
--- a/keystoneclient/tests/test_auth_token_middleware.py 2013-10-09 21:46:20.000000000 +0200
+++ b/keystoneclient/tests/test_auth_token_middleware.py 2013-10-14 09:52:46.021052970 +0200
@@ -20,6 +20,7 @@
import os
import shutil
import stat
+import subprocess
import sys
import tempfile
import testtools
@@ -1256,6 +1257,78 @@
self.assertEqual('foo%20bar', auth_token.safe_quote('foo%20bar'))
+class CmsTest(testtools.TestCase):
+
+ """Unit tests for the keystoneclient.common.cms module."""
+
+ def test_token_to_cms_to_token(self):
+ with open(os.path.join(client_fixtures.CMSDIR,
+ 'auth_token_scoped.pem')) as f:
+ AUTH_TOKEN_SCOPED_CMS = f.read()
+
+ self.assertEqual(cms.token_to_cms(client_fixtures.SIGNED_TOKEN_SCOPED),
+ AUTH_TOKEN_SCOPED_CMS)
+
+ tok = cms.cms_to_token(cms.token_to_cms(
+ client_fixtures.SIGNED_TOKEN_SCOPED))
+ self.assertEqual(tok, client_fixtures.SIGNED_TOKEN_SCOPED)
+
+ def test_ans1_token(self):
+ self.assertTrue(cms.is_ans1_token(client_fixtures.SIGNED_TOKEN_SCOPED))
+ self.assertFalse(cms.is_ans1_token('FOOBAR'))
+
+ def test_cms_sign_token_no_files(self):
+ self.assertRaises(subprocess.CalledProcessError,
+ cms.cms_sign_token,
+ client_fixtures.SIGNED_TOKEN_SCOPED,
+ '/no/such/file', '/no/such/key')
+
+ def test_cms_sign_token_success(self):
+ self.assertTrue(
+ cms.cms_sign_token(client_fixtures.SIGNED_TOKEN_SCOPED,
+ client_fixtures.SIGNING_CERT_FILE,
+ client_fixtures.SIGNING_KEY_FILE))
+
+ def test_cms_verify_token_no_files(self):
+ self.assertRaises(subprocess.CalledProcessError,
+ cms.cms_verify,
+ client_fixtures.SIGNED_TOKEN_SCOPED,
+ '/no/such/file', '/no/such/key')
+
+ def test_cms_verify_token_no_oserror(self):
+ try:
+ cms.cms_verify("x" * 2 ** 17, '/no/such/file', '/no/such/key')
+ except subprocess.CalledProcessError as e:
+ self.assertTrue('/no/such/file' in e.output)
+ else:
+ raise
+
+ def test_cms_verify_token_scoped(self):
+ cms_content = cms.token_to_cms(client_fixtures.SIGNED_TOKEN_SCOPED)
+ self.assertTrue(cms.cms_verify(cms_content,
+ client_fixtures.SIGNING_CERT_FILE,
+ client_fixtures.SIGNING_CA_FILE))
+
+ def test_cms_verify_token_scoped_expired(self):
+ cms_content = cms.token_to_cms(
+ client_fixtures.SIGNED_TOKEN_SCOPED_EXPIRED)
+ self.assertTrue(cms.cms_verify(cms_content,
+ client_fixtures.SIGNING_CERT_FILE,
+ client_fixtures.SIGNING_CA_FILE))
+
+ def test_cms_verify_token_unscoped(self):
+ cms_content = cms.token_to_cms(client_fixtures.SIGNED_TOKEN_UNSCOPED)
+ self.assertTrue(cms.cms_verify(cms_content,
+ client_fixtures.SIGNING_CERT_FILE,
+ client_fixtures.SIGNING_CA_FILE))
+
+ def test_cms_verify_token_v3_scoped(self):
+ cms_content = cms.token_to_cms(client_fixtures.SIGNED_v3_TOKEN_SCOPED)
+ self.assertTrue(cms.cms_verify(cms_content,
+ client_fixtures.SIGNING_CERT_FILE,
+ client_fixtures.SIGNING_CA_FILE))
+
+
class TokenExpirationTest(BaseAuthTokenMiddlewareTest):
def setUp(self):
super(TokenExpirationTest, self).setUp()