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()
openSUSE Build Service is sponsored by