summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Young <ayoung@redhat.com>2014-02-04 20:43:07 -0500
committerMorgan Fainberg <morgan.fainberg@gmail.com>2014-05-09 11:48:17 -0700
commit3d6d749e6f0fef682a88758e1a2f6c9e8e7bd23c (patch)
treeb5ffa079f9bdd6214c581e872ea668217834d312
parenta95edc7f38d7c267f9efa6c4a413b4a04d2686b0 (diff)
downloadpython-keystoneclient-3d6d749e6f0fef682a88758e1a2f6c9e8e7bd23c.tar.gz
Compressed Signature and Validation
Allows for a new form of document signature. pkiz_sign will take data and encode it in a string that starts with the substring "PKIZ_". This prefix indicates that the data has been: 1) Signed via PKI in Crypto Message Syntax (CMS) in binary (DER) format 2) Compressed using zlib (comparable to gzip) 3) urlsafe-base64 decoded This process is reversed to validate the data. middleware/auth_token.py will be capable of validating Keystone tokens that are marshalled in the new format. The current existing "PKI" tokens will continue to be identified with "MII", issued by default, and validated as well. It will require corresponding changes on the Keystone server to issue the new token format. A separate script for generating the sample data used in the unit tests, examples/pki/gen_cmsz.py, also serves as an example of how to call the API from Python code. Some of the sample data for the old tests had to be regenerated. A stray comma in one of the JSON files made for non-parsing JSON. Blueprint: compress-tokens Closes-Bug: #1255321 Change-Id: Ia9a66ba3742da0bcd58c4c096b28cc8a66ad6569
-rw-r--r--examples/pki/cms/auth_token_revoked.pkiz1
-rw-r--r--examples/pki/cms/auth_token_scoped.pkiz1
-rw-r--r--examples/pki/cms/auth_token_scoped_expired.pkiz1
-rw-r--r--examples/pki/cms/auth_token_unscoped.pem14
-rw-r--r--examples/pki/cms/auth_token_unscoped.pkiz1
-rw-r--r--examples/pki/cms/auth_v3_token_revoked.json2
-rw-r--r--examples/pki/cms/auth_v3_token_revoked.pem26
-rw-r--r--examples/pki/cms/auth_v3_token_revoked.pkiz1
-rw-r--r--examples/pki/cms/auth_v3_token_scoped.pkiz1
-rw-r--r--examples/pki/cms/revocation_list.der0
-rw-r--r--examples/pki/cms/revocation_list.json2
-rw-r--r--examples/pki/cms/revocation_list.pem31
-rw-r--r--examples/pki/cms/revocation_list.pkiz1
-rw-r--r--examples/pki/gen_cmsz.py117
-rw-r--r--keystoneclient/common/cms.py110
-rw-r--r--keystoneclient/exceptions.py8
-rw-r--r--keystoneclient/middleware/auth_token.py26
-rw-r--r--keystoneclient/tests/client_fixtures.py67
-rw-r--r--keystoneclient/tests/test_auth_token_middleware.py45
-rw-r--r--keystoneclient/tests/test_cms.py16
20 files changed, 412 insertions, 59 deletions
diff --git a/examples/pki/cms/auth_token_revoked.pkiz b/examples/pki/cms/auth_token_revoked.pkiz
new file mode 100644
index 0000000..9fbe8ea
--- /dev/null
+++ b/examples/pki/cms/auth_token_revoked.pkiz
@@ -0,0 +1 @@
+PKIZ_eJylVtly4jgUfddXzHuqK9jGED_Mgze8BInYeEF-8wJeBYTF29ePbEh3p9OZycxQRZUtS_eee87Rlb59oz9J1Qz0hwzXw8s3AA1DZxpsPh8CI6tjJFqxfKBjnSLL0pMli5bayo6oS6l7UlIoawUd31qavH7V1kbEAcVSdTGkg4mrpunG3nZmhllUxRzMV7k0N_b0eR8cMespeGNnkSbsjeKQ-tw5j8jiAoK1MTNkk43Ylol8N1_KYh74fBlrwjHa2_3bZOzbl9DnPbdsaGAxD3V7EiuHGix7tUPdtFkW4hU6hynqY3bJ4XbZ4wkuAgLZIMcsZGBv9ch3p9jBTUAQWSlVjgvMAugkmZE3qbE3q4Ct6igfEXWBnxwjln-JyA0VzT4JNuYV--07FGCA8X9QgAHGDxQSg0l7xIy3duQRySHR7WaVP9XQMbgxgTxtV0XKoR7XSaHWABV2jgjuA2IWuHd7pEAmcLIMFRLBLJ6ufDNHBW4Rq-Y7b3KmQSfbjVQN5Br7oAaR7l2oEsOHKiJ2E7HVNdHRLtKqa3iTMtps6EL9JttdtX2kLa6YdXPwb2X7hS8ewKLsBsL-qxLgs8jvA39OLnjPbtmtHGNg9yNhpLpgP6nGgMS7BrpUD4hAzAhn-nCKOxp5cUl26yal-4HCZO4L-Toh6qcWB18kazDXZDQX1f5n6cE_aT9kjom3D33hetP-TnQpXAf5Aa1zgFTFhM-ixVccaA0cXeH6iUWawYKgoGAIKpADJ7D3qpWmslALiqBIeUwMFhUqh29GaxLfpHyhL22m39b7u3LB33qdoDraSEyifWw0G7Y9RuTSg1EOhhGWMm1fAw-0K43wWI-PObt-c-FndgdfkLCn_DCoE1iYT5tfLT-osP5q9_ldcPAx-lebittARaxBUhh0wBQ262GxzcfanQPfrmi9x0QvPyVw4AIMBN4X15S40W10L1RbXTpSB46TjMJoYJ9eoKJeoJO5sFBn0LFmUElCcINNs5HFNRkg085Ds2W0jCoY3-0u8d1B3h8b7G3-QriCYRDenFYGG1TEpGoS7d5UNJ6JtGb4dgxufEyG4LSMXehbrbGf3PbC_WND-1wR-FkdaXRv5KYw1J5s6NGW35DFRDjTJO_6JaCa0gXuW0sbnjujmvwC2awSIpwC396NAW-GG9fcA3j9zwfmvfN29Lyk5ZkfXDoicYzR-kMJTMx63c8Lg00wKFJuOK-_Geo7T2_lfp8D7pPupDDCztFkMT40aaprYqpK0NBK-t9C69DIIlY8y1qojcpA69zIFlYAHdDUxvTcXl1CsdRExlVlCcrWRG3VQrSkFHmSGDuyh5iI8HxCFhS-uoaSOM4FcgZNh5OqqEIT7KMTtNVGacZMS7XJlsGm6hONti9HraAMv99M6MXEFG3sgx_b1hOjIdD-FmhJhC7oVRdKxphJbOHSZb1zkEtO6CfXwKfXH5oMSA1ePDdTRcwOjWL9fFdSJckS6bVHFfF1IvDP-CWbCmXy9NpVu_BpqcRivc16oLGr4hK_vmoz1BDkvSxetosqVk-l6J5X-elhpsFty70GHNfuNX6VQnbGwedWP0pnp9wFMTBTn1wV_hryDJ7He69j2piEh31eh4yyeDTnVnOUqwekOJskWmXPiGm6R-UlY4xz-ZjMe0C6bus-TBfLy45cLuHM19gyW1Df1s5JbjUu1XU3FphSW7XS6UnvrDYL42XW7YvwyD-fOhBCxpuHZbEsrSeTeY6cR3W5TY66RQ4MmmvZUYXRflFI5uuWEecPjMA9If-BMIFQZVOb04E_O0ai7my7iTy3iyjLPXa6O678kDwyBSTepGIrln2AO_U4mzlzS-TU7WP1_DJr_vwTjHdVFSk_7q1_AfJ_mjc= \ No newline at end of file
diff --git a/examples/pki/cms/auth_token_scoped.pkiz b/examples/pki/cms/auth_token_scoped.pkiz
new file mode 100644
index 0000000..34d7706
--- /dev/null
+++ b/examples/pki/cms/auth_token_scoped.pkiz
@@ -0,0 +1 @@
+PKIZ_eJylVst2ozgU3OsrZp_Tx4CNY5biaRFLGMx7ZyDGYMBObJ5fPwInpyedzkxmhhUIqVS36t4r_fhBH1HREPlDwrvx4wfACK1bM9CfziE6NjGBZiyd6dg1lyRxuZCgqXSSDddi6rzKKZa0cTxeaNLuRduhaA5kU1nDPR2MVkqaeo_PvX4MOFLEc5wZmfiIKvpehZeAc-XAt46RJlQoP6fe_JpFpXoD4Q4tkaRzEdexkedkGwlmocefYk24RJU1vE8OPOu293jXObUUGGb7tcXE8rkBm0HpSb9oNzmssX1ekCHmNvOg2wwBE-RhibkwCzjM4sEciOcsAjtow5KUhlxkQR5wANvJEWVtiiq9CLmiibKJUR96ySXi-G1U3lnR3ZnQ1-vA6z6wACON_8MCjDR-shDZoOwuAevubGlick7WVmtkqwbbaD5tIC06I0_nZAiaJFcaQHIrI2UwhKWeB4MzEBmzoX08klwsAy5YGJ6ekTzoCKdkB5e5UlDm2ReLUVxUhQ2I1u6NOjH-KKLSaiOuqJM1OURaUe_vVka-Txeu77a9uVZFmloHnJOBf2vbL3rxAOenfhTsvzoBvkL-CPy1uOCjuqfesNGo7mfByuIWeEkxAZZuHa7FZmQEYla40pfXuKfI6i057NqU1gOlyb4t5JukVL5McfBNscbkYqbkot7_1XrwT96PO8elW-09ob57_yb0SahH-wGNc6RUxCV_jNTvZKA5alTj3YojGuJAmFMyJcmJjRk8uIWhKRzWwjzMUz4oEUdyZR7cE61NPJ3qRb5VTL-N93fhgr_N9ZI0kS-yifa50fhcd4nK2wAmO1hW2Ei0fY060K400eNcPp5bzXsWfpXu4BsWDlQflvQCh7NF-2vKjy7svtt9fgcOPqN_t6k4LZZhA5Ic0QFd8HfjYouPtTcNPKug8V6S9elLAUctwCjg2-KGCjdlG62F4nktXmgGTpNQjlo8pDcsKzdsHx2cK0tsm0ssJ3twp013K9U6GSnTzkN3O9IwinD6tvrEc0Z7fxbY-3xVqME4iO-Zdgp9ksdl0SbaW1PReDbS2vHfJbzrwYzgNIzD3jM7VDH3Wnj72dI-l4fesYk0WhuZLoyxJz492rI7s7gUrnSTD_0SUE_pAue9pY3vPSqYXyi7A7X1MDVV-71CRzCcgRHlQwN5B6w-deKenp8Fzt4dm0DvGny1C41zsnQKoxAuoUzrxWcFHCCxp8c8jAMJ0PO_Tfdmm4aLTsohElPiitCxoe100gD1-3dgw8K1sXltJTOQXdNESqvLpq3sABahBllHETusO3O3jqqCoylcYAu1CpwmPyltsY01t3bmFr07XDvFhts78NUGknIrnn3C0Fqgdjotav96WzmJ6jF8Df1iSDTawhyxGYHiO1AdzfUKYMtslXTaSVbamx16XYlUcgkpYEgjUj5cbyAR09PL8ZRpQsuINHwVQLij9yBp74o5-3C9beMjRm4RGubu5K2F9HGJocPh_HJ7OM-zk36Nb-eHw2sxnGZ74rvrAqi2wSpx1jJyNWd7CHM1LftoqJiSh-nGUy32Js_OzhI1jmuXPJJmF9hh5aytDpquHbdgGGbIvIVPr71BcFdDy7fk2ZFJ92m33szIIMlu-IIEf-UzJFJOwolZRZ1hz-ONETD7_AwstzFmO7fpltxy63KH5wd0qXbBIt7HrOs-YWgF-_PT7CF9KnouPykraZg9YN1WOdW_7O0ckPm5UMNs268OL8QpD24qFNvu8eHFEjtI2uct79Qmn3P8cWWacap2kXw1ZCHP4Gzj16QE2-r1YrVQqwweOk_ybmMdDF83-GVNIJjuogqRf95L_wRcTpJ3 \ No newline at end of file
diff --git a/examples/pki/cms/auth_token_scoped_expired.pkiz b/examples/pki/cms/auth_token_scoped_expired.pkiz
new file mode 100644
index 0000000..766b4cd
--- /dev/null
+++ b/examples/pki/cms/auth_token_scoped_expired.pkiz
@@ -0,0 +1 @@
+PKIZ_eJylVtlyozgUfddXzHuqK2xOzCObMdiSzW7pzUCMwchLbNavH4GT6kmnM5OZcZWrQEhH555z75V-_GA_1TAt9IcGveHlB4CWNW8cbC9OxNrXCVKcRDuxsWuhaeqTpCmO0Wq-Mlez4FXPoGYO44lkat7F9KxYBLpjzJUtG4ynRpZFzy-dvccCKhMR5qtcfbaO7PlIzlgIdbxx97EpH63ilEXiNY_p7AaIZz1Zmi3EQsvHUZAvNSUn0eSQmPI5Prr9-2QcubdtNAmDQ8OAlXw7d7lEP9Vg2Rsd6qRmWSgV9E8S6hNhKeJ22WMOF4RCgeRYgDzsnR5FgYR93BCK6Eovc1xgAUA_3Vt5k1lHuyRCWcf5yKgjUXqOhck6pndWbHeObOwKR-0HFmCg8X9YgIHGTxYqj2l7xnzo-drI5JTO3WaVT2voW-K4gSa1qyITUY_rtDBqgAo3RxT3hNoF7oMe6ZAn_n6PCpViAUuryM5RgVskGPku5K4MlHvZqOUgrnUkNYjn4Y05MXwoY-o2sVBW6RztYrOstncr482GLZzfbXtz7RibswoLQQ7-rW2_6DUBsDh0g2D_1QnwFfJH4K_FBR_VPXQr3xrU_SwYLW84SssRkIYVmav1wAgkvHxlD69Jx5Bnt3TnNRmrB0aTf1s4qVNqfJni4JtiDcnFjcnFvP-r9eCfvB92Tmh43EZydff-TeiDXA32AxbnQKlM6GQfz76Tgc6gUQW9qYBMSwCkYGQoKpAPOdiH5co0BGiSghTZBFNLQIUh4nuiNWlkM73Qt4rpt_H-Llzwt7lOUR1vVD41PzeajdCeY3rrwWgHz8tLjbWvQQfWlUZ6QjhJRLd-z8Kv0h18w8Ke6cOjThZgLjW_pvzggvfd7vM7cPAZ_btNJWigrtQgLSw2YMsbb1jsThLzTYPILVm853R--FLAQQswCPi2uGbCjdnGaqF8matnloHjJKuwGugrN6hj9rcD6DtPSE-eYO9uwZ02243OqnSgzDoP223PwijJ-O52aRQM9v4ssPf5M7kCwyC8Z9qBbFCR0LJJzbemYk742GyGb2dy14MbwFkYu23ktNaRu9fC28eG9bmCRPs6Nllt5LY8xJ5u2NGW35klVL6yTT70S8A8ZQuC95Y2PHdWyf1COeyZrbuxqfrvFTqAwRwMKB8ayDvg8VMn7tj5WcL83bER9K7BV7uwOEdLxzBK-Ux0Vi8bXobYUjt2zCsJ1gA7_5ts6zQZkVqtUCw1Q6GqBL7iB63WK_b9HftKGfrQuTaag_XQcSyjsXXHNzwAVcVU-MBQW2gHYljFx1JgKVxC12oMZZy8MJpynZhhFYguuztcW8NX1nfgqw8041a-bBDHaoHZGTRW89fbykGd7ckr2ZR9arIWFqj1AJTcgapYtI8Auk5jZONOutHcfBK11JqhM2GAhEVkfLjeKEjNDpf9ITflhlNZ-DOgKB67B2niTXTXpH1IYeWIT09VZWNhm5pu_7LFotenk40hKN5tMWmeLuGz5F_p9Lw8CZct2Exj5Vhc1ig3oPTgy6G0cGOnnYclRPPLjp6a5elZauAxWJk7U3pep74japd2cbW6ykoJIP5aWuX7hwdztjNlszcnrfuwmnC8LJSzZ11Osktpha621jm0Jdw6epycXy3yWK5odqWiC66rXBCk-CJeBffxOaJazV2mNJhOt4l2eFXI3o0Wt2oBV3SWRiePSlr56B_UY9dRTz2YEvCb9bK-zFdQrRHO5cuZqx5fIiHT1CZ3-SQq7Cpz7MNRvjxORbSpQnmy7B7YRZI_16hsr-B6Pb2IF9vVHjxzkSbJLjhEi9h4DOIVBeNd1ED6z3vpnxbOkgI= \ No newline at end of file
diff --git a/examples/pki/cms/auth_token_unscoped.pem b/examples/pki/cms/auth_token_unscoped.pem
index 6c93452..4ef7a78 100644
--- a/examples/pki/cms/auth_token_unscoped.pem
+++ b/examples/pki/cms/auth_token_unscoped.pem
@@ -5,15 +5,15 @@ MTItMDgtMTdUMTU6MzU6MzRaIiwgImlkIjogIjAxZTAzMmM5OTZlZjQ0MDZiMTQ0
MzM1OTE1YTQxZTc5In0sICJzZXJ2aWNlQ2F0YWxvZyI6IHt9LCAidXNlciI6IHsi
dXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQi
OiAiYzljODllM2JlM2VlNDUzZmJmMDBjNzk2NmY2ZDNmYmQiLCAicm9sZXMiOiBb
-eyduYW1lJzogJ3JvbGUxJ30seyduYW1lJzogJ3JvbGUyJ30sXSwgIm5hbWUiOiAi
+eyJuYW1lIjogInJvbGUxIn0sIHsibmFtZSI6ICJyb2xlMiJ9XSwgIm5hbWUiOiAi
dXNlcl9uYW1lMSJ9fX0xggHKMIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkG
A1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNV
BAoTCU9wZW5TdGFjazERMA8GA1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEW
FmtleXN0b25lQG9wZW5zdGFjay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgER
-MAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAFq4JvODBIaoHiYG6KMCnBEhDjWS
-CuW0gq3kbi3j8kOzb4Mr7Muq0XvGMRwDrZlkfSpzIyuri/Fzf2pW58hnjWfDHQ1S
-laAWLs6csh2u80hgWpMngCN5ZVFtIIbWlE0ZuLZh8p7E0IJZnNvYmlOVrmIkRo+J
-1vMr71HZr5/kFcJzFVgi8QI4XU5iBPsUWOdJJV+0jXkMHVqOX3H297CYCePaotLD
-azuquE74N8KMyl8j8jE9wi9O1gVBqO4L66ePjt5zI/TrjbjKwdseqoZR1dDGlp5V
-awRwRYCjsKF+asAbuASOwdSgP8V6VgTOUrZh2D8KHtclwS+URoTdVl4ypQA=
+MAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAFvooB0VQsp6sBW+xbnGmfDKlLWS
+XHA1kqS5GuI1wu+rqSGarUR4WNCuBCp4bNzfgM+mXSArL/tTCiAMhs/Lh6GOYC7w
+ZOFh8GSIIcLFYThCPZa+uV/39ZaLTguMmjYPZq1EUco+NErajY6mbVGpshlb8Y5l
+F6cNkrMhPbskcARi6BUWu/eObjfeb9uw13wVIyWKQIEKA1UGA0yeyi+I6kmYpyBw
+U4fWKdvcvOiXiGSWZuToc/xZQV0NooQeEZI87n2AF+dGLe/7YJi7MdP7klI5u0Ue
+VP1YdeRzH4a2wyNRvGjD/b8+ZNqF+WDulfWSQ+spKqz2Y4FEO6z8ZuvI4wM=
-----END CMS-----
diff --git a/examples/pki/cms/auth_token_unscoped.pkiz b/examples/pki/cms/auth_token_unscoped.pkiz
new file mode 100644
index 0000000..13c5e40
--- /dev/null
+++ b/examples/pki/cms/auth_token_unscoped.pkiz
@@ -0,0 +1 @@
+PKIZ_eJx9VMmSozgQvfMVfa-oMAbbVRzmIAlZCFvQGLHewAs72MaY5esHuzt65tSKUEiZkS_z5RL5-TkfiAk1fiBmv4RPgVGq7kCg75qQps-jAawjamYd4QiBwUHAwgPiQIOJc1cThkg-67lDkH0jNo1lQbWwBqJZaQc4SXB2HvU0kIzyKLPMzOAXred_HV4DyVUD_5DGRKlp3iRnWWwp0kUhlh5lnNEN1dos9NM-8vXyOM4yoiPjeNxzsNpzLLsqXpo5e13Ry-gLfA0R3QizYc88p2eTnpu8kEIvEA0VSEGO55dNBi8Gw8PibCObtq7sEchO_szqd1DhWClt6BuXmJRd9It27Nt9Qqt1GnvOLP8GlEoXeMuS2e_oYywNb6YC3T6-_m_8dshxdpmdzPV4g14501p_xsQZab08_WEx44S_RHnnOL-56bGV6TlTUDlT6DmiwY0qqIKeESYLJg-kMA8LJoVZiHTl4otDkmi7ub1wSCgEHMGrimCd4x0DCQFLB8MDgwbHewYKIrwVKUOuywY0AR0mhgtBwkFhQHagPQaB6lqWhvuSn7x1d_bDuZXOgHNgvWwFCBqOHKUPvTU_kW0eTfjAwPc7EhoYtSV3fZQPz7hyBp2DHCbFLS0yovQiRBb2hG31KM--IcbSurTI29H0djSun8fqOGxVYP9ixThaGmVMgsSRyjqu3AIk-CAwcCTQbk3Q04gB8c-IzhMKgeUAONcCbO8atS73i3mAGF0iWEaZWKcHN11FAj1_r8a1F5ZGKDWGyD468ZlOstqwRb1jnp5-5fK-M-cJvXSTbE6Vxqs4Sg9dUQdNcSuE_Cfc3JzH-fqxLruP-wpoqpNGV9iP8lMuzsmGtUkY1PCeUyJHQ7Nl2vfJslSkKOoJWpOw21fD1JDztsjbyx27Hw95icVWut-JOC6a_SUK-k1AmpUrNtpjm3T5osNNEn608g1lsSOgZBVvppgUhx2vm-5ate56rZynjSgam_tr6J7awn9y4n5Lth48bJRdy6Wx8m52ju7IE1Z-G92-ldZegIXrbm6gHJuBT63Ss1g3be9i5-ZTVotYxMm5WNrPXaB2_PpzsPt_hPdKwYb633r5FzKfcIU= \ No newline at end of file
diff --git a/examples/pki/cms/auth_v3_token_revoked.json b/examples/pki/cms/auth_v3_token_revoked.json
index c1680c1..63410f1 100644
--- a/examples/pki/cms/auth_v3_token_revoked.json
+++ b/examples/pki/cms/auth_v3_token_revoked.json
@@ -7,6 +7,6 @@
"project": {"enabled": true, "description": null, "name": "tenant_name1", "id": "tenant_id1", "domain": {"id": "domain_id1", "name": "domain_name1"}},
"user": {"name": "revoked_username1", "id": "revoked_user_id1", "domain": {"id": "domain_id1", "name": "domain_name1"}},
"roles": [{"name": "role1"}, {"name": "role2"}],
- "methods": ["password"],
+ "methods": ["password"]
}
}
diff --git a/examples/pki/cms/auth_v3_token_revoked.pem b/examples/pki/cms/auth_v3_token_revoked.pem
index 9b0b1e2..c908533 100644
--- a/examples/pki/cms/auth_v3_token_revoked.pem
+++ b/examples/pki/cms/auth_v3_token_revoked.pem
@@ -1,6 +1,6 @@
-----BEGIN CMS-----
-MIIIVgYJKoZIhvcNAQcCoIIIRzCCCEMCAQExCTAHBgUrDgMCGjCCBmMGCSqGSIb3
-DQEHAaCCBlQEggZQeyJ0b2tlbiI6DQogICAgeyJjYXRhbG9nIjogW3siZW5kcG9p
+MIIIVQYJKoZIhvcNAQcCoIIIRjCCCEICAQExCTAHBgUrDgMCGjCCBmIGCSqGSIb3
+DQEHAaCCBlMEggZPeyJ0b2tlbiI6DQogICAgeyJjYXRhbG9nIjogW3siZW5kcG9p
bnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3YxLzY0
YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInJlZ2lvbiI6ICJyZWdp
b25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3Yx
@@ -33,15 +33,15 @@ bl9uYW1lMSJ9fSwNCiAgICAgInVzZXIiOiB7Im5hbWUiOiAicmV2b2tlZF91c2Vy
bmFtZTEiLCAiaWQiOiAicmV2b2tlZF91c2VyX2lkMSIsICJkb21haW4iOiB7Imlk
IjogImRvbWFpbl9pZDEiLCAibmFtZSI6ICJkb21haW5fbmFtZTEifX0sDQogICAg
ICJyb2xlcyI6IFt7Im5hbWUiOiAicm9sZTEifSwgeyJuYW1lIjogInJvbGUyIn1d
-LA0KICAgICAibWV0aG9kcyI6IFsicGFzc3dvcmQiXSwNCiAgICB9DQp9DQoxggHK
-MIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
-AkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5TdGFjazERMA8G
-A1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25lQG9wZW5zdGFj
-ay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIaMA0GCSqGSIb3
-DQEBAQUABIIBAI9qvSGYlIHoI0gWTZ55POWwj5Gjyr/SQ4q2e13m5bSnmvawGw6Z
-Xa500UvvnUPHe/Nf4ExS0/hO2zn80hjLC+uEDwESlMMDTc29+TbafHTQOp+Zz742
-KdO+2Zv3UevStJK+wg+D0cKUmhmghyzzIsD44OmzLaGe+3mCqLkWFv8i7KX9rrb5
-Jqv8kbLm9bY7wlWqmYcaJyXy5SdJMKi1/aWm9nn5AOaujHTfV/bygQd8ZY9t4+6k
-OwKPZlt5x1KA3IxGdJUFvIHj7am6j0auQ2TMx8x2vzPzy5+mBzB0u0XaENJsb9Jz
-z+aVgXOQ81PbwwZmStONrwEVpjQeyEXY4pM=
+LA0KICAgICAibWV0aG9kcyI6IFsicGFzc3dvcmQiXQ0KICAgIH0NCn0NCjGCAcow
+ggHGAgEBMIGkMIGeMQowCAYDVQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMC
+Q0ExEjAQBgNVBAcTCVN1bm55dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYD
+VQQLEwhLZXlzdG9uZTElMCMGCSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNr
+Lm9yZzEUMBIGA1UEAxMLU2VsZiBTaWduZWQCAREwBwYFKw4DAhowDQYJKoZIhvcN
+AQEBBQAEggEAmG4yoCylqeL51u3yAOI5hGOlOZrBT53W7GGLpTqa2NZxXJOhVhPa
+UBn8idQtVOPHk66XOrGdExSy0QSvTz/Q9iFQ5Tj7NsYj3vCOIHF7UqZo1SfRJ6Ss
+iE18JPYMDCt9kChcPyiNpdPpqUyHuX2Oe83yVZtfljf9u+WNv2kaNys2gwdrMKIb
+rKC3/JFoEEn6ISqkRqs3+aEbe++Z0YykrFctuYvctJPARqFewmBvkvrnOXuaeIsN
+kT70Zgthd/JUHp/fC2vbRtIXiskl9zVegAtu10nlHV9ff3B2YHZi1MGcwJAnwxyY
+eRuWwQ5bndCczoncOpb13FbC1eeOBgrXNQ==
-----END CMS-----
diff --git a/examples/pki/cms/auth_v3_token_revoked.pkiz b/examples/pki/cms/auth_v3_token_revoked.pkiz
new file mode 100644
index 0000000..67823fd
--- /dev/null
+++ b/examples/pki/cms/auth_v3_token_revoked.pkiz
@@ -0,0 +1 @@
+PKIZ_eJylVsmSozgQvesr5l7R0Symyhz6wG5oS5jFgLixtDEY7PLC-vUjYXd31Sw1PTOOcNgIZerle7no0yfykTXDRL8p0KMPnwA0zdWywNbXU2zuuwxJTqacyNpiUhRZXCqSow2KL63kYntRC6gYFVnfLQ3FOxuemfJAdbSVlNBFSSuK6PpttJiUu9VpaT6bq2uZrawuaYIqV-7PcSjscTPU8fzsjiAPt1dTsQ4px-6TcFHapfxiNsI-Dbfkv1TGhnjDYd1G3Lw2mGVfmE19MKsT-XU7kIb6a1qLr7GqlTuPvvxpnBtBi0OBeW_s1hmHxiSSmSQUW0A9pcfgmipvPB_dOm30NtffOkb73NCvKZdRlCkJlThna3A3iLt0Fdxiz6ThEGO3T7m6zVfw--Z9bLAEaeD5NHbFOuUrt7fLZQegb_LrSmqhshjsquDRhLu80jpUuSVq8BQ3VoWn7YRUyMb-fo8qucEcXtihVaIKDwBxWrlWpDJrgiON6Y7IqmOu7tKD2D5QvaYkrIzyo79HASiM_4MCUBg_UKyCMjXqKggseJdpz-Qr6Xk9LgdYZfSAfl1pz7aa8agUOegtOYAMk4srck6DKuRDBk5BbRsaB424iqtCwI3JoUrjsWeJEVXj6AqZ8ZC5Ea8kkdj6rm_Qxiu5S4juGSteye8lG0ms-i2nMn6X7Y4sv5L8qCg_4N_K9p6vwwhs36SE_WclwN95fuf4A3LBO3Z9U4Azu38mLAnZfcxtZ4ekIg-ZIVJEE4i44TVtbhP1HLKsuFbeV2PaiBz-IMXBr5FFk8uhIbVU-7fSg4-1n08e4zB_TbnFjOg70T4nzPIDUsItqfuRlO_1lzJQoRwthvWEGVzFDYBcXGIOsnByJhRuF9jHfdygxlbrElfkjZ_v50Q7yixpZa-Y_aVi-ut4_ypc8FGuY068kRxg_txo0I7kRZvwsARUjihirrTjEh5oV6LwLnFUT7nxIwv_Nt3BP0tI-dnyax5Pdy4eKV7ONh64SyRs0uaeZbQa44hW3hBsD_09C1cuk6mnbj1pIxqpIsS5f5oIJyxAI5FlnGH2eWiRMkb_ZMhCVepnREc2B_TUfFX3j9hfYzILcqNmvn1A3J03Nqe2ZLAETGKIh3vzIKPM0KeMz7usccpZlSZYZEY9xhHa4ciZkcFKmmyF6aHHDMDWnZHAGpB66hF7evQF8RpH8N0AefSILjXIhDr-VA08oI8pN9Sw_J4LwRRH5mNOut08_h7D9o3U8zwFhPXdvOhrDxWcPwzV-kD7A333xpiEFHcJFxxAxNPT7jDho3XFyvtNjz074pzAZ8WdbyhSduqLYmUAqdBkaBoH8v0GnVOvSFgNHEfXeo2FzrVXnPnZ0Hor2E7aGkoHQ2K3miJDxWG0AWiV5MgFCmQp85UAsWkjCDkpbRKSB2XpvnkPLZ-X67RGDA7RBbpar_az4zXQ-v36R977Wg0V-OP6Qm4vluTikIQhZDwhswmklDo63h2tG3EE8aRtoWzOJ0kDXG-54BqXsp-EeRuHjiKR0-Qe61_7hSrtT73qvL1PaTKQHXo30qTi8A1d3G3mrSX5pubCKREZlaxEeZF0qnqe3Gq0mmcvvB763tW0W69v-s-RDqpRgZnLY1x4BMViY3G8gDiW3cTRsolW2uc0MOVLyz_fal5dtTiSq7TstR2f2eNmoWKwQVmIxW25t-zzywnrqrEbO_VsuJd1bWtQ1vTyKWg3ngtbQfl80c8Xd0wydeAbqJRPVxcMHty3SBcuQd0vfX_h9ofRwuYUcmWwGJJ8SL7mJRwCzcebvLt5SqHwT_LGzgaxZ3aFBBzm5Ww_7faNib7K_nR4sXH7ujkdrPPlZSva8pNYtf1zPY0o6XtJv52T6LwNfIlbdkJvSQxA-XNVOzJ7Vlipvh6Dk_2UC0vmcxS3tiN9-QLmC62G1J-X298BCSOhiw== \ No newline at end of file
diff --git a/examples/pki/cms/auth_v3_token_scoped.pkiz b/examples/pki/cms/auth_v3_token_scoped.pkiz
new file mode 100644
index 0000000..d687c03
--- /dev/null
+++ b/examples/pki/cms/auth_v3_token_scoped.pkiz
@@ -0,0 +1 @@
+PKIZ_eJy9V8lyo0gQvddXzN3RYUCgNoc-FItYTCGBEEvdWCwWscjWwvL1UyDJ3W577J6YiFGEDlUFmS_zvcxKvn0jP0FWNPMvEa3HxTeANE1X2kB_bLCWnWMTWrHYkD1JEkXRSkVoyZ3oQFVINy9SikSlEEWhTxVx_aystWgGJEtWYUg2u52cprH71OtUxBzLKNfmmnrIY1U_h5VbJOJljRX-GHjlSSualDx7AoFHl-NCq-xz5C32Ucmfxj201g6aqO_x-KKo7yKGzkKP24ae1Wk1NZ6VUbXIQaS4u9FAouo0XrfEEJdF3iZf5jBPFJcY4yifmfY6LR_P7TJmzD70BSr0-BMYX45q9xCJ42E5GdNqe7R-Shb8Hktyvh0N1_qZOBvGc292yMn5Ea-1OSBQ-ojpCGSdN0Th-68I4oo_YEfLt-4E-Yh9u4kY-2Kk19vANweQMHyPRT0xRJhjP2tDXy9jms-mpIlajyTEGg7sDEdmXUnrloVMLQs48_IpRwUIfDuLFL7-HRo5ZAgyekQzGfe4Xazw-6i2X8NIfP0ALgxkVKLCudE_dKiIT0hkW6OQ50spnpk5z6D1A2MqGoMLswoqszAdRKHBLZeKzACk4AIXKRdUGmMW8iy40kc8lXGFs4C55CPw7GPosROauHLrkYHROSDZLTFTnqMdf8K3RNZuH134bxLVbpf5wxk52swo4IiO5CGdmUNwTgr5DMzCzgmwAVd6EQybwZQQjZ0sMwuhCpiAXXp6bhZBZzLy5J2IicK-XgWeWV4QVOWJCKYnyTtMQrkhyicEPfaSfcRwq6jaTHog8qXjqp3CClWbArHUnI1B7s1-TByB6DSsOcSMMQs6YwiooMAVYnAeMIhGgzWY3oYNnKDFlVktpTIHQUGOnCS7yPSCBleL4kplm3j6IfTQu-TdkIJb8vxJrjYXK9c6ICpMxkIbC0d9o486UhankZ3RKPgngXyqD0fj0KQP7QD-DecfUQ6-5nzXE48j5_8fjRwiXkca_4QZ8FmMvzMTenSGmVckU-u7ViN3Tir507L9J1bAa9mKIy3sH6nvV_GBD2LMsELvo0vHuSaRvba4S7gOw70KDHwpmi_Qgc_gfYDuKjrSeMULQvAVxK8Qgv-SwBEh-Lfl-7tGwE0kAcMfY9Wl8AcXTMi4XDwjd2f1vsWDPy1hNPZLJyZFhd4UFbhVlVYtdtF4bb8vqPVnBQXGivqgoIg3RJs9SW7_8T1xRTDOB-37hJV_fleAn41j0yIJvovxNcRaoIOq2wf9W4mDEc7mjYDo6aZO1LK9qQ-TQSNRSurplT53wL5GQhlb2m20uc5Ev3Tf17Fm2nNuLc2acnCblYDPlLvLcAF_fZmOGbd_O9rcppfRu36dlWgebB1FhHHTpqmqwFQWkKbsyP8JWU0rwkByLWshtzKNrEMrWtNakVvd3QyygeBOAZDeyKKARIuSO7mAlpCargBjR3RNOqo4LiHNlsBfIwEq07MZ0p2ZUEalSZEEvwBky63UTpYNuc0M7JdDohD6HLlEInodKMk8qUM78H7K2oURMQSi-mLJqMisNMgbJGiTJ9ghY8O4B5wLTuglJ-xZIiTOhDZYPLasBLOmlaxABz9HXFkQLEimVRnmJ3OlLmcvbKSdqMYrmzCrm95WXJ12CpbiH4Ln1O5ZzC2aZ6DndyU-zU7DXS1QL_Ndjdd-JsAIqbs9v3To5N5fB9zLshOf-uql6beRHX3H4Xy_hxWW6AqsHh-d7_NktVXtxxXTR2yhoe3cWAcs_bxqnxTBqRUha-onmROWuZpIXC05Em0v1vaB1bI50P2ZKjyrfXi33B4XFO47K4lXsKyFx7vW2Id3ZyKK9OUQMH7ztHPNY-vcQ38ZZliW5ORlDQYlpPYnVmg1NNNgWvIzt33g7oXy0LVwkMU8rNSu3g6ORWFa9GAxHL1NWqSxkdqqeL4HK0GEBs73RVma-_uGClnlMehWZR49Gdvvq8UiiqvZ1jZ0-OMHmD4xZFP6-bnxN6RCLsw= \ No newline at end of file
diff --git a/examples/pki/cms/revocation_list.der b/examples/pki/cms/revocation_list.der
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/pki/cms/revocation_list.der
diff --git a/examples/pki/cms/revocation_list.json b/examples/pki/cms/revocation_list.json
index c3401b0..f8e734d 100644
--- a/examples/pki/cms/revocation_list.json
+++ b/examples/pki/cms/revocation_list.json
@@ -1 +1 @@
-{"revoked":[{"id":"7acfcfdaf6a14aebe97c61c5947bc4d3","expires":"2012-08-14T17:58:48Z"}]}
+{"revoked": [{"expires": "2112-08-14T17:58:48Z", "id": "dc57ea171d2f93e4ff5fa01fe5711f2a"}, {"expires": "2112-08-14T17:58:48Z", "id": "4948fb46f88c41af90b65213a48baef7"}, {"expires": "2112-08-14T17:58:48Z", "id": "dc57ea171d2f93e4ff5fa01fe5711f2a"}, {"expires": "2112-08-14T17:58:48Z", "id": "4948fb46f88c41af90b65213a48baef7"}]} \ No newline at end of file
diff --git a/examples/pki/cms/revocation_list.pem b/examples/pki/cms/revocation_list.pem
index 4c6233e..d96cd5c 100644
--- a/examples/pki/cms/revocation_list.pem
+++ b/examples/pki/cms/revocation_list.pem
@@ -1,15 +1,20 @@
-----BEGIN CMS-----
-MIICWgYJKoZIhvcNAQcCoIICSzCCAkcCAQExCTAHBgUrDgMCGjBpBgkqhkiG9w0B
-BwGgXARaeyJyZXZva2VkIjpbeyJpZCI6IjdhY2ZjZmRhZjZhMTRhZWJlOTdjNjFj
-NTk0N2JjNGQzIiwiZXhwaXJlcyI6IjIwMTItMDgtMTRUMTc6NTg6NDhaIn1dfQ0K
-MYIByjCCAcYCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYD
-VQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sx
-ETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVu
-c3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkq
-hkiG9w0BAQEFAASCAQB8CHeQzIDFNy4RcWb+RRwwZ3JZ8Vw7OnFZhWXdbQ7a5KZr
-CrB/cGpkvMgnOtCNfpwSv7H97UEmOhQEarFJ6YFNNjA2FdXgt+2MCPmodG6tGyXl
-F+sh/g7qE8ONTiIJn2634kCj7fAyrVUlRxDLu6Llk9KWv7pAxtJKjqirHr8i8tYM
-/QV8pX/QP0u+vJvzZBXb/UlViQpaJnY9SWKF0ETXGypFTtExfiXG9qz96JWvC/jK
-gOF68N0FsoCNhzRys86rrAk7jZugajzjk3y/buInZiv4npQcEMC3lHKBXtA2uiRf
-ILgnF0qOttONx8GNE72eJqWBkiJf52239PxgxWNg
+MIIDTwYJKoZIhvcNAQcCoIIDQDCCAzwCAQExCTAHBgUrDgMCGjCCAVwGCSqGSIb3
+DQEHAaCCAU0EggFJeyJyZXZva2VkIjogW3siZXhwaXJlcyI6ICIyMTEyLTA4LTE0
+VDE3OjU4OjQ4WiIsICJpZCI6ICJkYzU3ZWExNzFkMmY5M2U0ZmY1ZmEwMWZlNTcx
+MWYyYSJ9LCB7ImV4cGlyZXMiOiAiMjExMi0wOC0xNFQxNzo1ODo0OFoiLCAiaWQi
+OiAiNDk0OGZiNDZmODhjNDFhZjkwYjY1MjEzYTQ4YmFlZjcifSwgeyJleHBpcmVz
+IjogIjIxMTItMDgtMTRUMTc6NTg6NDhaIiwgImlkIjogImRjNTdlYTE3MWQyZjkz
+ZTRmZjVmYTAxZmU1NzExZjJhIn0sIHsiZXhwaXJlcyI6ICIyMTEyLTA4LTE0VDE3
+OjU4OjQ4WiIsICJpZCI6ICI0OTQ4ZmI0NmY4OGM0MWFmOTBiNjUyMTNhNDhiYWVm
+NyJ9XX0xggHKMIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5T
+dGFjazERMA8GA1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25l
+QG9wZW5zdGFjay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIa
+MA0GCSqGSIb3DQEBAQUABIIBAI2tvOIhjQTThmRwK4wp+KeZOU6hKk2A5j5c+XNZ
+DxwLlvuX+YZxm5OpLdInKTjMvjMi6guciwH3VUAo2Iqq9yMhH/Xh5t8QJS+zPF7i
++GOqwZpBc6QKNihIok09L4jtaUjf4/f7EZQNh/jMkftuA3hhtuLalnkYW7yEA2sF
+ne7PRVUV6i8i+q7gC5L9iXk4Qy3p2AzgPGfhF6PM/0pzyjJtk6v8PBCkMBNexrkq
+RS4WjsYMR3mev1jL3dJ0wTgCgnqCcR3bQtDL/MHpU6q6Ce6Q3DGE6hkQOIRHenE/
+NoPZqDY/M34NHbjsMqi4zJkO4HMrcgAiYa/zX/yBwzvEurI=
-----END CMS-----
diff --git a/examples/pki/cms/revocation_list.pkiz b/examples/pki/cms/revocation_list.pkiz
new file mode 100644
index 0000000..600fce0
--- /dev/null
+++ b/examples/pki/cms/revocation_list.pkiz
@@ -0,0 +1 @@
+PKIZ_eJx9VEuPszgQvPMr9h6NQgIhk8N3MMaACTaBmJdvCZMxGMhjkgmPX79kRtq9rNYXq0ul6u7qVr-9Tc9EDqZ_QbJ_BW8KwdhiXe5tLxyXz4KCsICXCQstCMHYQRCiHjLgmiL-sgSBjpzwpHPg_ubs8VFTrBC54DCBsYqEsL3T4A0848_DMqmxvIhUu1c8K7tD5jXFgA0M8UAYGnwGdJ8hVUkspAUy1gMZ6mmF7xh6Vw5fRK_Ox1jjKerpaNekzVdkGau8zRe8RR1JeUNZ0SskzYd87218aK5xm-iF00wVkCqoQEUk6kmldgFUe2qHk9BlEVgXNbAvlQ9BdUjDSnkRqVWrgcOnn7eBVUpq2SWXdZfLfDGJjDkL9by1Gy6L6nPfianN5uSa16JNRuXVJ5a4Jww_iCUehEUxYYVBmTCoVR5w1QncNj9-4DaSlH00OUMaScNhSjIqnEUtl0mbM9DzNl7QEfVceiU-q3fs_r-BL_-U_zYQq8FUNm-xSttcDxyiktRuA2ZWVMaTCC2n6qo8TVqFDt4my9ReCHc77YTZC2wCBs2rBc2zRFsChAMWMTIjYlKGfALq37gkMElIr8AReKagiQkEAzU1SYQ7BHIrCUMXdQ37SFffp4yXRyfukQThL_fCYLzpeLpiyodjy8OIIgLef5RhT_B-mawKLXoe27j3GJCmqG9lXTmbTjVhiKZmHs0po-pxuWqU0PlRGn-EhtWzaIvetsD-NxNhcEGbo5OLeNmcj21SA_FKVjjm_h6ADh8UAtR_9npaaxOEMTAnLwBePp4BLmXIWNlG3VbvrrPtiQexUW7rJVjJVTHLKFesvvOb53c2y3nfroKr_4HPWybJU5LKEN9F1blaEoPLEt9um4GU7jwrV4_30NvPxp29rpSZE9w6fjULI9zSqsSXWt34unwcYvmpzz_XiIe0nEtSfz6-gVaWj2__0JzrPF0PCCzvtnI-rXdREidG9V7NbmsBV_6mymo9HLTrEoxi53yWtrEjc_U6DtJ71MbzfWfCehrqqf-qb0q011N5z0mktafnQvrah6d2TEBxvsEi0o7hw_LnxL3Gxs2AJyPULAcZZR0GOHJPZzRX6GXHb1Y-J5pO3aO8k1ulj14d6C75KgSo8sN8zOaD2Y1P9P2F_yg_dwhR69-b9Dc2l4GQ \ No newline at end of file
diff --git a/examples/pki/gen_cmsz.py b/examples/pki/gen_cmsz.py
new file mode 100644
index 0000000..6840c08
--- /dev/null
+++ b/examples/pki/gen_cmsz.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+
+# 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.
+
+import json
+import os
+
+from keystoneclient.common import cms
+from keystoneclient import utils
+
+CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
+
+
+def make_filename(*args):
+ return os.path.join(CURRENT_DIR, *args)
+
+
+def generate_revocation_list():
+ REVOKED_TOKENS = ['auth_token_revoked', 'auth_v3_token_revoked']
+ revoked_list = []
+ for token in REVOKED_TOKENS:
+ with open(make_filename('cms', '%s.pkiz' % name), 'r') as f:
+ token_data = f.read()
+ id = utils.hash_signed_token(token_data.encode('utf-8'))
+ revoked_list.append({
+ 'id': id,
+ "expires": "2112-08-14T17:58:48Z"
+ })
+ with open(make_filename('cms', '%s.pem' % name), 'r') as f:
+ pem_data = f.read()
+ token_data = cms.cms_to_token(pem_data).encode('utf-8')
+ id = utils.hash_signed_token(token_data)
+ revoked_list.append({
+ 'id': id,
+ "expires": "2112-08-14T17:58:48Z"
+ })
+ revoked_json = json.dumps({"revoked": revoked_list})
+ with open(make_filename('cms', 'revocation_list.json'), 'w') as f:
+ f.write(revoked_json)
+ encoded = cms.pkiz_sign(revoked_json,
+ SIGNING_CERT_FILE_NAME,
+ SIGNING_KEY_FILE_NAME)
+ with open(make_filename('cms', 'revocation_list.pkiz'), 'w') as f:
+ f.write(encoded)
+
+ encoded = cms.cms_sign_data(revoked_json,
+ SIGNING_CERT_FILE_NAME,
+ SIGNING_KEY_FILE_NAME)
+ with open(make_filename('cms', 'revocation_list.pem'), 'w') as f:
+ f.write(encoded)
+
+
+CA_CERT_FILE_NAME = make_filename('certs', 'cacert.pem')
+SIGNING_CERT_FILE_NAME = make_filename('certs', 'signing_cert.pem')
+SIGNING_KEY_FILE_NAME = make_filename('private', 'signing_key.pem')
+EXAMPLE_TOKENS = ['auth_token_revoked',
+ 'auth_token_unscoped',
+ 'auth_token_scoped',
+ 'auth_token_scoped_expired',
+ 'auth_v3_token_scoped',
+ 'auth_v3_token_revoked']
+
+
+# Helper script to generate the sample data for testing
+# the signed tokens using the existing JSON data for the
+# MII-prefixed tokens. Uses the keys and certificates
+# generated in gen_pki.sh.
+def generate_der_form(name):
+ derfile = make_filename('cms', '%s.der' % name)
+ with open(derfile, 'w') as f:
+ derform = cms.cms_sign_data(text,
+ SIGNING_CERT_FILE_NAME,
+ SIGNING_KEY_FILE_NAME, cms.PKIZ_CMS_FORM)
+ f.write(derform)
+
+for name in EXAMPLE_TOKENS:
+ json_file = make_filename('cms', name + '.json')
+ pkiz_file = make_filename('cms', name + '.pkiz')
+ with open(json_file, 'r') as f:
+ string_data = f.read()
+
+ # validate the JSON
+ try:
+ token_data = json.loads(string_data)
+ except ValueError as v:
+ raise SystemExit('%s while processing token data from %s: %s' %
+ (v, json_file, string_data))
+
+ text = json.dumps(token_data).encode('utf-8')
+
+ # Uncomment to record the token uncompressed,
+ # useful for debugging
+ # generate_der_form(name)
+
+ encoded = cms.pkiz_sign(text,
+ SIGNING_CERT_FILE_NAME,
+ SIGNING_KEY_FILE_NAME)
+
+ # verify before writing
+ cms.pkiz_verify(encoded,
+ SIGNING_CERT_FILE_NAME,
+ CA_CERT_FILE_NAME)
+
+ with open(pkiz_file, 'w') as f:
+ f.write(encoded)
+
+ generate_revocation_list()
diff --git a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py
index 96f8b61..156b1a1 100644
--- a/keystoneclient/common/cms.py
+++ b/keystoneclient/common/cms.py
@@ -19,9 +19,12 @@ 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 base64
import errno
import hashlib
import logging
+import zlib
+
import six
from keystoneclient import exceptions
@@ -30,6 +33,9 @@ from keystoneclient import exceptions
subprocess = None
LOG = logging.getLogger(__name__)
PKI_ASN1_PREFIX = 'MII'
+PKIZ_PREFIX = 'PKIZ_'
+PKIZ_CMS_FORM = 'DER'
+PKI_ASN1_FORM = 'PEM'
def _ensure_subprocess():
@@ -99,14 +105,30 @@ def _process_communicate_handle_oserror(process, data, files):
return output, err, retcode
-def cms_verify(formatted, signing_cert_file_name, ca_file_name):
+def _encoding_for_form(inform):
+ if inform == PKI_ASN1_FORM:
+ encoding = 'UTF-8'
+ elif inform == PKIZ_CMS_FORM:
+ encoding = 'hex'
+ else:
+ raise ValueError('"inform" must be either %s or %s' %
+ (PKI_ASN1_FORM, PKIZ_CMS_FORM))
+
+ return encoding
+
+
+def cms_verify(formatted, signing_cert_file_name, ca_file_name,
+ inform=PKI_ASN1_FORM):
"""Verifies the signature of the contents IAW CMS syntax.
:raises: subprocess.CalledProcessError
:raises: CertificateConfigError if certificate is not configured properly.
"""
_ensure_subprocess()
- data = bytearray(formatted, encoding='utf-8')
+ if isinstance(formatted, six.string_types):
+ data = bytearray(formatted, _encoding_for_form(inform))
+ else:
+ data = formatted
process = subprocess.Popen(['openssl', 'cms', '-verify',
'-certfile', signing_cert_file_name,
'-CAfile', ca_file_name,
@@ -133,7 +155,10 @@ def cms_verify(formatted, signing_cert_file_name, ca_file_name):
# Error opening certificate file not_exist_file
#
if retcode == 2:
- raise exceptions.CertificateConfigError(err)
+ if err.startswith('Error reading S/MIME message'):
+ raise exceptions.CMSError(err)
+ else:
+ raise exceptions.CertificateConfigError(err)
elif retcode:
# NOTE(dmllr): Python 2.6 compatibility:
# CalledProcessError did not have output keyword argument
@@ -143,6 +168,45 @@ def cms_verify(formatted, signing_cert_file_name, ca_file_name):
return output
+def is_pkiz(token_text):
+ """Determine if a token a cmsz token
+
+ Checks if the string has the prefix that indicates it is a
+ Crypto Message Syntax, Z compressed token.
+ """
+ return token_text.startswith(PKIZ_PREFIX)
+
+
+def pkiz_sign(text,
+ signing_cert_file_name,
+ signing_key_file_name,
+ compression_level=6):
+ signed = cms_sign_data(text,
+ signing_cert_file_name,
+ signing_key_file_name,
+ PKIZ_CMS_FORM)
+
+ compressed = zlib.compress(signed, compression_level)
+ encoded = PKIZ_PREFIX + base64.urlsafe_b64encode(
+ compressed).decode('utf-8')
+ return encoded
+
+
+def pkiz_uncompress(signed_text):
+ text = signed_text[len(PKIZ_PREFIX):].encode('utf-8')
+ unencoded = base64.urlsafe_b64decode(text)
+ uncompressed = zlib.decompress(unencoded)
+ return uncompressed
+
+
+def pkiz_verify(signed_text, signing_cert_file_name, ca_file_name):
+ uncompressed = pkiz_uncompress(signed_text)
+ return cms_verify(uncompressed, signing_cert_file_name, ca_file_name,
+ inform=PKIZ_CMS_FORM)
+
+
+# This function is deprecated and will be removed once the ASN1 token format
+# is no longer required. It is only here to be used for testing.
def token_to_cms(signed_text):
copy_of_text = signed_text.replace('-', '/')
@@ -225,14 +289,33 @@ def is_ans1_token(token):
return is_asn1_token(token)
-def cms_sign_text(text, signing_cert_file_name, signing_key_file_name):
+def cms_sign_text(data_to_sign, signing_cert_file_name, signing_key_file_name):
+ return cms_sign_data(data_to_sign, signing_cert_file_name,
+ signing_key_file_name)
+
+
+def cms_sign_data(data_to_sign, signing_cert_file_name, signing_key_file_name,
+ outform=PKI_ASN1_FORM):
"""Uses OpenSSL to sign a document.
Produces a Base64 encoding of a DER formatted CMS Document
http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax
+
+ :param data_to_sign: data to sign
+ :param signing_cert_file_name: path to the X509 certificate containing
+ the public key associated with the private key used to sign the data
+ :param signing_key_file_name: path to the private key used to sign
+ the data
+ :param outform: Format for the signed document PKIZ_CMS_FORM or
+ PKI_ASN1_FORM
+
+
"""
_ensure_subprocess()
- data = bytearray(text, encoding='utf-8')
+ if isinstance(data_to_sign, six.string_types):
+ data = bytearray(data_to_sign, encoding='utf-8')
+ else:
+ data = data_to_sign
process = subprocess.Popen(['openssl', 'cms', '-sign',
'-signer', signing_cert_file_name,
'-inkey', signing_key_file_name,
@@ -248,12 +331,21 @@ def cms_sign_text(text, signing_cert_file_name, signing_key_file_name):
if retcode or ('Error' in err):
LOG.error('Signing error: %s' % err)
+ if retcode == 3:
+ LOG.error('Signing error: Unable to load certificate - '
+ 'ensure you have configured PKI with '
+ '"keystone-manage pki_setup"')
+ else:
+ LOG.error('Signing error: %s', err)
raise subprocess.CalledProcessError(retcode, 'openssl')
- return output.decode('utf-8')
+ if outform == PKI_ASN1_FORM:
+ return output.decode('utf-8')
+ else:
+ return output
def cms_sign_token(text, signing_cert_file_name, signing_key_file_name):
- output = cms_sign_text(text, signing_cert_file_name, signing_key_file_name)
+ output = cms_sign_data(text, signing_cert_file_name, signing_key_file_name)
return cms_to_token(output)
@@ -273,12 +365,12 @@ def cms_to_token(cms_text):
def cms_hash_token(token_id, mode='md5'):
"""Hash PKI tokens.
- return: for asn1_token, returns the hash of the passed in token
+ return: for asn1 or pkiz tokens, returns the hash of the passed in token
otherwise, returns what it was passed in.
"""
if token_id is None:
return None
- if is_asn1_token(token_id):
+ if is_asn1_token(token_id) or is_pkiz(token_id):
hasher = hashlib.new(mode)
if isinstance(token_id, six.text_type):
token_id = token_id.encode('utf-8')
diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py
index 4572af9..31f25cb 100644
--- a/keystoneclient/exceptions.py
+++ b/keystoneclient/exceptions.py
@@ -37,6 +37,14 @@ class CertificateConfigError(Exception):
super(CertificateConfigError, self).__init__(msg)
+class CMSError(Exception):
+ """Error reading the certificate"""
+ def __init__(self, output):
+ self.output = output
+ msg = ("Unable to sign or verify data.")
+ super(CMSError, self).__init__(msg)
+
+
class EmptyCatalog(EndpointNotFound):
"""The service catalog is empty."""
pass
diff --git a/keystoneclient/middleware/auth_token.py b/keystoneclient/middleware/auth_token.py
index 637b3b2..f11a260 100644
--- a/keystoneclient/middleware/auth_token.py
+++ b/keystoneclient/middleware/auth_token.py
@@ -875,7 +875,9 @@ class AuthProtocol(object):
'Token is marked as having been revoked')
raise InvalidUserToken(
'Token authorization failed')
-
+ elif cms.is_pkiz(user_token):
+ verified = self.verify_pkiz_token(user_token)
+ data = jsonutils.loads(verified)
elif cms.is_asn1_token(user_token):
verified = self.verify_signed_token(user_token)
data = jsonutils.loads(verified)
@@ -1228,7 +1230,7 @@ class AuthProtocol(object):
revoked_ids = (x['id'] for x in revoked_tokens)
return token_id in revoked_ids
- def cms_verify(self, data):
+ def cms_verify(self, data, inform=cms.PKI_ASN1_FORM):
"""Verifies the signature of the provided data's IAW CMS syntax.
If either of the certificate files might be missing, fetch them and
@@ -1236,9 +1238,9 @@ class AuthProtocol(object):
"""
def verify():
try:
- return cms.cms_verify(
- data, self.signing_cert_file_name,
- self.signing_ca_file_name).decode('utf-8')
+ return cms.cms_verify(data, self.signing_cert_file_name,
+ self.signing_ca_file_name,
+ inform=inform).decode('utf-8')
except cms.subprocess.CalledProcessError as err:
self.LOG.warning('Verify error: %s', err)
raise
@@ -1265,7 +1267,19 @@ class AuthProtocol(object):
raise InvalidUserToken('Token has been revoked')
formatted = cms.token_to_cms(signed_text)
- return self.cms_verify(formatted)
+ verified = self.cms_verify(formatted)
+ return verified
+
+ def verify_pkiz_token(self, signed_text):
+ if self.is_signed_token_revoked(signed_text):
+ raise InvalidUserToken('Token has been revoked')
+ try:
+ uncompressed = cms.pkiz_uncompress(signed_text)
+ verified = self.cms_verify(uncompressed, inform=cms.PKIZ_CMS_FORM)
+ return verified
+ # TypeError If the signed_text is not zlib compressed
+ except TypeError:
+ raise InvalidUserToken(signed_text)
def verify_signing_dir(self):
if os.path.exists(self.signing_dirname):
diff --git a/keystoneclient/tests/client_fixtures.py b/keystoneclient/tests/client_fixtures.py
index 6aabd99..f090db0 100644
--- a/keystoneclient/tests/client_fixtures.py
+++ b/keystoneclient/tests/client_fixtures.py
@@ -53,6 +53,8 @@ class Examples(fixtures.Fixture):
# files in the signing subdirectory. In order to keep the values
# consistent between the tests and the signed documents, we read them
# in for use in the tests.
+ with open(os.path.join(CMSDIR, 'auth_token_scoped.json')) as f:
+ self.TOKEN_SCOPED_DATA = cms.cms_to_token(f.read())
with open(os.path.join(CMSDIR, 'auth_token_scoped.pem')) as f:
self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read())
@@ -66,6 +68,19 @@ class Examples(fixtures.Fixture):
self.SIGNED_TOKEN_SCOPED_EXPIRED = cms.cms_to_token(f.read())
with open(os.path.join(CMSDIR, 'auth_v3_token_revoked.pem')) as f:
self.REVOKED_v3_TOKEN = cms.cms_to_token(f.read())
+ with open(os.path.join(CMSDIR, 'auth_token_scoped.pkiz')) as f:
+ self.SIGNED_TOKEN_SCOPED_PKIZ = cms.cms_to_token(f.read())
+ with open(os.path.join(CMSDIR, 'auth_token_unscoped.pkiz')) as f:
+ self.SIGNED_TOKEN_UNSCOPED_PKIZ = cms.cms_to_token(f.read())
+ with open(os.path.join(CMSDIR, 'auth_v3_token_scoped.pkiz')) as f:
+ self.SIGNED_v3_TOKEN_SCOPED_PKIZ = cms.cms_to_token(f.read())
+ with open(os.path.join(CMSDIR, 'auth_token_revoked.pkiz')) as f:
+ self.REVOKED_TOKEN_PKIZ = cms.cms_to_token(f.read())
+ with open(os.path.join(CMSDIR,
+ 'auth_token_scoped_expired.pkiz')) as f:
+ self.SIGNED_TOKEN_SCOPED_EXPIRED_PKIZ = cms.cms_to_token(f.read())
+ with open(os.path.join(CMSDIR, 'auth_v3_token_revoked.pkiz')) as f:
+ self.REVOKED_v3_TOKEN_PKIZ = cms.cms_to_token(f.read())
with open(os.path.join(CMSDIR, 'revocation_list.json')) as f:
self.REVOCATION_LIST = jsonutils.loads(f.read())
with open(os.path.join(CMSDIR, 'revocation_list.pem')) as f:
@@ -116,6 +131,26 @@ class Examples(fixtures.Fixture):
self.REVOKED_v3_TOKEN_LIST_JSON = jsonutils.dumps(
self.REVOKED_v3_TOKEN_LIST)
+ revoked_token_pkiz = self.REVOKED_TOKEN_PKIZ
+ if isinstance(revoked_token_pkiz, six.text_type):
+ revoked_token_pkiz = revoked_token_pkiz.encode('utf-8')
+ self.REVOKED_TOKEN_PKIZ_HASH = utils.hash_signed_token(
+ revoked_token_pkiz)
+ revoked_v3_token_pkiz = self.REVOKED_v3_TOKEN_PKIZ
+ if isinstance(revoked_v3_token_pkiz, six.text_type):
+ revoked_v3_token_pkiz = revoked_v3_token_pkiz.encode('utf-8')
+ self.REVOKED_v3_PKIZ_TOKEN_HASH = utils.hash_signed_token(
+ revoked_v3_token_pkiz)
+
+ self.REVOKED_TOKEN_PKIZ_LIST = (
+ {'revoked': [{'id': self.REVOKED_TOKEN_PKIZ_HASH,
+ 'expires': timeutils.utcnow()},
+ {'id': self.REVOKED_v3_PKIZ_TOKEN_HASH,
+ 'expires': timeutils.utcnow()},
+ ]})
+ self.REVOKED_TOKEN_PKIZ_LIST_JSON = jsonutils.dumps(
+ self.REVOKED_TOKEN_PKIZ_LIST)
+
self.SIGNED_TOKEN_SCOPED_KEY = cms.cms_hash_token(
self.SIGNED_TOKEN_SCOPED)
self.SIGNED_TOKEN_UNSCOPED_KEY = cms.cms_hash_token(
@@ -123,6 +158,13 @@ class Examples(fixtures.Fixture):
self.SIGNED_v3_TOKEN_SCOPED_KEY = cms.cms_hash_token(
self.SIGNED_v3_TOKEN_SCOPED)
+ self.SIGNED_TOKEN_SCOPED_PKIZ_KEY = cms.cms_hash_token(
+ self.SIGNED_TOKEN_SCOPED_PKIZ)
+ self.SIGNED_TOKEN_UNSCOPED_PKIZ_KEY = cms.cms_hash_token(
+ self.SIGNED_TOKEN_UNSCOPED_PKIZ)
+ self.SIGNED_v3_TOKEN_SCOPED_PKIZ_KEY = cms.cms_hash_token(
+ self.SIGNED_v3_TOKEN_SCOPED_PKIZ)
+
self.INVALID_SIGNED_TOKEN = (
"MIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
@@ -142,6 +184,25 @@ class Examples(fixtures.Fixture):
"9999999999999999999999999999999999999999999999999999999999999999"
"0000000000000000000000000000000000000000000000000000000000000000")
+ self.INVALID_SIGNED_PKIZ_TOKEN = (
+ "PKIZ_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
+ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
+ "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "2222222222222222222222222222222222222222222222222222222222222222"
+ "3333333333333333333333333333333333333333333333333333333333333333"
+ "4444444444444444444444444444444444444444444444444444444444444444"
+ "5555555555555555555555555555555555555555555555555555555555555555"
+ "6666666666666666666666666666666666666666666666666666666666666666"
+ "7777777777777777777777777777777777777777777777777777777777777777"
+ "8888888888888888888888888888888888888888888888888888888888888888"
+ "9999999999999999999999999999999999999999999999999999999999999999"
+ "0000000000000000000000000000000000000000000000000000000000000000")
+
# JSON responses keyed by token ID
self.TOKEN_RESPONSES = {
self.UUID_TOKEN_DEFAULT: {
@@ -444,6 +505,12 @@ class Examples(fixtures.Fixture):
}
},
}
+ self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_PKIZ_KEY] = (
+ self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY])
+ self.TOKEN_RESPONSES[self.SIGNED_TOKEN_UNSCOPED_PKIZ_KEY] = (
+ self.TOKEN_RESPONSES[self.SIGNED_TOKEN_UNSCOPED_KEY])
+ self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_PKIZ_KEY] = (
+ self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_KEY])
self.JSON_TOKEN_RESPONSES = dict([(k, jsonutils.dumps(v)) for k, v in
six.iteritems(self.TOKEN_RESPONSES)])
diff --git a/keystoneclient/tests/test_auth_token_middleware.py b/keystoneclient/tests/test_auth_token_middleware.py
index b14917d..6b81f23 100644
--- a/keystoneclient/tests/test_auth_token_middleware.py
+++ b/keystoneclient/tests/test_auth_token_middleware.py
@@ -14,6 +14,7 @@
import calendar
import datetime
+import json
import os
import shutil
import stat
@@ -532,6 +533,12 @@ class CommonAuthTokenMiddlewareTest(object):
#ensure that signed requests do not generate HTTP traffic
self.assertLastPath(None)
+ def test_valid_signed_compressed_request(self):
+ self.assert_valid_request_200(
+ self.token_dict['signed_token_scoped_pkiz'])
+ # ensure that signed requests do not generate HTTP traffic
+ self.assertLastPath(None)
+
def test_revoked_token_receives_401(self):
self.middleware.token_revocation_list = self.get_revocation_list_json()
req = webob.Request.blank('/')
@@ -572,10 +579,27 @@ class CommonAuthTokenMiddlewareTest(object):
self.middleware.verify_signed_token,
self.token_dict['revoked_token'])
+ def test_verify_signed_token_raises_exception_for_revoked_pkiz_token(self):
+ self.middleware.token_revocation_list = (
+ self.examples.REVOKED_TOKEN_PKIZ_LIST_JSON)
+ self.assertRaises(auth_token.InvalidUserToken,
+ self.middleware.verify_pkiz_token,
+ self.token_dict['revoked_token_pkiz'])
+
+ def assertIsValidJSON(self, text):
+ json.loads(text)
+
def test_verify_signed_token_succeeds_for_unrevoked_token(self):
self.middleware.token_revocation_list = self.get_revocation_list_json()
- self.middleware.verify_signed_token(
+ text = self.middleware.verify_signed_token(
self.token_dict['signed_token_scoped'])
+ self.assertIsValidJSON(text)
+
+ def test_verify_signed_compressed_token_succeeds_for_unrevoked_token(self):
+ self.middleware.token_revocation_list = self.get_revocation_list_json()
+ text = self.middleware.verify_pkiz_token(
+ self.token_dict['signed_token_scoped_pkiz'])
+ self.assertIsValidJSON(text)
def test_verify_signing_dir_create_while_missing(self):
tmp_name = uuid.uuid4().hex
@@ -671,9 +695,17 @@ class CommonAuthTokenMiddlewareTest(object):
req = webob.Request.blank('/')
req.headers['X-Auth-Token'] = self.examples.INVALID_SIGNED_TOKEN
self.middleware(req.environ, self.start_fake_response)
- self.assertEqual(self.response_status, 401)
- self.assertEqual(self.response_headers['WWW-Authenticate'],
- "Keystone uri='https://keystone.example.com:1234'")
+ self.assertEqual(401, self.response_status)
+ self.assertEqual("Keystone uri='https://keystone.example.com:1234'",
+ self.response_headers['WWW-Authenticate'])
+
+ def test_request_invalid_signed_pkiz_token(self):
+ req = webob.Request.blank('/')
+ req.headers['X-Auth-Token'] = self.examples.INVALID_SIGNED_PKIZ_TOKEN
+ self.middleware(req.environ, self.start_fake_response)
+ self.assertEqual(401, self.response_status)
+ self.assertEqual("Keystone uri='https://keystone.example.com:1234'",
+ self.response_headers['WWW-Authenticate'])
def test_request_no_token(self):
req = webob.Request.blank('/')
@@ -1293,9 +1325,11 @@ class v2AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest,
'uuid_token_bind': self.examples.UUID_TOKEN_BIND,
'uuid_token_unknown_bind': self.examples.UUID_TOKEN_UNKNOWN_BIND,
'signed_token_scoped': self.examples.SIGNED_TOKEN_SCOPED,
+ 'signed_token_scoped_pkiz': self.examples.SIGNED_TOKEN_SCOPED_PKIZ,
'signed_token_scoped_expired':
self.examples.SIGNED_TOKEN_SCOPED_EXPIRED,
'revoked_token': self.examples.REVOKED_TOKEN,
+ 'revoked_token_pkiz': self.examples.REVOKED_TOKEN_PKIZ,
'revoked_token_hash': self.examples.REVOKED_TOKEN_HASH
}
@@ -1475,9 +1509,12 @@ class v3AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest,
'uuid_token_unknown_bind':
self.examples.v3_UUID_TOKEN_UNKNOWN_BIND,
'signed_token_scoped': self.examples.SIGNED_v3_TOKEN_SCOPED,
+ 'signed_token_scoped_pkiz':
+ self.examples.SIGNED_v3_TOKEN_SCOPED_PKIZ,
'signed_token_scoped_expired':
self.examples.SIGNED_TOKEN_SCOPED_EXPIRED,
'revoked_token': self.examples.REVOKED_v3_TOKEN,
+ 'revoked_token_pkiz': self.examples.REVOKED_v3_TOKEN_PKIZ,
'revoked_token_hash': self.examples.REVOKED_v3_TOKEN_HASH
}
diff --git a/keystoneclient/tests/test_cms.py b/keystoneclient/tests/test_cms.py
index 2f00522..43eba2b 100644
--- a/keystoneclient/tests/test_cms.py
+++ b/keystoneclient/tests/test_cms.py
@@ -36,7 +36,7 @@ class CMSTest(utils.TestCase, testresources.ResourcedTestCase):
'no_exist_cert_file',
'no_exist_ca_file')
- def test_token_to_cms_to_token(self):
+ def test_token_tocms_to_token(self):
with open(os.path.join(client_fixtures.CMSDIR,
'auth_token_scoped.pem')) as f:
AUTH_TOKEN_SCOPED_CMS = f.read()
@@ -55,14 +55,20 @@ class CMSTest(utils.TestCase, testresources.ResourcedTestCase):
def test_cms_sign_token_no_files(self):
self.assertRaises(subprocess.CalledProcessError,
cms.cms_sign_token,
- self.examples.SIGNED_TOKEN_SCOPED,
+ self.examples.TOKEN_SCOPED_DATA,
+ '/no/such/file', '/no/such/key')
+
+ def test_cms_sign_token_no_files_pkiz(self):
+ self.assertRaises(subprocess.CalledProcessError,
+ cms.pkiz_sign,
+ self.examples.TOKEN_SCOPED_DATA,
'/no/such/file', '/no/such/key')
def test_cms_sign_token_success(self):
self.assertTrue(
- cms.cms_sign_token(self.examples.SIGNED_TOKEN_SCOPED,
- self.examples.SIGNING_CERT_FILE,
- self.examples.SIGNING_KEY_FILE))
+ cms.pkiz_sign(self.examples.TOKEN_SCOPED_DATA,
+ self.examples.SIGNING_CERT_FILE,
+ self.examples.SIGNING_KEY_FILE))
def test_cms_verify_token_no_files(self):
self.assertRaises(exceptions.CertificateConfigError,