Remove support for PKI and PKIz tokens
This is the first step of several to remove PKI token support in keystone. A large issue in removing PKI support is support for the revocation list must be maintained. This patch removes support for the token format, it's surrounding tests and examples that are generated. Additionally, some wording has been changed around the CLI and config options to make the distinction between keys and certs used for PKI tokens and those used for getting the revocation list (a list of tokens that are revoked, which is signed). Future patches will: - Remove the keystone-manage commands for generating certs - Modify the revocation list (at /auth/tokens/OS-PKI/revoked) to return a 403 if pki is not configured (instead of raising a 500). We cannot remove the API as that would break an API contract. - Options to configure PKI will be marked as deprecated - If PKI is configured a normal signed list will be returned (same behavior as today) - Follow up patch to keystonemiddleware will make sure auth_token does not rely on the revocation api at all. Related-Bug: 1626778 Related-Bug: 1626779 Co-Authored-By: Boris Bobrov <bbobrov@mirantis.com> bp removed-as-of-ocata Change-Id: Icf1ebced44a675c88fb66a6c0431208ff5181574
This commit is contained in:
parent
748eb41904
commit
8a66ef6354
@ -437,8 +437,8 @@ configuring the following property.
|
|||||||
:class:`keystone.token.providers.uuid.Provider`
|
:class:`keystone.token.providers.uuid.Provider`
|
||||||
|
|
||||||
|
|
||||||
UUID, PKI, PKIZ, or Fernet?
|
UUID or Fernet?
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Each token format uses different technologies to achieve various performance,
|
Each token format uses different technologies to achieve various performance,
|
||||||
scaling and architectural requirements.
|
scaling and architectural requirements.
|
||||||
@ -449,29 +449,6 @@ transport and are thus URL-friendly. They must be persisted by the identity
|
|||||||
service in order to be later validated. Revoking them is simply a matter of
|
service in order to be later validated. Revoking them is simply a matter of
|
||||||
deleting them from the token persistence backend.
|
deleting them from the token persistence backend.
|
||||||
|
|
||||||
Both PKI and PKIZ tokens contain JSON payloads that represent the entire token
|
|
||||||
validation response that would normally be retrieved from keystone. The payload
|
|
||||||
is then signed using `Cryptographic Message Syntax (CMS)
|
|
||||||
<http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax>`_. The combination
|
|
||||||
of CMS and the exhaustive payload allows PKI and PKIZ tokens to be verified
|
|
||||||
offline using keystone's public signing key. The only reason for them to be
|
|
||||||
persisted by the identity service is to later build token revocation *lists*
|
|
||||||
(explicit lists of tokens that have been revoked), otherwise they are
|
|
||||||
theoretically ephemeral when supported by token revocation *events* (which
|
|
||||||
describe invalidated tokens rather than enumerate them). PKIZ tokens add zlib
|
|
||||||
compression after signing to achieve a smaller overall token size. To make them
|
|
||||||
URL-friendly, PKI tokens are base64 encoded and then arbitrarily manipulated to
|
|
||||||
replace unsafe characters with safe ones whereas PKIZ tokens use conventional
|
|
||||||
base64url encoding. Due to the size of the payload and the overhead incurred by
|
|
||||||
the CMS format, both PKI and PKIZ tokens may be too long to fit in either
|
|
||||||
headers or URLs if they contain extensive service catalogs or other additional
|
|
||||||
attributes. Some third-party applications such as web servers and clients may
|
|
||||||
need to be recompiled from source to customize the limitations that PKI and
|
|
||||||
PKIZ tokens would otherwise exceed). Both PKI and PKIZ tokens require signing
|
|
||||||
certificates which may be created using ``keystone-manage pki_setup`` for
|
|
||||||
demonstration purposes (this is not recommended for production deployments: use
|
|
||||||
certificates issued by an trusted CA instead).
|
|
||||||
|
|
||||||
Fernet tokens contain a limited amount of identity and authorization data in a
|
Fernet tokens contain a limited amount of identity and authorization data in a
|
||||||
`MessagePacked <http://msgpack.org/>`_ payload. The payload is then wrapped as
|
`MessagePacked <http://msgpack.org/>`_ payload. The payload is then wrapped as
|
||||||
a `Fernet <https://github.com/fernet/spec>`_ message for transport, where
|
a `Fernet <https://github.com/fernet/spec>`_ message for transport, where
|
||||||
@ -481,7 +458,7 @@ established using ``keystone-manage fernet_setup`` and periodically rotated
|
|||||||
using ``keystone-manage fernet_rotate``.
|
using ``keystone-manage fernet_rotate``.
|
||||||
|
|
||||||
.. WARNING::
|
.. WARNING::
|
||||||
UUID, PKI, PKIZ, and Fernet tokens are all bearer tokens, meaning that they
|
UUID and Fernet tokens are both bearer tokens, meaning that they
|
||||||
must be protected from unnecessary disclosure to prevent unauthorized
|
must be protected from unnecessary disclosure to prevent unauthorized
|
||||||
access.
|
access.
|
||||||
|
|
||||||
@ -1338,7 +1315,7 @@ through the normal REST API. At the moment, the following calls are supported:
|
|||||||
* ``mapping_engine``: Test your federation mapping rules.
|
* ``mapping_engine``: Test your federation mapping rules.
|
||||||
* ``mapping_populate``: Prepare domain-specific LDAP backend
|
* ``mapping_populate``: Prepare domain-specific LDAP backend
|
||||||
* ``mapping_purge``: Purge the identity mapping table.
|
* ``mapping_purge``: Purge the identity mapping table.
|
||||||
* ``pki_setup``: Initialize the certificates used to sign tokens.
|
* ``pki_setup``: Initialize the certificates used to sign revocation lists.
|
||||||
* ``saml_idp_metadata``: Generate identity provider metadata.
|
* ``saml_idp_metadata``: Generate identity provider metadata.
|
||||||
* ``token_flush``: Purge expired tokens
|
* ``token_flush``: Purge expired tokens
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ Available commands:
|
|||||||
* ``mapping_populate``: Prepare domain-specific LDAP backend.
|
* ``mapping_populate``: Prepare domain-specific LDAP backend.
|
||||||
* ``mapping_purge``: Purge the identity mapping table.
|
* ``mapping_purge``: Purge the identity mapping table.
|
||||||
* ``mapping_engine``: Test your federation mapping rules.
|
* ``mapping_engine``: Test your federation mapping rules.
|
||||||
* ``pki_setup``: Initialize the certificates used to sign tokens. **deprecated**
|
* ``pki_setup``: Initialize the certificates used to sign revocation lists. **deprecated**
|
||||||
* ``saml_idp_metadata``: Generate identity provider metadata.
|
* ``saml_idp_metadata``: Generate identity provider metadata.
|
||||||
* ``token_flush``: Purge expired tokens.
|
* ``token_flush``: Purge expired tokens.
|
||||||
|
|
||||||
|
@ -56,8 +56,6 @@
|
|||||||
# drivers should maintain their own equivalent document, and merge it with this
|
# drivers should maintain their own equivalent document, and merge it with this
|
||||||
# when their code merges into core.
|
# when their code merges into core.
|
||||||
driver-impl-uuid=UUID tokens
|
driver-impl-uuid=UUID tokens
|
||||||
driver-impl-pki=PKI tokens
|
|
||||||
driver-impl-pkiz=PKIZ tokens
|
|
||||||
driver-impl-fernet=Fernet tokens
|
driver-impl-fernet=Fernet tokens
|
||||||
|
|
||||||
[operation.create_unscoped_token]
|
[operation.create_unscoped_token]
|
||||||
@ -68,8 +66,6 @@ notes=All token providers must be capable of issuing tokens without an explicit
|
|||||||
cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
||||||
--os-password=<password> token issue
|
--os-password=<password> token issue
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[operation.create_project_scoped_token]
|
[operation.create_project_scoped_token]
|
||||||
@ -80,8 +76,6 @@ cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
|||||||
--os-password=<password> --os-project-name=<project>
|
--os-password=<password> --os-project-name=<project>
|
||||||
--os-project-domain-name=<domain> token issue
|
--os-project-domain-name=<domain> token issue
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[operation.create_domain_scoped_token]
|
[operation.create_domain_scoped_token]
|
||||||
@ -92,8 +86,6 @@ notes=Domain-scoped tokens are not required for all use cases, and for some use
|
|||||||
cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
||||||
--os-password=<password> --os-domain-name=<domain> token issue
|
--os-password=<password> --os-domain-name=<domain> token issue
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[operation.create_trust_scoped_token]
|
[operation.create_trust_scoped_token]
|
||||||
@ -104,8 +96,6 @@ notes=Tokens scoped to a trust convey only the user impersonation and
|
|||||||
cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
cli=openstack --os-username=<username> --os-user-domain-name=<domain>
|
||||||
--os-password=<password> --os-trust-id=<trust> token issue
|
--os-password=<password> --os-trust-id=<trust> token issue
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[operation.create_token_using_oauth]
|
[operation.create_token_using_oauth]
|
||||||
@ -114,8 +104,6 @@ status=optional
|
|||||||
notes=OAuth access tokens can be exchanged for keystone tokens.
|
notes=OAuth access tokens can be exchanged for keystone tokens.
|
||||||
cli=
|
cli=
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[operation.create_token_with_bind]
|
[operation.create_token_with_bind]
|
||||||
@ -125,8 +113,6 @@ notes=Tokens can express a binding to an additional authentication method, such
|
|||||||
as kerberos or x509.
|
as kerberos or x509.
|
||||||
cli=
|
cli=
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=missing
|
driver-impl-fernet=missing
|
||||||
|
|
||||||
[operation.revoke_token]
|
[operation.revoke_token]
|
||||||
@ -138,8 +124,6 @@ notes=Tokens may be individually revoked, such as when a user logs out of
|
|||||||
revoked token was previously used to create additional tokens).
|
revoked token was previously used to create additional tokens).
|
||||||
cli=openstack token revoke
|
cli=openstack token revoke
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[feature.online_validation]
|
[feature.online_validation]
|
||||||
@ -149,8 +133,6 @@ notes=Keystone must be able to validate the tokens that it issues when
|
|||||||
presented with a token that it previously issued.
|
presented with a token that it previously issued.
|
||||||
cli=
|
cli=
|
||||||
driver-impl-uuid=complete
|
driver-impl-uuid=complete
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
|
||||||
[feature.offline_validation]
|
[feature.offline_validation]
|
||||||
@ -161,8 +143,6 @@ notes=Services using Keystone for authentication may want to validate tokens
|
|||||||
performance and scalability.
|
performance and scalability.
|
||||||
cli=
|
cli=
|
||||||
driver-impl-uuid=missing
|
driver-impl-uuid=missing
|
||||||
driver-impl-pki=complete
|
|
||||||
driver-impl-pkiz=complete
|
|
||||||
driver-impl-fernet=missing
|
driver-impl-fernet=missing
|
||||||
|
|
||||||
[feature.non_persistent]
|
[feature.non_persistent]
|
||||||
@ -174,6 +154,4 @@ notes=If a token format does not require persistence (such as to a SQL
|
|||||||
operations such as `keystone-manage token_flush`.
|
operations such as `keystone-manage token_flush`.
|
||||||
cli=
|
cli=
|
||||||
driver-impl-uuid=missing
|
driver-impl-uuid=missing
|
||||||
driver-impl-pki=partial
|
|
||||||
driver-impl-pkiz=partial
|
|
||||||
driver-impl-fernet=complete
|
driver-impl-fernet=complete
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
{
|
|
||||||
"access": {
|
|
||||||
"serviceCatalog": [
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "volume",
|
|
||||||
"name": "volume"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:9292/v1",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:9292/v1",
|
|
||||||
"publicURL": "http://127.0.0.1:9292/v1"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "image",
|
|
||||||
"name": "glance"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "compute",
|
|
||||||
"name": "nova"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:35357/v2.0",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:35357/v2.0",
|
|
||||||
"publicURL": "http://127.0.0.1:5000/v2.0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "identity",
|
|
||||||
"name": "keystone"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"token": {
|
|
||||||
"expires": "2012-06-02T14:47:34Z",
|
|
||||||
"id": "placeholder",
|
|
||||||
"tenant": {
|
|
||||||
"enabled": true,
|
|
||||||
"description": null,
|
|
||||||
"name": "tenant_name1",
|
|
||||||
"id": "tenant_id1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"user": {
|
|
||||||
"username": "revoked_username1",
|
|
||||||
"roles_links": [
|
|
||||||
"role1",
|
|
||||||
"role2"
|
|
||||||
],
|
|
||||||
"id": "revoked_user_id1",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"name": "role1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "role2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "revoked_username1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
-----BEGIN CMS-----
|
|
||||||
MIIH1wYJKoZIhvcNAQcCoIIHyDCCB8QCAQExCTAHBgUrDgMCGjCCBeQGCSqGSIb3
|
|
||||||
DQEHAaCCBdUEggXReyJhY2Nlc3MiOiB7InNlcnZpY2VDYXRhbG9nIjogW3siZW5k
|
|
||||||
cG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3Yx
|
|
||||||
LzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInJlZ2lvbiI6ICJy
|
|
||||||
ZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2
|
|
||||||
L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInB1YmxpY1VS
|
|
||||||
TCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThh
|
|
||||||
NjBmY2Y4OWJiNjYxN2EifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUi
|
|
||||||
OiAidm9sdW1lIiwgIm5hbWUiOiAidm9sdW1lIn0sIHsiZW5kcG9pbnRzIjogW3si
|
|
||||||
YWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwgInJlZ2lvbiI6
|
|
||||||
ICJyZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5
|
|
||||||
MjkyL3YxIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEi
|
|
||||||
fV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiaW1hZ2UiLCAibmFt
|
|
||||||
ZSI6ICJnbGFuY2UifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRw
|
|
||||||
Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5
|
|
||||||
YmI2NjE3YSIsICJyZWdpb24iOiAicmVnaW9uT25lIiwgImludGVybmFsVVJMIjog
|
|
||||||
Imh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYw
|
|
||||||
ZmNmODliYjY2MTdhIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3
|
|
||||||
NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSJ9XSwgImVu
|
|
||||||
ZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAi
|
|
||||||
bm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xMjcu
|
|
||||||
MC4wLjE6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVy
|
|
||||||
bmFsVVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsICJwdWJsaWNV
|
|
||||||
UkwiOiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAifV0sICJlbmRwb2ludHNf
|
|
||||||
bGlua3MiOiBbXSwgInR5cGUiOiAiaWRlbnRpdHkiLCAibmFtZSI6ICJrZXlzdG9u
|
|
||||||
ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjAxMi0wNi0wMlQxNDo0NzozNFoi
|
|
||||||
LCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJlbmFibGVkIjogdHJ1
|
|
||||||
ZSwgImRlc2NyaXB0aW9uIjogbnVsbCwgIm5hbWUiOiAidGVuYW50X25hbWUxIiwg
|
|
||||||
ImlkIjogInRlbmFudF9pZDEifX0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJyZXZv
|
|
||||||
a2VkX3VzZXJuYW1lMSIsICJyb2xlc19saW5rcyI6IFsicm9sZTEiLCJyb2xlMiJd
|
|
||||||
LCAiaWQiOiAicmV2b2tlZF91c2VyX2lkMSIsICJyb2xlcyI6IFt7Im5hbWUiOiAi
|
|
||||||
cm9sZTEifSwgeyJuYW1lIjogInJvbGUyIn1dLCAibmFtZSI6ICJyZXZva2VkX3Vz
|
|
||||||
ZXJuYW1lMSJ9fX0NCjGCAcowggHGAgEBMIGkMIGeMQowCAYDVQQFEwE1MQswCQYD
|
|
||||||
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55dmFsZTESMBAGA1UE
|
|
||||||
ChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMGCSqGSIb3DQEJARYW
|
|
||||||
a2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2VsZiBTaWduZWQCAREw
|
|
||||||
BwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEggEAXY8JvllpyctcNlJByPLxhgLyRfFo
|
|
||||||
Ew+8Yq3O4FxOyfVkINvOz4EHTipY0M/K8OLwfxpRt7o/iGLGRDBTI6Dd+erXsus8
|
|
||||||
NecnNxcWN9RUE2CZhoGj/0nhnNEGF+9Mlv3tMBngwoUJg2paSw/Vn2Q7RaqbOC05
|
|
||||||
aZOSDoSX7Zf0DIS/T0ZPnmOUb9+N25M20ctMHksPMEq0qyf2oove0O+WMa/cA8JT
|
|
||||||
c2EAhew4WSD0Zv0GOAP30GS+hkNfA1GZTrvCQrpRs9jXhK4dR2bBsnUFVix1BEZ0
|
|
||||||
sDhI8cXLvm16IpOO8ov6002ZoZhPn6Qo+0J8QOfdnjiwNnxLOEbuOIwPeQ==
|
|
||||||
-----END CMS-----
|
|
@ -1,85 +0,0 @@
|
|||||||
{
|
|
||||||
"access": {
|
|
||||||
"serviceCatalog": [
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "volume",
|
|
||||||
"name": "volume"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:9292/v1",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:9292/v1",
|
|
||||||
"publicURL": "http://127.0.0.1:9292/v1"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "image",
|
|
||||||
"name": "glance"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a",
|
|
||||||
"publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "compute",
|
|
||||||
"name": "nova"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"endpoints": [
|
|
||||||
{
|
|
||||||
"adminURL": "http://127.0.0.1:35357/v2.0",
|
|
||||||
"region": "RegionOne",
|
|
||||||
"internalURL": "http://127.0.0.1:35357/v2.0",
|
|
||||||
"publicURL": "http://127.0.0.1:5000/v2.0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"endpoints_links": [],
|
|
||||||
"type": "identity",
|
|
||||||
"name": "keystone"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"token": {
|
|
||||||
"expires": "2012-06-02T14:47:34Z",
|
|
||||||
"id": "placeholder",
|
|
||||||
"tenant": {
|
|
||||||
"enabled": true,
|
|
||||||
"description": null,
|
|
||||||
"name": "tenant_name1",
|
|
||||||
"id": "tenant_id1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"user": {
|
|
||||||
"username": "user_name1",
|
|
||||||
"roles_links": [
|
|
||||||
"role1",
|
|
||||||
"role2"
|
|
||||||
],
|
|
||||||
"id": "user_id1",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"name": "role1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "role2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "user_name1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
-----BEGIN CMS-----
|
|
||||||
MIIHwQYJKoZIhvcNAQcCoIIHsjCCB64CAQExCTAHBgUrDgMCGjCCBc4GCSqGSIb3
|
|
||||||
DQEHAaCCBb8EggW7eyJhY2Nlc3MiOiB7InNlcnZpY2VDYXRhbG9nIjogW3siZW5k
|
|
||||||
cG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3Yx
|
|
||||||
LzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInJlZ2lvbiI6ICJy
|
|
||||||
ZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2
|
|
||||||
L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInB1YmxpY1VS
|
|
||||||
TCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThh
|
|
||||||
NjBmY2Y4OWJiNjYxN2EifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUi
|
|
||||||
OiAidm9sdW1lIiwgIm5hbWUiOiAidm9sdW1lIn0sIHsiZW5kcG9pbnRzIjogW3si
|
|
||||||
YWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwgInJlZ2lvbiI6
|
|
||||||
ICJyZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5
|
|
||||||
MjkyL3YxIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEi
|
|
||||||
fV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiaW1hZ2UiLCAibmFt
|
|
||||||
ZSI6ICJnbGFuY2UifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRw
|
|
||||||
Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5
|
|
||||||
YmI2NjE3YSIsICJyZWdpb24iOiAicmVnaW9uT25lIiwgImludGVybmFsVVJMIjog
|
|
||||||
Imh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYw
|
|
||||||
ZmNmODliYjY2MTdhIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3
|
|
||||||
NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSJ9XSwgImVu
|
|
||||||
ZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAi
|
|
||||||
bm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xMjcu
|
|
||||||
MC4wLjE6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVy
|
|
||||||
bmFsVVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsICJwdWJsaWNV
|
|
||||||
UkwiOiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAifV0sICJlbmRwb2ludHNf
|
|
||||||
bGlua3MiOiBbXSwgInR5cGUiOiAiaWRlbnRpdHkiLCAibmFtZSI6ICJrZXlzdG9u
|
|
||||||
ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjAxMi0wNi0wMlQxNDo0NzozNFoi
|
|
||||||
LCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJlbmFibGVkIjogdHJ1
|
|
||||||
ZSwgImRlc2NyaXB0aW9uIjogbnVsbCwgIm5hbWUiOiAidGVuYW50X25hbWUxIiwg
|
|
||||||
ImlkIjogInRlbmFudF9pZDEifX0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJ1c2Vy
|
|
||||||
X25hbWUxIiwgInJvbGVzX2xpbmtzIjogWyJyb2xlMSIsInJvbGUyIl0sICJpZCI6
|
|
||||||
ICJ1c2VyX2lkMSIsICJyb2xlcyI6IFt7Im5hbWUiOiAicm9sZTEifSwgeyJuYW1l
|
|
||||||
IjogInJvbGUyIn1dLCAibmFtZSI6ICJ1c2VyX25hbWUxIn19fQ0KMYIByjCCAcYC
|
|
||||||
AQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTES
|
|
||||||
MBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sxETAPBgNVBAsT
|
|
||||||
CEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVuc3RhY2sub3Jn
|
|
||||||
MRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkqhkiG9w0BAQEF
|
|
||||||
AASCAQCAtuVtqTU9h1uaRrYU1eusSnHwD6jizp/xltTrYTyFPfYjhJdglS+bjSeS
|
|
||||||
Iau9pN3Tfug98ozUTJ5ByNepAQtxBxPz5bDXhBmAbU6ywaolqRAG+b/s2ShNGQ2a
|
|
||||||
tn80NeZmDNbtoqdHVAkD3EZXjsEKr2w+3JTTF2indzczyGe5EeSfNUaT+ZhNEmPR
|
|
||||||
Urob62t8atW+zehCSurpaa8pC5m1NcbK8Uu6Y+qO2m08KU9w5kmbOQtWAGCmtpIx
|
|
||||||
F2yM1AbSgd90yzen7dv5mNkgZyzQ6SYgRUvkKOKnCyBb97EZK3ZR4qUxQzRYM++8
|
|
||||||
g8HdaIfoYVPoPHqODet8Xmhw/Wtp
|
|
||||||
-----END CMS-----
|
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"access": {
|
|
||||||
"token": {
|
|
||||||
"expires": "2012-08-17T15:35:34Z",
|
|
||||||
"id": "01e032c996ef4406b144335915a41e79"
|
|
||||||
},
|
|
||||||
"serviceCatalog": {},
|
|
||||||
"user": {
|
|
||||||
"username": "user_name1",
|
|
||||||
"roles_links": [],
|
|
||||||
"id": "c9c89e3be3ee453fbf00c7966f6d3fbd",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"name": "role1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "role2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "user_name1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
-----BEGIN CMS-----
|
|
||||||
MIIDKAYJKoZIhvcNAQcCoIIDGTCCAxUCAQExCTAHBgUrDgMCGjCCATUGCSqGSIb3
|
|
||||||
DQEHAaCCASYEggEieyJhY2Nlc3MiOiB7InRva2VuIjogeyJleHBpcmVzIjogIjIw
|
|
||||||
MTItMDgtMTdUMTU6MzU6MzRaIiwgImlkIjogIjAxZTAzMmM5OTZlZjQ0MDZiMTQ0
|
|
||||||
MzM1OTE1YTQxZTc5In0sICJzZXJ2aWNlQ2F0YWxvZyI6IHt9LCAidXNlciI6IHsi
|
|
||||||
dXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQi
|
|
||||||
OiAiYzljODllM2JlM2VlNDUzZmJmMDBjNzk2NmY2ZDNmYmQiLCAicm9sZXMiOiBb
|
|
||||||
eyduYW1lJzogJ3JvbGUxJ30seyduYW1lJzogJ3JvbGUyJ30sXSwgIm5hbWUiOiAi
|
|
||||||
dXNlcl9uYW1lMSJ9fX0xggHKMIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkG
|
|
||||||
A1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNV
|
|
||||||
BAoTCU9wZW5TdGFjazERMA8GA1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEW
|
|
||||||
FmtleXN0b25lQG9wZW5zdGFjay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgER
|
|
||||||
MAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAFyD9IH2bXsafCTyHEWS28zBuq03
|
|
||||||
ZNWXV4+0BfdMbX1ONkaQ7mLGRmfabLHwfE5RaSASFh/Doq7KTc8XrBVfTm9HQPGr
|
|
||||||
TLZUawdYlyBFVq0PEE1cPvO9Blz4X/2Awcp/Q67YRd/oLCY2dFWMClMroXu1fy3P
|
|
||||||
oFlpWPPhURrbU1GjhUgPIz0IxNGjfWEHVsb5kz7Bo4E8J3pgIkccm97XZZtiCwf7
|
|
||||||
DVNj+Eb5mRegGG6IgSSRpZULgnCmSofQ3RnW3jSCkDxLXDQm9IsaaLJsuUFLylGs
|
|
||||||
mB/98w9mP192IGl5MVr8/tANXwb5ok2VatUp/Ww1U0IlWbhN374PbK76vcE=
|
|
||||||
-----END CMS-----
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"revoked": [
|
|
||||||
{
|
|
||||||
"id": "7acfcfdaf6a14aebe97c61c5947bc4d3",
|
|
||||||
"expires": "2012-08-14T17:58:48Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
-----BEGIN CMS-----
|
|
||||||
MIICWgYJKoZIhvcNAQcCoIICSzCCAkcCAQExCTAHBgUrDgMCGjBpBgkqhkiG9w0B
|
|
||||||
BwGgXARaeyJyZXZva2VkIjpbeyJpZCI6IjdhY2ZjZmRhZjZhMTRhZWJlOTdjNjFj
|
|
||||||
NTk0N2JjNGQzIiwiZXhwaXJlcyI6IjIwMTItMDgtMTRUMTc6NTg6NDhaIn1dfQ0K
|
|
||||||
MYIByjCCAcYCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYD
|
|
||||||
VQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sx
|
|
||||||
ETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVu
|
|
||||||
c3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkq
|
|
||||||
hkiG9w0BAQEFAASCAQC2f05VHM7zjNT3TBO80AmZ00n7AEWUjbFe5nqIM8kWGM83
|
|
||||||
01Bi3uU/nQ0daAd3tqCmDL2EfETAjD+xnIzjlN6eIA74Vy51wFD/KiyWYPWzw8mH
|
|
||||||
WcATHmE4E8kLdt8NhUodCY9TCFxcHJNDR1Eai/U7hH+5O4p9HcmMjv/GWegZL6HB
|
|
||||||
Up9Cxu6haxvPFmYylzM6Qt0Ad/WiO/JZLPTA4qXJEJSa9EMFMb0c2wSDSn30swJe
|
|
||||||
7J79VTFktTr2djv8KFvaHr4vLFYv2Y3ZkTeHqam0m91vllxLZJUP5QTSHjjY6LFE
|
|
||||||
5eEjIlOv9wOOm1uTtPIq6pxCugU1Wm7gstkqr55R
|
|
||||||
-----END CMS-----
|
|
@ -1,233 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright 2012 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# This script generates the crypto necessary for the SSL tests.
|
|
||||||
|
|
||||||
DIR=`dirname "$0"`
|
|
||||||
CURRENT_DIR=`cd "$DIR" && pwd`
|
|
||||||
CERTS_DIR=$CURRENT_DIR/certs
|
|
||||||
PRIVATE_DIR=$CURRENT_DIR/private
|
|
||||||
CMS_DIR=$CURRENT_DIR/cms
|
|
||||||
|
|
||||||
|
|
||||||
function rm_old {
|
|
||||||
rm -rf $CERTS_DIR/*.pem
|
|
||||||
rm -rf $PRIVATE_DIR/*.pem
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanup {
|
|
||||||
rm -rf *.conf > /dev/null 2>&1
|
|
||||||
rm -rf index* > /dev/null 2>&1
|
|
||||||
rm -rf *.crt > /dev/null 2>&1
|
|
||||||
rm -rf newcerts > /dev/null 2>&1
|
|
||||||
rm -rf *.pem > /dev/null 2>&1
|
|
||||||
rm -rf serial* > /dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_ca_conf {
|
|
||||||
echo '
|
|
||||||
[ req ]
|
|
||||||
default_bits = 2048
|
|
||||||
default_keyfile = cakey.pem
|
|
||||||
default_md = default
|
|
||||||
|
|
||||||
prompt = no
|
|
||||||
distinguished_name = ca_distinguished_name
|
|
||||||
|
|
||||||
x509_extensions = ca_extensions
|
|
||||||
|
|
||||||
[ ca_distinguished_name ]
|
|
||||||
serialNumber = 5
|
|
||||||
countryName = US
|
|
||||||
stateOrProvinceName = CA
|
|
||||||
localityName = Sunnyvale
|
|
||||||
organizationName = OpenStack
|
|
||||||
organizationalUnitName = Keystone
|
|
||||||
emailAddress = keystone@openstack.org
|
|
||||||
commonName = Self Signed
|
|
||||||
|
|
||||||
[ ca_extensions ]
|
|
||||||
basicConstraints = critical,CA:true
|
|
||||||
' > ca.conf
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_ssl_req_conf {
|
|
||||||
echo '
|
|
||||||
[ req ]
|
|
||||||
default_bits = 2048
|
|
||||||
default_keyfile = keystonekey.pem
|
|
||||||
default_md = default
|
|
||||||
|
|
||||||
prompt = no
|
|
||||||
distinguished_name = distinguished_name
|
|
||||||
|
|
||||||
[ distinguished_name ]
|
|
||||||
countryName = US
|
|
||||||
stateOrProvinceName = CA
|
|
||||||
localityName = Sunnyvale
|
|
||||||
organizationName = OpenStack
|
|
||||||
organizationalUnitName = Keystone
|
|
||||||
commonName = localhost
|
|
||||||
emailAddress = keystone@openstack.org
|
|
||||||
' > ssl_req.conf
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_cms_signing_req_conf {
|
|
||||||
echo '
|
|
||||||
[ req ]
|
|
||||||
default_bits = 2048
|
|
||||||
default_keyfile = keystonekey.pem
|
|
||||||
default_md = default
|
|
||||||
|
|
||||||
prompt = no
|
|
||||||
distinguished_name = distinguished_name
|
|
||||||
|
|
||||||
[ distinguished_name ]
|
|
||||||
countryName = US
|
|
||||||
stateOrProvinceName = CA
|
|
||||||
localityName = Sunnyvale
|
|
||||||
organizationName = OpenStack
|
|
||||||
organizationalUnitName = Keystone
|
|
||||||
commonName = Keystone
|
|
||||||
emailAddress = keystone@openstack.org
|
|
||||||
' > cms_signing_req.conf
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_signing_conf {
|
|
||||||
echo '
|
|
||||||
[ ca ]
|
|
||||||
default_ca = signing_ca
|
|
||||||
|
|
||||||
[ signing_ca ]
|
|
||||||
dir = .
|
|
||||||
database = $dir/index.txt
|
|
||||||
new_certs_dir = $dir/newcerts
|
|
||||||
|
|
||||||
certificate = $dir/certs/cacert.pem
|
|
||||||
serial = $dir/serial
|
|
||||||
private_key = $dir/private/cakey.pem
|
|
||||||
|
|
||||||
default_days = 21360
|
|
||||||
default_crl_days = 30
|
|
||||||
default_md = default
|
|
||||||
|
|
||||||
policy = policy_any
|
|
||||||
|
|
||||||
[ policy_any ]
|
|
||||||
countryName = supplied
|
|
||||||
stateOrProvinceName = supplied
|
|
||||||
localityName = optional
|
|
||||||
organizationName = supplied
|
|
||||||
organizationalUnitName = supplied
|
|
||||||
emailAddress = supplied
|
|
||||||
commonName = supplied
|
|
||||||
' > signing.conf
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup {
|
|
||||||
touch index.txt
|
|
||||||
echo '10' > serial
|
|
||||||
generate_ca_conf
|
|
||||||
mkdir newcerts
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_error {
|
|
||||||
if [ $1 != 0 ] ; then
|
|
||||||
echo "Failed! rc=${1}"
|
|
||||||
echo 'Bailing ...'
|
|
||||||
cleanup
|
|
||||||
exit $1
|
|
||||||
else
|
|
||||||
echo 'Done'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_ca {
|
|
||||||
echo 'Generating New CA Certificate ...'
|
|
||||||
openssl req -x509 -newkey rsa:2048 -days 21360 -out $CERTS_DIR/cacert.pem \
|
|
||||||
-keyout $PRIVATE_DIR/cakey.pem -outform PEM -config ca.conf -nodes
|
|
||||||
check_error $?
|
|
||||||
}
|
|
||||||
|
|
||||||
function ssl_cert_req {
|
|
||||||
echo 'Generating SSL Certificate Request ...'
|
|
||||||
generate_ssl_req_conf
|
|
||||||
openssl req -newkey rsa:2048 -keyout $PRIVATE_DIR/ssl_key.pem \
|
|
||||||
-keyform PEM -out ssl_req.pem -outform PEM -config ssl_req.conf -nodes
|
|
||||||
check_error $?
|
|
||||||
#openssl req -in req.pem -text -noout
|
|
||||||
}
|
|
||||||
|
|
||||||
function cms_signing_cert_req {
|
|
||||||
echo 'Generating CMS Signing Certificate Request ...'
|
|
||||||
generate_cms_signing_req_conf
|
|
||||||
openssl req -newkey rsa:2048 -keyout $PRIVATE_DIR/signing_key.pem \
|
|
||||||
-keyform PEM -out cms_signing_req.pem -outform PEM \
|
|
||||||
-config cms_signing_req.conf -nodes
|
|
||||||
check_error $?
|
|
||||||
#openssl req -in req.pem -text -noout
|
|
||||||
}
|
|
||||||
|
|
||||||
function issue_certs {
|
|
||||||
generate_signing_conf
|
|
||||||
echo 'Issuing SSL Certificate ...'
|
|
||||||
openssl ca -in ssl_req.pem -config signing.conf -batch
|
|
||||||
check_error $?
|
|
||||||
openssl x509 -in $CURRENT_DIR/newcerts/10.pem -out $CERTS_DIR/ssl_cert.pem
|
|
||||||
check_error $?
|
|
||||||
echo 'Issuing CMS Signing Certificate ...'
|
|
||||||
openssl ca -in cms_signing_req.pem -config signing.conf -batch
|
|
||||||
check_error $?
|
|
||||||
openssl x509 -in $CURRENT_DIR/newcerts/11.pem \
|
|
||||||
-out $CERTS_DIR/signing_cert.pem
|
|
||||||
check_error $?
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_middleware_cert {
|
|
||||||
cp $CERTS_DIR/ssl_cert.pem $CERTS_DIR/middleware.pem
|
|
||||||
cat $PRIVATE_DIR/ssl_key.pem >> $CERTS_DIR/middleware.pem
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_openssl {
|
|
||||||
echo 'Checking openssl availability ...'
|
|
||||||
which openssl
|
|
||||||
check_error $?
|
|
||||||
}
|
|
||||||
|
|
||||||
function gen_sample_cms {
|
|
||||||
FILES="${CMS_DIR}/auth_token_revoked.json"
|
|
||||||
FILES+=" ${CMS_DIR}/auth_token_unscoped.json"
|
|
||||||
FILES+=" ${CMS_DIR}/auth_token_scoped.json"
|
|
||||||
FILES+=" ${CMS_DIR}/revocation_list.json"
|
|
||||||
for json_file in $FILES; do
|
|
||||||
openssl cms -sign -in $json_file -nosmimecap \
|
|
||||||
-signer $CERTS_DIR/signing_cert.pem \
|
|
||||||
-inkey $PRIVATE_DIR/signing_key.pem -outform PEM -nodetach \
|
|
||||||
-nocerts -noattr -out ${json_file/.json/.pem}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
check_openssl
|
|
||||||
rm_old
|
|
||||||
cleanup
|
|
||||||
setup
|
|
||||||
generate_ca
|
|
||||||
ssl_cert_req
|
|
||||||
cms_signing_cert_req
|
|
||||||
issue_certs
|
|
||||||
create_middleware_cert
|
|
||||||
gen_sample_cms
|
|
||||||
cleanup
|
|
@ -518,7 +518,7 @@ class BaseCertificateSetup(BasePermissionsSetup):
|
|||||||
|
|
||||||
|
|
||||||
class PKISetup(BaseCertificateSetup):
|
class PKISetup(BaseCertificateSetup):
|
||||||
"""Set up Key pairs and certificates for token signing and verification.
|
"""Setup keys and certificates for signing and verifying revocation lists.
|
||||||
|
|
||||||
This is NOT intended for production use, see Keystone Configuration
|
This is NOT intended for production use, see Keystone Configuration
|
||||||
documentation for details. As of the Mitaka release, this command has
|
documentation for details. As of the Mitaka release, this command has
|
||||||
|
@ -28,10 +28,6 @@ def symptom_unreasonable_max_token_size():
|
|||||||
- For UUID, set `keystone.conf [DEFAULT] max_token_size = 32`, because UUID
|
- For UUID, set `keystone.conf [DEFAULT] max_token_size = 32`, because UUID
|
||||||
tokens are always exactly 32 characters.
|
tokens are always exactly 32 characters.
|
||||||
|
|
||||||
- For PKI and PKIZ, set `keystone.conf [DEFAULT] max_token_size = 8192`,
|
|
||||||
because PKI and PKIZ tokens can be quite large, but any larger than 8192
|
|
||||||
and they tend to break certain implementations of HTTP.
|
|
||||||
|
|
||||||
- For Fernet, set `keystone.conf [DEFAULT] max_token_size = 255`, because
|
- For Fernet, set `keystone.conf [DEFAULT] max_token_size = 255`, because
|
||||||
Fernet tokens should never exceed this length in most deployments.
|
Fernet tokens should never exceed this length in most deployments.
|
||||||
However, if you are also using `keystone.conf [identity] driver = ldap`,
|
However, if you are also using `keystone.conf [identity] driver = ldap`,
|
||||||
@ -41,6 +37,4 @@ def symptom_unreasonable_max_token_size():
|
|||||||
"""
|
"""
|
||||||
return (
|
return (
|
||||||
'uuid' in CONF.token.provider and CONF.max_token_size != 32
|
'uuid' in CONF.token.provider and CONF.max_token_size != 32
|
||||||
or 'pki' in CONF.token.provider and CONF.max_token_size < 8192
|
|
||||||
or 'pkiz' in CONF.token.provider and CONF.max_token_size < 8192
|
|
||||||
or 'fernet' in CONF.token.provider and CONF.max_token_size > 255)
|
or 'fernet' in CONF.token.provider and CONF.max_token_size > 255)
|
||||||
|
@ -95,13 +95,6 @@ class SmarterEncoder(jsonutils.json.JSONEncoder):
|
|||||||
return super(SmarterEncoder, self).default(obj)
|
return super(SmarterEncoder, self).default(obj)
|
||||||
|
|
||||||
|
|
||||||
class PKIEncoder(SmarterEncoder):
|
|
||||||
"""Special encoder to make token JSON a bit shorter."""
|
|
||||||
|
|
||||||
item_separator = ','
|
|
||||||
key_separator = ':'
|
|
||||||
|
|
||||||
|
|
||||||
def verify_length_and_trunc_password(password):
|
def verify_length_and_trunc_password(password):
|
||||||
"""Verify and truncate the provided password to the max_password_length."""
|
"""Verify and truncate the provided password to the max_password_length."""
|
||||||
max_length = CONF.identity.max_password_length
|
max_length = CONF.identity.max_password_length
|
||||||
|
@ -16,15 +16,8 @@ package.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from keystone.conf import utils
|
|
||||||
|
|
||||||
|
|
||||||
_DEFAULT_AUTH_METHODS = ['external', 'password', 'token', 'oauth1']
|
_DEFAULT_AUTH_METHODS = ['external', 'password', 'token', 'oauth1']
|
||||||
|
|
||||||
_CERTFILE = '/etc/keystone/ssl/certs/signing_cert.pem'
|
_CERTFILE = '/etc/keystone/ssl/certs/signing_cert.pem'
|
||||||
_KEYFILE = '/etc/keystone/ssl/private/signing_key.pem'
|
_KEYFILE = '/etc/keystone/ssl/private/signing_key.pem'
|
||||||
|
|
||||||
_DEPRECATE_PKI_MSG = utils.fmt("""
|
|
||||||
PKI token support has been deprecated in the M release and will be removed in
|
|
||||||
the O release. Fernet or UUID tokens are recommended.
|
|
||||||
""")
|
|
||||||
|
@ -82,16 +82,16 @@ max_param_size = cfg.IntOpt(
|
|||||||
Limit the sizes of user & project ID/names.
|
Limit the sizes of user & project ID/names.
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
# we allow tokens to be a bit larger to accommodate PKI
|
# NOTE(breton): 255 is the size of the database columns used for ID fields.
|
||||||
|
# This size is picked so that the tokens can be indexed in-place as opposed to
|
||||||
|
# being entries in a string table. Thus, this is a performance decision.
|
||||||
max_token_size = cfg.IntOpt(
|
max_token_size = cfg.IntOpt(
|
||||||
'max_token_size',
|
'max_token_size',
|
||||||
default=8192,
|
default=255,
|
||||||
help=utils.fmt("""
|
help=utils.fmt("""
|
||||||
Similar to `[DEFAULT] max_param_size`, but provides an exception for token
|
Similar to `[DEFAULT] max_param_size`, but provides an exception for token
|
||||||
values. With PKI / PKIZ tokens, this needs to be set close to 8192 (any higher,
|
values. With Fernet tokens, this can be set as low as 255. With UUID tokens,
|
||||||
and other HTTP implementations may break), depending on the size of your
|
this should be set to 32).
|
||||||
service catalog and other factors. With Fernet tokens, this can be set as low
|
|
||||||
as 255. With UUID tokens, this should be set to 32).
|
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
member_role_id = cfg.StrOpt(
|
member_role_id = cfg.StrOpt(
|
||||||
|
@ -10,13 +10,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import hashlib
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import versionutils
|
|
||||||
|
|
||||||
from keystone.conf import constants
|
|
||||||
from keystone.conf import utils
|
from keystone.conf import utils
|
||||||
|
|
||||||
|
|
||||||
@ -66,14 +63,12 @@ provider = cfg.StrOpt(
|
|||||||
help=utils.fmt("""
|
help=utils.fmt("""
|
||||||
Entry point for the token provider in the `keystone.token.provider` namespace.
|
Entry point for the token provider in the `keystone.token.provider` namespace.
|
||||||
The token provider controls the token construction, validation, and revocation
|
The token provider controls the token construction, validation, and revocation
|
||||||
operations. Keystone includes `fernet`, `pkiz`, `pki`, and `uuid` token
|
operations. Keystone includes `fernet` and `uuid` token
|
||||||
providers. `uuid` tokens must be persisted (using the backend specified in the
|
providers. `uuid` tokens must be persisted (using the backend specified in the
|
||||||
`[token] driver` option), but do not require any extra configuration or setup.
|
`[token] driver` option), but do not require any extra configuration or setup.
|
||||||
`fernet` tokens do not need to be persisted at all, but require that you run
|
`fernet` tokens do not need to be persisted at all, but require that you run
|
||||||
`keystone-manage fernet_setup` (also see the `keystone-manage fernet_rotate`
|
`keystone-manage fernet_setup` (also see the `keystone-manage fernet_rotate`
|
||||||
command). `pki` and `pkiz` tokens can be validated offline, without making HTTP
|
command).
|
||||||
calls to keystone, but require that certificates be installed and distributed
|
|
||||||
to facilitate signing tokens and later validating those signatures.
|
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
driver = cfg.StrOpt(
|
driver = cfg.StrOpt(
|
||||||
@ -128,26 +123,6 @@ for tokens with a more specific scope) or to provide their credentials in every
|
|||||||
request for a scoped token to avoid re-scoping altogether.
|
request for a scoped token to avoid re-scoping altogether.
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
# This attribute only exists in Python 2.7.8+ or 3.2+
|
|
||||||
hash_choices = getattr(hashlib, 'algorithms_guaranteed', None)
|
|
||||||
hash_choices = sorted(hash_choices) if hash_choices else None
|
|
||||||
hash_algorithm = cfg.StrOpt(
|
|
||||||
'hash_algorithm',
|
|
||||||
default='md5',
|
|
||||||
choices=hash_choices,
|
|
||||||
deprecated_for_removal=True,
|
|
||||||
deprecated_reason=constants._DEPRECATE_PKI_MSG,
|
|
||||||
deprecated_since=versionutils.deprecated.MITAKA,
|
|
||||||
help=utils.fmt("""
|
|
||||||
This controls the hash algorithm to use to uniquely identify PKI tokens without
|
|
||||||
having to transmit the entire token to keystone (which may be several
|
|
||||||
kilobytes). This can be set to any algorithm that hashlib supports. WARNING:
|
|
||||||
Before changing this value, the `auth_token` middleware protecting all other
|
|
||||||
services must be configured with the set of hash algorithms to expect from
|
|
||||||
keystone (both your old and new value for this option), otherwise token
|
|
||||||
revocation will not be processed correctly.
|
|
||||||
"""))
|
|
||||||
|
|
||||||
infer_roles = cfg.BoolOpt(
|
infer_roles = cfg.BoolOpt(
|
||||||
'infer_roles',
|
'infer_roles',
|
||||||
default=True,
|
default=True,
|
||||||
@ -176,7 +151,6 @@ ALL_OPTS = [
|
|||||||
cache_time,
|
cache_time,
|
||||||
revoke_by_id,
|
revoke_by_id,
|
||||||
allow_rescope_scoped_token,
|
allow_rescope_scoped_token,
|
||||||
hash_algorithm,
|
|
||||||
infer_roles,
|
infer_roles,
|
||||||
cache_on_issue,
|
cache_on_issue,
|
||||||
]
|
]
|
||||||
|
@ -176,12 +176,6 @@ class RegionDeletionError(ForbiddenNotSecurity):
|
|||||||
"its child regions have associated endpoints.")
|
"its child regions have associated endpoints.")
|
||||||
|
|
||||||
|
|
||||||
class PKITokenExpected(ForbiddenNotSecurity):
|
|
||||||
message_format = _('The certificates you requested are not available. '
|
|
||||||
'It is likely that this server does not use PKI tokens '
|
|
||||||
'otherwise this is the result of misconfiguration.')
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityError(Error):
|
class SecurityError(Error):
|
||||||
"""Security error exception.
|
"""Security error exception.
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
"""Unified in-memory token model."""
|
"""Unified in-memory token model."""
|
||||||
|
|
||||||
from keystoneclient.common import cms
|
|
||||||
from oslo_utils import reflection
|
from oslo_utils import reflection
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
@ -51,8 +50,7 @@ class KeystoneToken(dict):
|
|||||||
super(KeystoneToken, self).__init__(**token_data['token'])
|
super(KeystoneToken, self).__init__(**token_data['token'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise exception.UnsupportedTokenVersionException()
|
raise exception.UnsupportedTokenVersionException()
|
||||||
self.short_id = cms.cms_hash_token(token_id,
|
self.token_id = token_id
|
||||||
mode=CONF.token.hash_algorithm)
|
|
||||||
|
|
||||||
if self.project_scoped and self.domain_scoped:
|
if self.project_scoped and self.domain_scoped:
|
||||||
raise exception.UnexpectedError(_('Found invalid token: scoped to '
|
raise exception.UnexpectedError(_('Found invalid token: scoped to '
|
||||||
|
@ -18,7 +18,6 @@ import uuid
|
|||||||
import freezegun
|
import freezegun
|
||||||
from oslo_config import fixture as config_fixture
|
from oslo_config import fixture as config_fixture
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from keystone.common import fernet_utils
|
from keystone.common import fernet_utils
|
||||||
@ -196,12 +195,6 @@ class UtilsTestCase(unit.BaseTestCase):
|
|||||||
TZ = 'UTC' + d
|
TZ = 'UTC' + d
|
||||||
_test_unixtime()
|
_test_unixtime()
|
||||||
|
|
||||||
def test_pki_encoder(self):
|
|
||||||
data = {'field': 'value'}
|
|
||||||
json = jsonutils.dumps(data, cls=common_utils.PKIEncoder)
|
|
||||||
expected_json = '{"field":"value"}'
|
|
||||||
self.assertEqual(expected_json, json)
|
|
||||||
|
|
||||||
def test_url_safe_check(self):
|
def test_url_safe_check(self):
|
||||||
base_str = 'i am safe'
|
base_str = 'i am safe'
|
||||||
self.assertFalse(common_utils.is_not_url_safe(base_str))
|
self.assertFalse(common_utils.is_not_url_safe(base_str))
|
||||||
|
@ -664,18 +664,6 @@ class FernetAuthWithToken(AuthWithToken, AuthTest):
|
|||||||
self.skip_test_overrides('Fernet with v2.0 and revocation is broken')
|
self.skip_test_overrides('Fernet with v2.0 and revocation is broken')
|
||||||
|
|
||||||
|
|
||||||
class PKIAuthWithToken(AuthWithToken, AuthTest):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIAuthWithToken, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
|
|
||||||
|
|
||||||
class PKIZAuthWithToken(AuthWithToken, AuthTest):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIZAuthWithToken, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
|
|
||||||
|
|
||||||
class AuthWithPasswordCredentials(AuthTest):
|
class AuthWithPasswordCredentials(AuthTest):
|
||||||
def test_auth_invalid_user(self):
|
def test_auth_invalid_user(self):
|
||||||
"""Verify exception is raised if invalid user."""
|
"""Verify exception is raised if invalid user."""
|
||||||
@ -880,20 +868,6 @@ class UUIDAuthWithRemoteUser(AuthWithRemoteUser, AuthTest):
|
|||||||
self.config_fixture.config(group='token', provider='uuid')
|
self.config_fixture.config(group='token', provider='uuid')
|
||||||
|
|
||||||
|
|
||||||
class PKIAuthWithRemoteUser(AuthWithRemoteUser, AuthTest):
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIAuthWithRemoteUser, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
|
|
||||||
|
|
||||||
class PKIZAuthWithRemoteUser(AuthWithRemoteUser, AuthTest):
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIZAuthWithRemoteUser, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
|
|
||||||
|
|
||||||
class AuthWithTrust(object):
|
class AuthWithTrust(object):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(AuthWithTrust, self).setUp()
|
super(AuthWithTrust, self).setUp()
|
||||||
|
@ -854,33 +854,6 @@ class SqlTokenCacheInvalidationWithUUID(SqlTests,
|
|||||||
self.config_fixture.config(group='token', provider='uuid')
|
self.config_fixture.config(group='token', provider='uuid')
|
||||||
|
|
||||||
|
|
||||||
class SqlTokenCacheInvalidationWithPKI(SqlTests,
|
|
||||||
token_tests.TokenCacheInvalidation):
|
|
||||||
def setUp(self):
|
|
||||||
super(SqlTokenCacheInvalidationWithPKI, self).setUp()
|
|
||||||
self._create_test_data()
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(SqlTokenCacheInvalidationWithPKI, self).config_overrides()
|
|
||||||
# NOTE(lbragstad): The TokenCacheInvalidation tests are coded to work
|
|
||||||
# against a persistent token backend. Only run these with token
|
|
||||||
# providers that issue persistent tokens.
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
|
|
||||||
|
|
||||||
class SqlTokenCacheInvalidationWithPKIZ(SqlTests,
|
|
||||||
token_tests.TokenCacheInvalidation):
|
|
||||||
def setUp(self):
|
|
||||||
super(SqlTokenCacheInvalidationWithPKIZ, self).setUp()
|
|
||||||
self._create_test_data()
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(SqlTokenCacheInvalidationWithPKIZ, self).config_overrides()
|
|
||||||
# NOTE(lbragstad): The TokenCacheInvalidation tests are coded to work
|
|
||||||
# against a persistent token backend. Only run these with token
|
|
||||||
# providers that issue persistent tokens.
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
|
|
||||||
# NOTE(lbragstad): The Fernet token provider doesn't persist tokens in a
|
# NOTE(lbragstad): The Fernet token provider doesn't persist tokens in a
|
||||||
# backend, so running the TokenCacheInvalidation tests here doesn't make sense.
|
# backend, so running the TokenCacheInvalidation tests here doesn't make sense.
|
||||||
|
|
||||||
|
@ -22,10 +22,9 @@ from six.moves import http_client
|
|||||||
from testtools import matchers
|
from testtools import matchers
|
||||||
|
|
||||||
from keystone.common import openssl
|
from keystone.common import openssl
|
||||||
from keystone import exception
|
|
||||||
from keystone.tests import unit
|
from keystone.tests import unit
|
||||||
|
from keystone.tests.unit import ksfixtures
|
||||||
from keystone.tests.unit import rest
|
from keystone.tests.unit import rest
|
||||||
from keystone import token
|
|
||||||
|
|
||||||
|
|
||||||
SSLDIR = unit.dirs.tmp('ssl')
|
SSLDIR = unit.dirs.tmp('ssl')
|
||||||
@ -60,23 +59,14 @@ class CertSetupTestCase(rest.RestfulTestCase):
|
|||||||
ca_certs=ca_certs,
|
ca_certs=ca_certs,
|
||||||
ca_key=ca_key,
|
ca_key=ca_key,
|
||||||
keyfile=os.path.join(KEYDIR, 'signing_key.pem'))
|
keyfile=os.path.join(KEYDIR, 'signing_key.pem'))
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
self.config_fixture.config(group='token', provider='fernet')
|
||||||
|
self.useFixture(
|
||||||
def test_can_handle_missing_certs(self):
|
ksfixtures.KeyRepository(
|
||||||
controller = token.controllers.Auth()
|
self.config_fixture,
|
||||||
|
'fernet_tokens',
|
||||||
self.config_fixture.config(group='signing', certfile='invalid')
|
CONF.fernet_tokens.max_active_keys
|
||||||
user = unit.create_user(self.identity_api,
|
)
|
||||||
domain_id=CONF.identity.default_domain_id)
|
)
|
||||||
body_dict = {
|
|
||||||
'passwordCredentials': {
|
|
||||||
'userId': user['id'],
|
|
||||||
'password': user['password'],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
self.assertRaises(exception.UnexpectedError,
|
|
||||||
controller.authenticate,
|
|
||||||
self.make_request(), body_dict)
|
|
||||||
|
|
||||||
def test_create_pki_certs(self, rebuild=False):
|
def test_create_pki_certs(self, rebuild=False):
|
||||||
pki = openssl.ConfigurePKI(None, None, rebuild=rebuild)
|
pki = openssl.ConfigurePKI(None, None, rebuild=rebuild)
|
||||||
|
@ -23,7 +23,6 @@ from keystone import exception
|
|||||||
from keystone.models import revoke_model
|
from keystone.models import revoke_model
|
||||||
from keystone.revoke.backends import sql
|
from keystone.revoke.backends import sql
|
||||||
from keystone.tests import unit
|
from keystone.tests import unit
|
||||||
from keystone.tests.unit import test_backend_sql
|
|
||||||
from keystone.token.providers import common
|
from keystone.token.providers import common
|
||||||
|
|
||||||
|
|
||||||
@ -367,15 +366,6 @@ class RevokeTests(object):
|
|||||||
token_values)
|
token_values)
|
||||||
|
|
||||||
|
|
||||||
class SqlRevokeTests(test_backend_sql.SqlTests, RevokeTests):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(SqlRevokeTests, self).config_overrides()
|
|
||||||
self.config_fixture.config(
|
|
||||||
group='token',
|
|
||||||
provider='pki',
|
|
||||||
revoke_by_id=False)
|
|
||||||
|
|
||||||
|
|
||||||
def add_event(events, event):
|
def add_event(events, event):
|
||||||
events.append(event)
|
events.append(event)
|
||||||
return event
|
return event
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from six.moves import reload_module
|
|
||||||
|
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import utils
|
from keystone.common import utils
|
||||||
@ -26,8 +25,6 @@ from keystone.tests.unit import ksfixtures
|
|||||||
from keystone.tests.unit.ksfixtures import database
|
from keystone.tests.unit.ksfixtures import database
|
||||||
from keystone import token
|
from keystone import token
|
||||||
from keystone.token.providers import fernet
|
from keystone.token.providers import fernet
|
||||||
from keystone.token.providers import pki
|
|
||||||
from keystone.token.providers import pkiz
|
|
||||||
from keystone.token.providers import uuid
|
from keystone.token.providers import uuid
|
||||||
|
|
||||||
|
|
||||||
@ -759,14 +756,6 @@ class TestTokenProvider(unit.TestCase):
|
|||||||
self.config_fixture.config(group='token', provider='uuid')
|
self.config_fixture.config(group='token', provider='uuid')
|
||||||
self.assertIsInstance(token.provider.Manager().driver, uuid.Provider)
|
self.assertIsInstance(token.provider.Manager().driver, uuid.Provider)
|
||||||
|
|
||||||
dependency.reset()
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
self.assertIsInstance(token.provider.Manager().driver, pki.Provider)
|
|
||||||
|
|
||||||
dependency.reset()
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
self.assertIsInstance(token.provider.Manager().driver, pkiz.Provider)
|
|
||||||
|
|
||||||
dependency.reset()
|
dependency.reset()
|
||||||
self.config_fixture.config(group='token', provider='fernet')
|
self.config_fixture.config(group='token', provider='fernet')
|
||||||
self.assertIsInstance(token.provider.Manager().driver, fernet.Provider)
|
self.assertIsInstance(token.provider.Manager().driver, fernet.Provider)
|
||||||
@ -797,42 +786,3 @@ class TestTokenProvider(unit.TestCase):
|
|||||||
exception.TokenNotFound,
|
exception.TokenNotFound,
|
||||||
self.token_provider_api.validate_token,
|
self.token_provider_api.validate_token,
|
||||||
None)
|
None)
|
||||||
|
|
||||||
|
|
||||||
# NOTE(ayoung): renamed to avoid automatic test detection
|
|
||||||
class PKIProviderTests(object):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(PKIProviderTests, self).setUp()
|
|
||||||
|
|
||||||
from keystoneclient.common import cms
|
|
||||||
self.cms = cms
|
|
||||||
|
|
||||||
old_cms_subprocess = cms.subprocess
|
|
||||||
self.addCleanup(setattr, cms, 'subprocess', old_cms_subprocess)
|
|
||||||
|
|
||||||
self.cms.subprocess = self.target_subprocess
|
|
||||||
|
|
||||||
# force module reload so the imports get re-evaluated
|
|
||||||
reload_module(pki)
|
|
||||||
|
|
||||||
def test_get_token_id_error_handling(self):
|
|
||||||
# cause command-line failure
|
|
||||||
self.config_fixture.config(group='signing',
|
|
||||||
keyfile='--please-break-me')
|
|
||||||
|
|
||||||
provider = pki.Provider()
|
|
||||||
token_data = {}
|
|
||||||
self.assertRaises(exception.UnexpectedError,
|
|
||||||
provider._get_token_id,
|
|
||||||
token_data)
|
|
||||||
|
|
||||||
|
|
||||||
class TestPKIProviderWithStdlib(PKIProviderTests, unit.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
# force keystoneclient.common.cms to use the stdlib subprocess
|
|
||||||
import subprocess
|
|
||||||
self.target_subprocess = subprocess
|
|
||||||
|
|
||||||
super(TestPKIProviderWithStdlib, self).setUp()
|
|
||||||
|
@ -12,14 +12,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import time
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from keystoneclient.common import cms
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
import six
|
import six
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
from testtools import matchers
|
|
||||||
|
|
||||||
from keystone.common import extension as keystone_extension
|
from keystone.common import extension as keystone_extension
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
@ -1226,68 +1222,6 @@ class V2TestCase(object):
|
|||||||
def assertValidRevocationListResponse(self, response):
|
def assertValidRevocationListResponse(self, response):
|
||||||
self.assertIsNotNone(response.result['signed'])
|
self.assertIsNotNone(response.result['signed'])
|
||||||
|
|
||||||
def _fetch_parse_revocation_list(self):
|
|
||||||
|
|
||||||
token1 = self.get_scoped_token()
|
|
||||||
|
|
||||||
# TODO(morganfainberg): Because this is making a restful call to the
|
|
||||||
# app a change to UTCNOW via mock.patch will not affect the returned
|
|
||||||
# token. The only surefire way to ensure there is not a transient bug
|
|
||||||
# based upon when the second token is issued is with a sleep. This
|
|
||||||
# issue all stems from the limited resolution (no microseconds) on the
|
|
||||||
# expiry time of tokens and the way revocation events utilizes token
|
|
||||||
# expiry to revoke individual tokens. This is a stop-gap until all
|
|
||||||
# associated issues with resolution on expiration and revocation events
|
|
||||||
# are resolved.
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
token2 = self.get_scoped_token()
|
|
||||||
|
|
||||||
self.admin_request(method='DELETE',
|
|
||||||
path='/v2.0/tokens/%s' % token2,
|
|
||||||
token=token1)
|
|
||||||
|
|
||||||
r = self.admin_request(
|
|
||||||
method='GET',
|
|
||||||
path='/v2.0/tokens/revoked',
|
|
||||||
token=token1,
|
|
||||||
expected_status=http_client.OK)
|
|
||||||
signed_text = r.result['signed']
|
|
||||||
|
|
||||||
data_json = cms.cms_verify(signed_text, CONF.signing.certfile,
|
|
||||||
CONF.signing.ca_certs)
|
|
||||||
|
|
||||||
data = jsonutils.loads(data_json)
|
|
||||||
|
|
||||||
return (data, token2)
|
|
||||||
|
|
||||||
def test_fetch_revocation_list_md5(self):
|
|
||||||
"""Hash for tokens in revocation list and server config should match.
|
|
||||||
|
|
||||||
If the server is configured for md5, then the revocation list has
|
|
||||||
tokens hashed with MD5.
|
|
||||||
"""
|
|
||||||
# The default hash algorithm is md5.
|
|
||||||
hash_algorithm = 'md5'
|
|
||||||
|
|
||||||
(data, token) = self._fetch_parse_revocation_list()
|
|
||||||
token_hash = cms.cms_hash_token(token, mode=hash_algorithm)
|
|
||||||
self.assertThat(token_hash, matchers.Equals(data['revoked'][0]['id']))
|
|
||||||
|
|
||||||
def test_fetch_revocation_list_sha256(self):
|
|
||||||
"""Hash for tokens in revocation list and server config should match.
|
|
||||||
|
|
||||||
If the server is configured for sha256, then the revocation list has
|
|
||||||
tokens hashed with SHA256.
|
|
||||||
"""
|
|
||||||
hash_algorithm = 'sha256'
|
|
||||||
self.config_fixture.config(group='token',
|
|
||||||
hash_algorithm=hash_algorithm)
|
|
||||||
|
|
||||||
(data, token) = self._fetch_parse_revocation_list()
|
|
||||||
token_hash = cms.cms_hash_token(token, mode=hash_algorithm)
|
|
||||||
self.assertThat(token_hash, matchers.Equals(data['revoked'][0]['id']))
|
|
||||||
|
|
||||||
def test_create_update_user_invalid_enabled_type(self):
|
def test_create_update_user_invalid_enabled_type(self):
|
||||||
# Enforce usage of boolean for 'enabled' field
|
# Enforce usage of boolean for 'enabled' field
|
||||||
token = self.get_scoped_token()
|
token = self.get_scoped_token()
|
||||||
@ -1467,25 +1401,6 @@ class V2TestCaseFernet(V2TestCase, RestfulTestCase, CoreApiTests,
|
|||||||
self.skipTest('Revocation lists do not support Fernet')
|
self.skipTest('Revocation lists do not support Fernet')
|
||||||
|
|
||||||
|
|
||||||
class RevokeApiTestCase(V2TestCase, RestfulTestCase, CoreApiTests,
|
|
||||||
LegacyV2UsernameTests):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(RevokeApiTestCase, self).config_overrides()
|
|
||||||
self.config_fixture.config(
|
|
||||||
group='token',
|
|
||||||
provider='pki',
|
|
||||||
revoke_by_id=False)
|
|
||||||
|
|
||||||
def test_fetch_revocation_list_admin_200(self):
|
|
||||||
self.skip_test_overrides('Revoke API disables revocation_list.')
|
|
||||||
|
|
||||||
def test_fetch_revocation_list_md5(self):
|
|
||||||
self.skip_test_overrides('Revoke API disables revocation_list.')
|
|
||||||
|
|
||||||
def test_fetch_revocation_list_sha256(self):
|
|
||||||
self.skip_test_overrides('Revoke API disables revocation_list.')
|
|
||||||
|
|
||||||
|
|
||||||
class TestFernetTokenProviderV2(RestfulTestCase):
|
class TestFernetTokenProviderV2(RestfulTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -1409,8 +1409,6 @@ class TokenAPITests(object):
|
|||||||
v3_token_data['token']['expires_at'])
|
v3_token_data['token']['expires_at'])
|
||||||
|
|
||||||
def test_v3_v2_token_intermix(self):
|
def test_v3_v2_token_intermix(self):
|
||||||
# FIXME(gyee): PKI tokens are not interchangeable because token
|
|
||||||
# data is baked into the token itself.
|
|
||||||
r = self.v3_create_token(self.build_authentication_request(
|
r = self.v3_create_token(self.build_authentication_request(
|
||||||
user_id=self.default_domain_user['id'],
|
user_id=self.default_domain_user['id'],
|
||||||
password=self.default_domain_user['password'],
|
password=self.default_domain_user['password'],
|
||||||
@ -2426,74 +2424,6 @@ class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase):
|
|||||||
expected_status=http_client.FORBIDDEN)
|
expected_status=http_client.FORBIDDEN)
|
||||||
|
|
||||||
|
|
||||||
class TestPKITokenAPIs(test_v3.RestfulTestCase, TokenAPITests, TokenDataTests):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(TestPKITokenAPIs, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestPKITokenAPIs, self).setUp()
|
|
||||||
self.doSetUp()
|
|
||||||
|
|
||||||
def verify_token(self, *args, **kwargs):
|
|
||||||
return cms.verify_token(*args, **kwargs)
|
|
||||||
|
|
||||||
def test_v3_token_id(self):
|
|
||||||
auth_data = self.build_authentication_request(
|
|
||||||
user_id=self.user['id'],
|
|
||||||
password=self.user['password'])
|
|
||||||
resp = self.v3_create_token(auth_data)
|
|
||||||
token_data = resp.result
|
|
||||||
token_id = resp.headers.get('X-Subject-Token')
|
|
||||||
self.assertIn('expires_at', token_data['token'])
|
|
||||||
|
|
||||||
decoded_token = self.verify_token(token_id, CONF.signing.certfile,
|
|
||||||
CONF.signing.ca_certs)
|
|
||||||
|
|
||||||
decoded_token_dict = json.loads(decoded_token)
|
|
||||||
token_resp_dict = json.loads(resp.body)
|
|
||||||
|
|
||||||
self.assertEqual(decoded_token_dict, token_resp_dict)
|
|
||||||
# should be able to validate hash PKI token as well
|
|
||||||
hash_token_id = cms.cms_hash_token(token_id)
|
|
||||||
headers = {'X-Subject-Token': hash_token_id}
|
|
||||||
resp = self.get('/auth/tokens', headers=headers)
|
|
||||||
expected_token_data = resp.result
|
|
||||||
self.assertDictEqual(expected_token_data, token_data)
|
|
||||||
|
|
||||||
def test_v3_v2_hashed_pki_token_intermix(self):
|
|
||||||
auth_data = self.build_authentication_request(
|
|
||||||
user_id=self.default_domain_user['id'],
|
|
||||||
password=self.default_domain_user['password'],
|
|
||||||
project_id=self.default_domain_project['id'])
|
|
||||||
resp = self.v3_create_token(auth_data)
|
|
||||||
token_data = resp.result
|
|
||||||
token = resp.headers.get('X-Subject-Token')
|
|
||||||
|
|
||||||
# should be able to validate a hash PKI token in v2 too
|
|
||||||
token = cms.cms_hash_token(token)
|
|
||||||
path = '/v2.0/tokens/%s' % (token)
|
|
||||||
resp = self.admin_request(path=path,
|
|
||||||
token=self.get_admin_token(),
|
|
||||||
method='GET')
|
|
||||||
v2_token = resp.result
|
|
||||||
self.assertEqual(v2_token['access']['user']['id'],
|
|
||||||
token_data['token']['user']['id'])
|
|
||||||
self.assertTimestampEqual(v2_token['access']['token']['expires'],
|
|
||||||
token_data['token']['expires_at'])
|
|
||||||
self.assertEqual(v2_token['access']['user']['roles'][0]['name'],
|
|
||||||
token_data['token']['roles'][0]['name'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestPKIZTokenAPIs(TestPKITokenAPIs):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(TestPKIZTokenAPIs, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
|
|
||||||
def verify_token(self, *args, **kwargs):
|
|
||||||
return cms.pkiz_verify(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
||||||
TokenDataTests):
|
TokenDataTests):
|
||||||
def config_overrides(self):
|
def config_overrides(self):
|
||||||
@ -2510,9 +2440,7 @@ class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
|||||||
password=self.user['password'])
|
password=self.user['password'])
|
||||||
resp = self.v3_create_token(auth_data)
|
resp = self.v3_create_token(auth_data)
|
||||||
token_data = resp.result
|
token_data = resp.result
|
||||||
token_id = resp.headers.get('X-Subject-Token')
|
|
||||||
self.assertIn('expires_at', token_data['token'])
|
self.assertIn('expires_at', token_data['token'])
|
||||||
self.assertFalse(cms.is_asn1_token(token_id))
|
|
||||||
|
|
||||||
|
|
||||||
class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
||||||
@ -2761,8 +2689,15 @@ class TestTokenRevokeById(test_v3.RestfulTestCase):
|
|||||||
super(TestTokenRevokeById, self).config_overrides()
|
super(TestTokenRevokeById, self).config_overrides()
|
||||||
self.config_fixture.config(
|
self.config_fixture.config(
|
||||||
group='token',
|
group='token',
|
||||||
provider='pki',
|
provider='fernet',
|
||||||
revoke_by_id=False)
|
revoke_by_id=False)
|
||||||
|
self.useFixture(
|
||||||
|
ksfixtures.KeyRepository(
|
||||||
|
self.config_fixture,
|
||||||
|
'fernet_tokens',
|
||||||
|
CONF.fernet_tokens.max_active_keys
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Setup for Token Revoking Test Cases.
|
"""Setup for Token Revoking Test Cases.
|
||||||
@ -3507,8 +3442,15 @@ class TestTokenRevokeApi(TestTokenRevokeById):
|
|||||||
super(TestTokenRevokeApi, self).config_overrides()
|
super(TestTokenRevokeApi, self).config_overrides()
|
||||||
self.config_fixture.config(
|
self.config_fixture.config(
|
||||||
group='token',
|
group='token',
|
||||||
provider='pki',
|
provider='fernet',
|
||||||
revoke_by_id=False)
|
revoke_by_id=False)
|
||||||
|
self.useFixture(
|
||||||
|
ksfixtures.KeyRepository(
|
||||||
|
self.config_fixture,
|
||||||
|
'fernet_tokens',
|
||||||
|
CONF.fernet_tokens.max_active_keys
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def assertValidDeletedProjectResponse(self, events_response, project_id):
|
def assertValidDeletedProjectResponse(self, events_response, project_id):
|
||||||
events = events_response['events']
|
events = events_response['events']
|
||||||
@ -3772,24 +3714,6 @@ class TestAuthExternalDomainBehaviorWithUUID(AuthExternalDomainBehavior,
|
|||||||
self.config_fixture.config(group='token', provider='uuid')
|
self.config_fixture.config(group='token', provider='uuid')
|
||||||
|
|
||||||
|
|
||||||
class TestAuthExternalDomainBehaviorWithPKI(AuthExternalDomainBehavior,
|
|
||||||
test_v3.RestfulTestCase):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(TestAuthExternalDomainBehaviorWithPKI, self).config_overrides()
|
|
||||||
self.kerberos = False
|
|
||||||
self.auth_plugin_config_override(external='Domain')
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
|
|
||||||
|
|
||||||
class TestAuthExternalDomainBehaviorWithPKIZ(AuthExternalDomainBehavior,
|
|
||||||
test_v3.RestfulTestCase):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(TestAuthExternalDomainBehaviorWithPKIZ, self).config_overrides()
|
|
||||||
self.kerberos = False
|
|
||||||
self.auth_plugin_config_override(external='Domain')
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE(lbragstad): The Fernet token provider doesn't support bind
|
# NOTE(lbragstad): The Fernet token provider doesn't support bind
|
||||||
# authentication so we don't inhereit TestAuthExternalDomain here to test it.
|
# authentication so we don't inhereit TestAuthExternalDomain here to test it.
|
||||||
|
|
||||||
@ -3858,22 +3782,6 @@ class UUIDAuthExternalDefaultDomain(TestAuthExternalDefaultDomain,
|
|||||||
self.config_fixture.config(group='token', provider='uuid')
|
self.config_fixture.config(group='token', provider='uuid')
|
||||||
|
|
||||||
|
|
||||||
class PKIAuthExternalDefaultDomain(TestAuthExternalDefaultDomain,
|
|
||||||
test_v3.RestfulTestCase):
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIAuthExternalDefaultDomain, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
|
|
||||||
|
|
||||||
class PKIZAuthExternalDefaultDomain(TestAuthExternalDefaultDomain,
|
|
||||||
test_v3.RestfulTestCase):
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIZAuthExternalDefaultDomain, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
|
|
||||||
|
|
||||||
class UUIDAuthKerberos(AuthExternalDomainBehavior, test_v3.RestfulTestCase):
|
class UUIDAuthKerberos(AuthExternalDomainBehavior, test_v3.RestfulTestCase):
|
||||||
|
|
||||||
def config_overrides(self):
|
def config_overrides(self):
|
||||||
@ -3884,26 +3792,6 @@ class UUIDAuthKerberos(AuthExternalDomainBehavior, test_v3.RestfulTestCase):
|
|||||||
methods=['kerberos', 'password', 'token'])
|
methods=['kerberos', 'password', 'token'])
|
||||||
|
|
||||||
|
|
||||||
class PKIAuthKerberos(AuthExternalDomainBehavior, test_v3.RestfulTestCase):
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIAuthKerberos, self).config_overrides()
|
|
||||||
self.kerberos = True
|
|
||||||
self.config_fixture.config(group='token', provider='pki')
|
|
||||||
self.auth_plugin_config_override(
|
|
||||||
methods=['kerberos', 'password', 'token'])
|
|
||||||
|
|
||||||
|
|
||||||
class PKIZAuthKerberos(AuthExternalDomainBehavior, test_v3.RestfulTestCase):
|
|
||||||
|
|
||||||
def config_overrides(self):
|
|
||||||
super(PKIZAuthKerberos, self).config_overrides()
|
|
||||||
self.kerberos = True
|
|
||||||
self.config_fixture.config(group='token', provider='pkiz')
|
|
||||||
self.auth_plugin_config_override(
|
|
||||||
methods=['kerberos', 'password', 'token'])
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE(lbragstad): The Fernet token provider doesn't support bind
|
# NOTE(lbragstad): The Fernet token provider doesn't support bind
|
||||||
# authentication so we don't inherit AuthExternalDomainBehavior here to test
|
# authentication so we don't inherit AuthExternalDomainBehavior here to test
|
||||||
# it.
|
# it.
|
||||||
@ -4991,26 +4879,6 @@ class TestAuthSpecificData(test_v3.RestfulTestCase):
|
|||||||
self.assertValidDomainListResponse(r)
|
self.assertValidDomainListResponse(r)
|
||||||
|
|
||||||
|
|
||||||
class TestTrustAuthPKITokenProvider(TrustAPIBehavior, TestTrustChain):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(TestTrustAuthPKITokenProvider, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token',
|
|
||||||
provider='pki',
|
|
||||||
revoke_by_id=False)
|
|
||||||
self.config_fixture.config(group='trust',
|
|
||||||
enabled=True)
|
|
||||||
|
|
||||||
|
|
||||||
class TestTrustAuthPKIZTokenProvider(TrustAPIBehavior, TestTrustChain):
|
|
||||||
def config_overrides(self):
|
|
||||||
super(TestTrustAuthPKIZTokenProvider, self).config_overrides()
|
|
||||||
self.config_fixture.config(group='token',
|
|
||||||
provider='pkiz',
|
|
||||||
revoke_by_id=False)
|
|
||||||
self.config_fixture.config(group='trust',
|
|
||||||
enabled=True)
|
|
||||||
|
|
||||||
|
|
||||||
class TestTrustAuthFernetTokenProvider(TrustAPIBehavior, TestTrustChain):
|
class TestTrustAuthFernetTokenProvider(TrustAPIBehavior, TestTrustChain):
|
||||||
def config_overrides(self):
|
def config_overrides(self):
|
||||||
super(TestTrustAuthFernetTokenProvider, self).config_overrides()
|
super(TestTrustAuthFernetTokenProvider, self).config_overrides()
|
||||||
|
@ -12,10 +12,8 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from keystoneclient.common import cms
|
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
@ -32,13 +30,7 @@ NULL_OBJECT = object()
|
|||||||
|
|
||||||
class TokenTests(object):
|
class TokenTests(object):
|
||||||
def _create_token_id(self):
|
def _create_token_id(self):
|
||||||
# Use a token signed by the cms module
|
return uuid.uuid4().hex
|
||||||
token_id = ""
|
|
||||||
for i in range(1, 20):
|
|
||||||
token_id += uuid.uuid4().hex
|
|
||||||
return cms.cms_sign_token(token_id,
|
|
||||||
CONF.signing.certfile,
|
|
||||||
CONF.signing.keyfile)
|
|
||||||
|
|
||||||
def _assert_revoked_token_list_matches_token_persistence(
|
def _assert_revoked_token_list_matches_token_persistence(
|
||||||
self, revoked_token_id_list):
|
self, revoked_token_id_list):
|
||||||
@ -367,30 +359,6 @@ class TokenTests(object):
|
|||||||
self.assertIn(token_id, revoked_ids)
|
self.assertIn(token_id, revoked_ids)
|
||||||
self.assertIn(token2_id, revoked_ids)
|
self.assertIn(token2_id, revoked_ids)
|
||||||
|
|
||||||
def _test_predictable_revoked_pki_token_id(self, hash_fn):
|
|
||||||
token_id = self._create_token_id()
|
|
||||||
token_id_hash = hash_fn(token_id.encode('utf-8')).hexdigest()
|
|
||||||
token = {'user': {'id': uuid.uuid4().hex},
|
|
||||||
'token_data': {'token': {'audit_ids': [uuid.uuid4().hex]}}}
|
|
||||||
|
|
||||||
self.token_provider_api._persistence.create_token(token_id, token)
|
|
||||||
self.token_provider_api._persistence.delete_token(token_id)
|
|
||||||
|
|
||||||
revoked_ids = [x['id']
|
|
||||||
for x in self.token_provider_api.list_revoked_tokens()]
|
|
||||||
self._assert_revoked_token_list_matches_token_persistence(revoked_ids)
|
|
||||||
self.assertIn(token_id_hash, revoked_ids)
|
|
||||||
self.assertNotIn(token_id, revoked_ids)
|
|
||||||
for t in self.token_provider_api._persistence.list_revoked_tokens():
|
|
||||||
self.assertIn('expires', t)
|
|
||||||
|
|
||||||
def test_predictable_revoked_pki_token_id_default(self):
|
|
||||||
self._test_predictable_revoked_pki_token_id(hashlib.md5)
|
|
||||||
|
|
||||||
def test_predictable_revoked_pki_token_id_sha256(self):
|
|
||||||
self.config_fixture.config(group='token', hash_algorithm='sha256')
|
|
||||||
self._test_predictable_revoked_pki_token_id(hashlib.sha256)
|
|
||||||
|
|
||||||
def test_predictable_revoked_uuid_token_id(self):
|
def test_predictable_revoked_uuid_token_id(self):
|
||||||
token_id = uuid.uuid4().hex
|
token_id = uuid.uuid4().hex
|
||||||
token = {'user': {'id': uuid.uuid4().hex},
|
token = {'user': {'id': uuid.uuid4().hex},
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
# 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 keystone.tests import unit
|
|
||||||
from keystone.token.providers import pki
|
|
||||||
|
|
||||||
|
|
||||||
class TestPkiTokenProvider(unit.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestPkiTokenProvider, self).setUp()
|
|
||||||
self.provider = pki.Provider()
|
|
||||||
|
|
||||||
def test_supports_bind_authentication_returns_true(self):
|
|
||||||
self.assertTrue(self.provider._supports_bind_authentication)
|
|
||||||
|
|
||||||
def test_need_persistence_return_true(self):
|
|
||||||
self.assertIs(True, self.provider.needs_persistence())
|
|
@ -1,26 +0,0 @@
|
|||||||
# 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 keystone.tests import unit
|
|
||||||
from keystone.token.providers import pkiz
|
|
||||||
|
|
||||||
|
|
||||||
class TestPkizTokenProvider(unit.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestPkizTokenProvider, self).setUp()
|
|
||||||
self.provider = pkiz.Provider()
|
|
||||||
|
|
||||||
def test_supports_bind_authentication_returns_true(self):
|
|
||||||
self.assertTrue(self.provider._supports_bind_authentication)
|
|
||||||
|
|
||||||
def test_need_persistence_return_true(self):
|
|
||||||
self.assertIs(True, self.provider.needs_persistence())
|
|
@ -26,7 +26,6 @@ from keystone.common import manager
|
|||||||
import keystone.conf
|
import keystone.conf
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _LW
|
from keystone.i18n import _LW
|
||||||
from keystone.token import utils
|
|
||||||
|
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
CONF = keystone.conf.CONF
|
||||||
@ -52,7 +51,7 @@ class PersistenceManager(manager.Manager):
|
|||||||
super(PersistenceManager, self).__init__(CONF.token.driver)
|
super(PersistenceManager, self).__init__(CONF.token.driver)
|
||||||
|
|
||||||
def get_token(self, token_id):
|
def get_token(self, token_id):
|
||||||
return self._get_token(utils.generate_unique_id(token_id))
|
return self._get_token(token_id)
|
||||||
|
|
||||||
@MEMOIZE
|
@MEMOIZE
|
||||||
def _get_token(self, token_id):
|
def _get_token(self, token_id):
|
||||||
@ -60,23 +59,21 @@ class PersistenceManager(manager.Manager):
|
|||||||
return self.driver.get_token(token_id)
|
return self.driver.get_token(token_id)
|
||||||
|
|
||||||
def create_token(self, token_id, data):
|
def create_token(self, token_id, data):
|
||||||
unique_id = utils.generate_unique_id(token_id)
|
|
||||||
data_copy = copy.deepcopy(data)
|
data_copy = copy.deepcopy(data)
|
||||||
data_copy['id'] = unique_id
|
data_copy['id'] = token_id
|
||||||
ret = self.driver.create_token(unique_id, data_copy)
|
ret = self.driver.create_token(token_id, data_copy)
|
||||||
if MEMOIZE.should_cache(ret):
|
if MEMOIZE.should_cache(ret):
|
||||||
# NOTE(morganfainberg): when doing a cache set, you must pass the
|
# NOTE(morganfainberg): when doing a cache set, you must pass the
|
||||||
# same arguments through, the same as invalidate (this includes
|
# same arguments through, the same as invalidate (this includes
|
||||||
# "self"). First argument is always the value to be cached
|
# "self"). First argument is always the value to be cached
|
||||||
self._get_token.set(ret, self, unique_id)
|
self._get_token.set(ret, self, token_id)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def delete_token(self, token_id):
|
def delete_token(self, token_id):
|
||||||
if not CONF.token.revoke_by_id:
|
if not CONF.token.revoke_by_id:
|
||||||
return
|
return
|
||||||
unique_id = utils.generate_unique_id(token_id)
|
self.driver.delete_token(token_id)
|
||||||
self.driver.delete_token(unique_id)
|
self._invalidate_individual_token_cache(token_id)
|
||||||
self._invalidate_individual_token_cache(unique_id)
|
|
||||||
self.invalidate_revocation_list()
|
self.invalidate_revocation_list()
|
||||||
|
|
||||||
def delete_tokens(self, user_id, tenant_id=None, trust_id=None,
|
def delete_tokens(self, user_id, tenant_id=None, trust_id=None,
|
||||||
@ -86,8 +83,7 @@ class PersistenceManager(manager.Manager):
|
|||||||
token_list = self.driver.delete_tokens(user_id, tenant_id, trust_id,
|
token_list = self.driver.delete_tokens(user_id, tenant_id, trust_id,
|
||||||
consumer_id)
|
consumer_id)
|
||||||
for token_id in token_list:
|
for token_id in token_list:
|
||||||
unique_id = utils.generate_unique_id(token_id)
|
self._invalidate_individual_token_cache(token_id)
|
||||||
self._invalidate_individual_token_cache(unique_id)
|
|
||||||
self.invalidate_revocation_list()
|
self.invalidate_revocation_list()
|
||||||
|
|
||||||
@REVOCATION_MEMOIZE
|
@REVOCATION_MEMOIZE
|
||||||
|
@ -29,7 +29,6 @@ from keystone.i18n import _, _LE
|
|||||||
from keystone.models import token_model
|
from keystone.models import token_model
|
||||||
from keystone import notifications
|
from keystone import notifications
|
||||||
from keystone.token import persistence
|
from keystone.token import persistence
|
||||||
from keystone.token import utils
|
|
||||||
|
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
CONF = keystone.conf.CONF
|
||||||
@ -166,10 +165,7 @@ class Manager(manager.Manager):
|
|||||||
# Otherwise the information about the token must be in the token
|
# Otherwise the information about the token must be in the token
|
||||||
# id.
|
# id.
|
||||||
if self._needs_persistence:
|
if self._needs_persistence:
|
||||||
unique_id = utils.generate_unique_id(token_id)
|
token_ref = self._persistence.get_token(token_id)
|
||||||
# NOTE(morganfainberg): Ensure we never use the long-form
|
|
||||||
# token_id (PKI) as part of the cache_key.
|
|
||||||
token_ref = self._persistence.get_token(unique_id)
|
|
||||||
# Overload the token_id variable to be a token reference
|
# Overload the token_id variable to be a token reference
|
||||||
# instead.
|
# instead.
|
||||||
token_id = token_ref
|
token_id = token_ref
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
# Copyright 2013 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Keystone PKI Token Provider."""
|
|
||||||
|
|
||||||
import subprocess # nosec : used to catch subprocess exceptions
|
|
||||||
|
|
||||||
from keystoneclient.common import cms
|
|
||||||
from oslo_log import log
|
|
||||||
from oslo_log import versionutils
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from keystone.common import utils
|
|
||||||
import keystone.conf
|
|
||||||
from keystone import exception
|
|
||||||
from keystone.i18n import _, _LE
|
|
||||||
from keystone.token.providers import common
|
|
||||||
|
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
@versionutils.deprecated(
|
|
||||||
as_of=versionutils.deprecated.MITAKA,
|
|
||||||
what='the PKI token provider',
|
|
||||||
in_favor_of='the Fernet or UUID token providers')
|
|
||||||
class Provider(common.BaseProvider):
|
|
||||||
def _get_token_id(self, token_data):
|
|
||||||
try:
|
|
||||||
# force conversion to a string as the keystone client cms code
|
|
||||||
# produces unicode. This can be removed if the client returns
|
|
||||||
# str()
|
|
||||||
# TODO(ayoung): Make to a byte_str for Python3
|
|
||||||
token_json = jsonutils.dumps(token_data, cls=utils.PKIEncoder)
|
|
||||||
token_id = str(cms.cms_sign_token(token_json,
|
|
||||||
CONF.signing.certfile,
|
|
||||||
CONF.signing.keyfile))
|
|
||||||
return token_id
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
LOG.exception(_LE('Unable to sign token'))
|
|
||||||
raise exception.UnexpectedError(_(
|
|
||||||
'Unable to sign token.'))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _supports_bind_authentication(self):
|
|
||||||
"""Return if the token provider supports bind authentication methods.
|
|
||||||
|
|
||||||
:returns: True
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
def needs_persistence(self):
|
|
||||||
"""Should the token be written to a backend."""
|
|
||||||
return True
|
|
@ -1,65 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
"""Keystone Compressed PKI Token Provider."""
|
|
||||||
|
|
||||||
import subprocess # nosec : used to catch subprocess exceptions
|
|
||||||
|
|
||||||
from keystoneclient.common import cms
|
|
||||||
from oslo_log import log
|
|
||||||
from oslo_log import versionutils
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from keystone.common import utils
|
|
||||||
import keystone.conf
|
|
||||||
from keystone import exception
|
|
||||||
from keystone.i18n import _
|
|
||||||
from keystone.token.providers import common
|
|
||||||
|
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
|
||||||
ERROR_MESSAGE = _('Unable to sign token.')
|
|
||||||
|
|
||||||
|
|
||||||
@versionutils.deprecated(
|
|
||||||
as_of=versionutils.deprecated.MITAKA,
|
|
||||||
what='the PKIZ token provider',
|
|
||||||
in_favor_of='the Fernet or UUID token providers')
|
|
||||||
class Provider(common.BaseProvider):
|
|
||||||
def _get_token_id(self, token_data):
|
|
||||||
try:
|
|
||||||
# force conversion to a string as the keystone client cms code
|
|
||||||
# produces unicode. This can be removed if the client returns
|
|
||||||
# str()
|
|
||||||
# TODO(ayoung): Make to a byte_str for Python3
|
|
||||||
token_json = jsonutils.dumps(token_data, cls=utils.PKIEncoder)
|
|
||||||
token_id = str(cms.pkiz_sign(token_json,
|
|
||||||
CONF.signing.certfile,
|
|
||||||
CONF.signing.keyfile))
|
|
||||||
return token_id
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
LOG.exception(ERROR_MESSAGE)
|
|
||||||
raise exception.UnexpectedError(ERROR_MESSAGE)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _supports_bind_authentication(self):
|
|
||||||
"""Return if the token provider supports bind authentication methods.
|
|
||||||
|
|
||||||
:returns: True
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
def needs_persistence(self):
|
|
||||||
"""Should the token be written to a backend."""
|
|
||||||
return True
|
|
@ -1,31 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
import keystone.conf
|
|
||||||
|
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
|
||||||
|
|
||||||
|
|
||||||
def generate_unique_id(token_id):
|
|
||||||
"""Return a unique ID for a token.
|
|
||||||
|
|
||||||
The returned value is useful as the primary key of a database table,
|
|
||||||
memcache store, or other lookup table.
|
|
||||||
|
|
||||||
:returns: Given a PKI token, returns it's hashed value. Otherwise,
|
|
||||||
returns the passed-in value (such as a UUID token ID or an
|
|
||||||
existing hash).
|
|
||||||
"""
|
|
||||||
return cms.cms_hash_token(token_id, mode=CONF.token.hash_algorithm)
|
|
@ -163,8 +163,6 @@ keystone.token.persistence =
|
|||||||
keystone.token.provider =
|
keystone.token.provider =
|
||||||
fernet = keystone.token.providers.fernet:Provider
|
fernet = keystone.token.providers.fernet:Provider
|
||||||
uuid = keystone.token.providers.uuid:Provider
|
uuid = keystone.token.providers.uuid:Provider
|
||||||
pki = keystone.token.providers.pki:Provider
|
|
||||||
pkiz = keystone.token.providers.pkiz:Provider
|
|
||||||
|
|
||||||
keystone.trust =
|
keystone.trust =
|
||||||
sql = keystone.trust.backends.sql:Trust
|
sql = keystone.trust.backends.sql:Trust
|
||||||
|
2
tox.ini
2
tox.ini
@ -32,7 +32,7 @@ commands =
|
|||||||
flake8
|
flake8
|
||||||
# Run bash8 during pep8 runs to ensure violations are caught by
|
# Run bash8 during pep8 runs to ensure violations are caught by
|
||||||
# the check and gate queues
|
# the check and gate queues
|
||||||
bashate examples/pki/gen_pki.sh devstack/plugin.sh
|
bashate devstack/plugin.sh
|
||||||
# Run security linter
|
# Run security linter
|
||||||
bandit -r keystone -x tests
|
bandit -r keystone -x tests
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user