Merge "Remove support for PKI and PKIz tokens"
This commit is contained in:
commit
142e9e760a
|
@ -437,8 +437,8 @@ configuring the following property.
|
|||
:class:`keystone.token.providers.uuid.Provider`
|
||||
|
||||
|
||||
UUID, PKI, PKIZ, or Fernet?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
UUID or Fernet?
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Each token format uses different technologies to achieve various performance,
|
||||
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
|
||||
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
|
||||
`MessagePacked <http://msgpack.org/>`_ payload. The payload is then wrapped as
|
||||
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``.
|
||||
|
||||
.. 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
|
||||
access.
|
||||
|
||||
|
@ -1352,7 +1329,7 @@ through the normal REST API. At the moment, the following calls are supported:
|
|||
* ``mapping_engine``: Test your federation mapping rules.
|
||||
* ``mapping_populate``: Prepare domain-specific LDAP backend
|
||||
* ``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.
|
||||
* ``token_flush``: Purge expired tokens
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ Available commands:
|
|||
* ``mapping_populate``: Prepare domain-specific LDAP backend.
|
||||
* ``mapping_purge``: Purge the identity mapping table.
|
||||
* ``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.
|
||||
* ``token_flush``: Purge expired tokens.
|
||||
|
||||
|
|
|
@ -56,8 +56,6 @@
|
|||
# drivers should maintain their own equivalent document, and merge it with this
|
||||
# when their code merges into core.
|
||||
driver-impl-uuid=UUID tokens
|
||||
driver-impl-pki=PKI tokens
|
||||
driver-impl-pkiz=PKIZ tokens
|
||||
driver-impl-fernet=Fernet tokens
|
||||
|
||||
[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>
|
||||
--os-password=<password> token issue
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[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-project-domain-name=<domain> token issue
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[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>
|
||||
--os-password=<password> --os-domain-name=<domain> token issue
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[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>
|
||||
--os-password=<password> --os-trust-id=<trust> token issue
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[operation.create_token_using_oauth]
|
||||
|
@ -114,8 +104,6 @@ status=optional
|
|||
notes=OAuth access tokens can be exchanged for keystone tokens.
|
||||
cli=
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[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.
|
||||
cli=
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=missing
|
||||
|
||||
[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).
|
||||
cli=openstack token revoke
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[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.
|
||||
cli=
|
||||
driver-impl-uuid=complete
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=complete
|
||||
|
||||
[feature.offline_validation]
|
||||
|
@ -161,8 +143,6 @@ notes=Services using Keystone for authentication may want to validate tokens
|
|||
performance and scalability.
|
||||
cli=
|
||||
driver-impl-uuid=missing
|
||||
driver-impl-pki=complete
|
||||
driver-impl-pkiz=complete
|
||||
driver-impl-fernet=missing
|
||||
|
||||
[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`.
|
||||
cli=
|
||||
driver-impl-uuid=missing
|
||||
driver-impl-pki=partial
|
||||
driver-impl-pkiz=partial
|
||||
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):
|
||||
"""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
|
||||
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
|
||||
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
|
||||
Fernet tokens should never exceed this length in most deployments.
|
||||
However, if you are also using `keystone.conf [identity] driver = ldap`,
|
||||
|
@ -41,6 +37,4 @@ def symptom_unreasonable_max_token_size():
|
|||
"""
|
||||
return (
|
||||
'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)
|
||||
|
|
|
@ -95,13 +95,6 @@ class SmarterEncoder(jsonutils.json.JSONEncoder):
|
|||
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):
|
||||
"""Verify and truncate the provided password to the 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']
|
||||
|
||||
_CERTFILE = '/etc/keystone/ssl/certs/signing_cert.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.
|
||||
"""))
|
||||
|
||||
# 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',
|
||||
default=8192,
|
||||
default=255,
|
||||
help=utils.fmt("""
|
||||
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,
|
||||
and other HTTP implementations may break), depending on the size of your
|
||||
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).
|
||||
values. 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(
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import hashlib
|
||||
import sys
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import versionutils
|
||||
|
||||
from keystone.conf import constants
|
||||
from keystone.conf import utils
|
||||
|
||||
|
||||
|
@ -66,14 +63,12 @@ provider = cfg.StrOpt(
|
|||
help=utils.fmt("""
|
||||
Entry point for the token provider in the `keystone.token.provider` namespace.
|
||||
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
|
||||
`[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
|
||||
`keystone-manage fernet_setup` (also see the `keystone-manage fernet_rotate`
|
||||
command). `pki` and `pkiz` tokens can be validated offline, without making HTTP
|
||||
calls to keystone, but require that certificates be installed and distributed
|
||||
to facilitate signing tokens and later validating those signatures.
|
||||
command).
|
||||
"""))
|
||||
|
||||
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.
|
||||
"""))
|
||||
|
||||
# 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',
|
||||
default=True,
|
||||
|
@ -176,7 +151,6 @@ ALL_OPTS = [
|
|||
cache_time,
|
||||
revoke_by_id,
|
||||
allow_rescope_scoped_token,
|
||||
hash_algorithm,
|
||||
infer_roles,
|
||||
cache_on_issue,
|
||||
]
|
||||
|
|
|
@ -176,12 +176,6 @@ class RegionDeletionError(ForbiddenNotSecurity):
|
|||
"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):
|
||||
"""Security error exception.
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
"""Unified in-memory token model."""
|
||||
|
||||
from keystoneclient.common import cms
|
||||
from oslo_utils import reflection
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
@ -51,8 +50,7 @@ class KeystoneToken(dict):
|
|||
super(KeystoneToken, self).__init__(**token_data['token'])
|
||||
except KeyError:
|
||||
raise exception.UnsupportedTokenVersionException()
|
||||
self.short_id = cms.cms_hash_token(token_id,
|
||||
mode=CONF.token.hash_algorithm)
|
||||
self.token_id = token_id
|
||||
|
||||
if self.project_scoped and self.domain_scoped:
|
||||
raise exception.UnexpectedError(_('Found invalid token: scoped to '
|
||||
|
|
|
@ -18,7 +18,6 @@ import uuid
|
|||
import freezegun
|
||||
from oslo_config import fixture as config_fixture
|
||||
from oslo_log import log
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
|
||||
from keystone.common import fernet_utils
|
||||
|
@ -196,12 +195,6 @@ class UtilsTestCase(unit.BaseTestCase):
|
|||
TZ = 'UTC' + d
|
||||
_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):
|
||||
base_str = 'i am safe'
|
||||
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')
|
||||
|
||||
|
||||
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):
|
||||
def test_auth_invalid_user(self):
|
||||
"""Verify exception is raised if invalid user."""
|
||||
|
@ -880,20 +868,6 @@ class UUIDAuthWithRemoteUser(AuthWithRemoteUser, AuthTest):
|
|||
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):
|
||||
def setUp(self):
|
||||
super(AuthWithTrust, self).setUp()
|
||||
|
|
|
@ -854,33 +854,6 @@ class SqlTokenCacheInvalidationWithUUID(SqlTests,
|
|||
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
|
||||
# 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 keystone.common import openssl
|
||||
from keystone import exception
|
||||
from keystone.tests import unit
|
||||
from keystone.tests.unit import ksfixtures
|
||||
from keystone.tests.unit import rest
|
||||
from keystone import token
|
||||
|
||||
|
||||
SSLDIR = unit.dirs.tmp('ssl')
|
||||
|
@ -60,23 +59,14 @@ class CertSetupTestCase(rest.RestfulTestCase):
|
|||
ca_certs=ca_certs,
|
||||
ca_key=ca_key,
|
||||
keyfile=os.path.join(KEYDIR, 'signing_key.pem'))
|
||||
self.config_fixture.config(group='token', provider='pkiz')
|
||||
|
||||
def test_can_handle_missing_certs(self):
|
||||
controller = token.controllers.Auth()
|
||||
|
||||
self.config_fixture.config(group='signing', certfile='invalid')
|
||||
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)
|
||||
self.config_fixture.config(group='token', provider='fernet')
|
||||
self.useFixture(
|
||||
ksfixtures.KeyRepository(
|
||||
self.config_fixture,
|
||||
'fernet_tokens',
|
||||
CONF.fernet_tokens.max_active_keys
|
||||
)
|
||||
)
|
||||
|
||||
def test_create_pki_certs(self, rebuild=False):
|
||||
pki = openssl.ConfigurePKI(None, None, rebuild=rebuild)
|
||||
|
|
|
@ -23,7 +23,6 @@ from keystone import exception
|
|||
from keystone.models import revoke_model
|
||||
from keystone.revoke.backends import sql
|
||||
from keystone.tests import unit
|
||||
from keystone.tests.unit import test_backend_sql
|
||||
from keystone.token.providers import common
|
||||
|
||||
|
||||
|
@ -367,15 +366,6 @@ class RevokeTests(object):
|
|||
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):
|
||||
events.append(event)
|
||||
return event
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import datetime
|
||||
|
||||
from oslo_utils import timeutils
|
||||
from six.moves import reload_module
|
||||
|
||||
from keystone.common import dependency
|
||||
from keystone.common import utils
|
||||
|
@ -26,8 +25,6 @@ from keystone.tests.unit import ksfixtures
|
|||
from keystone.tests.unit.ksfixtures import database
|
||||
from keystone import token
|
||||
from keystone.token.providers import fernet
|
||||
from keystone.token.providers import pki
|
||||
from keystone.token.providers import pkiz
|
||||
from keystone.token.providers import uuid
|
||||
|
||||
|
||||
|
@ -759,14 +756,6 @@ class TestTokenProvider(unit.TestCase):
|
|||
self.config_fixture.config(group='token', provider='uuid')
|
||||
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()
|
||||
self.config_fixture.config(group='token', provider='fernet')
|
||||
self.assertIsInstance(token.provider.Manager().driver, fernet.Provider)
|
||||
|
@ -797,42 +786,3 @@ class TestTokenProvider(unit.TestCase):
|
|||
exception.TokenNotFound,
|
||||
self.token_provider_api.validate_token,
|
||||
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
|
||||
# under the License.
|
||||
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from keystoneclient.common import cms
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
from six.moves import http_client
|
||||
from testtools import matchers
|
||||
|
||||
from keystone.common import extension as keystone_extension
|
||||
import keystone.conf
|
||||
|
@ -1226,68 +1222,6 @@ class V2TestCase(object):
|
|||
def assertValidRevocationListResponse(self, response):
|
||||
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):
|
||||
# Enforce usage of boolean for 'enabled' field
|
||||
token = self.get_scoped_token()
|
||||
|
@ -1467,25 +1401,6 @@ class V2TestCaseFernet(V2TestCase, RestfulTestCase, CoreApiTests,
|
|||
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):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -1409,8 +1409,6 @@ class TokenAPITests(object):
|
|||
v3_token_data['token']['expires_at'])
|
||||
|
||||
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(
|
||||
user_id=self.default_domain_user['id'],
|
||||
password=self.default_domain_user['password'],
|
||||
|
@ -2426,74 +2424,6 @@ class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase):
|
|||
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,
|
||||
TokenDataTests):
|
||||
def config_overrides(self):
|
||||
|
@ -2510,9 +2440,7 @@ class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
|||
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'])
|
||||
self.assertFalse(cms.is_asn1_token(token_id))
|
||||
|
||||
|
||||
class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
|
||||
|
@ -2761,8 +2689,15 @@ class TestTokenRevokeById(test_v3.RestfulTestCase):
|
|||
super(TestTokenRevokeById, self).config_overrides()
|
||||
self.config_fixture.config(
|
||||
group='token',
|
||||
provider='pki',
|
||||
provider='fernet',
|
||||
revoke_by_id=False)
|
||||
self.useFixture(
|
||||
ksfixtures.KeyRepository(
|
||||
self.config_fixture,
|
||||
'fernet_tokens',
|
||||
CONF.fernet_tokens.max_active_keys
|
||||
)
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
"""Setup for Token Revoking Test Cases.
|
||||
|
@ -3507,8 +3442,15 @@ class TestTokenRevokeApi(TestTokenRevokeById):
|
|||
super(TestTokenRevokeApi, self).config_overrides()
|
||||
self.config_fixture.config(
|
||||
group='token',
|
||||
provider='pki',
|
||||
provider='fernet',
|
||||
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):
|
||||
events = events_response['events']
|
||||
|
@ -3772,24 +3714,6 @@ class TestAuthExternalDomainBehaviorWithUUID(AuthExternalDomainBehavior,
|
|||
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
|
||||
# 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')
|
||||
|
||||
|
||||
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):
|
||||
|
||||
def config_overrides(self):
|
||||
|
@ -3884,26 +3792,6 @@ class UUIDAuthKerberos(AuthExternalDomainBehavior, test_v3.RestfulTestCase):
|
|||
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
|
||||
# authentication so we don't inherit AuthExternalDomainBehavior here to test
|
||||
# it.
|
||||
|
@ -4991,26 +4879,6 @@ class TestAuthSpecificData(test_v3.RestfulTestCase):
|
|||
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):
|
||||
def config_overrides(self):
|
||||
super(TestTrustAuthFernetTokenProvider, self).config_overrides()
|
||||
|
|
|
@ -12,10 +12,8 @@
|
|||
|
||||
import copy
|
||||
import datetime
|
||||
import hashlib
|
||||
import uuid
|
||||
|
||||
from keystoneclient.common import cms
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
from six.moves import range
|
||||
|
@ -32,13 +30,7 @@ NULL_OBJECT = object()
|
|||
|
||||
class TokenTests(object):
|
||||
def _create_token_id(self):
|
||||
# Use a token signed by the cms module
|
||||
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)
|
||||
return uuid.uuid4().hex
|
||||
|
||||
def _assert_revoked_token_list_matches_token_persistence(
|
||||
self, revoked_token_id_list):
|
||||
|
@ -367,30 +359,6 @@ class TokenTests(object):
|
|||
self.assertIn(token_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):
|
||||
token_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
|
||||
from keystone import exception
|
||||
from keystone.i18n import _LW
|
||||
from keystone.token import utils
|
||||
|
||||
|
||||
CONF = keystone.conf.CONF
|
||||
|
@ -52,7 +51,7 @@ class PersistenceManager(manager.Manager):
|
|||
super(PersistenceManager, self).__init__(CONF.token.driver)
|
||||
|
||||
def get_token(self, token_id):
|
||||
return self._get_token(utils.generate_unique_id(token_id))
|
||||
return self._get_token(token_id)
|
||||
|
||||
@MEMOIZE
|
||||
def _get_token(self, token_id):
|
||||
|
@ -60,23 +59,21 @@ class PersistenceManager(manager.Manager):
|
|||
return self.driver.get_token(token_id)
|
||||
|
||||
def create_token(self, token_id, data):
|
||||
unique_id = utils.generate_unique_id(token_id)
|
||||
data_copy = copy.deepcopy(data)
|
||||
data_copy['id'] = unique_id
|
||||
ret = self.driver.create_token(unique_id, data_copy)
|
||||
data_copy['id'] = token_id
|
||||
ret = self.driver.create_token(token_id, data_copy)
|
||||
if MEMOIZE.should_cache(ret):
|
||||
# NOTE(morganfainberg): when doing a cache set, you must pass the
|
||||
# same arguments through, the same as invalidate (this includes
|
||||
# "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
|
||||
|
||||
def delete_token(self, token_id):
|
||||
if not CONF.token.revoke_by_id:
|
||||
return
|
||||
unique_id = utils.generate_unique_id(token_id)
|
||||
self.driver.delete_token(unique_id)
|
||||
self._invalidate_individual_token_cache(unique_id)
|
||||
self.driver.delete_token(token_id)
|
||||
self._invalidate_individual_token_cache(token_id)
|
||||
self.invalidate_revocation_list()
|
||||
|
||||
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,
|
||||
consumer_id)
|
||||
for token_id in token_list:
|
||||
unique_id = utils.generate_unique_id(token_id)
|
||||
self._invalidate_individual_token_cache(unique_id)
|
||||
self._invalidate_individual_token_cache(token_id)
|
||||
self.invalidate_revocation_list()
|
||||
|
||||
@REVOCATION_MEMOIZE
|
||||
|
|
|
@ -29,7 +29,6 @@ from keystone.i18n import _, _LE
|
|||
from keystone.models import token_model
|
||||
from keystone import notifications
|
||||
from keystone.token import persistence
|
||||
from keystone.token import utils
|
||||
|
||||
|
||||
CONF = keystone.conf.CONF
|
||||
|
@ -166,10 +165,7 @@ class Manager(manager.Manager):
|
|||
# Otherwise the information about the token must be in the token
|
||||
# id.
|
||||
if self._needs_persistence:
|
||||
unique_id = utils.generate_unique_id(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)
|
||||
token_ref = self._persistence.get_token(token_id)
|
||||
# Overload the token_id variable to be a token reference
|
||||
# instead.
|
||||
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 =
|
||||
fernet = keystone.token.providers.fernet:Provider
|
||||
uuid = keystone.token.providers.uuid:Provider
|
||||
pki = keystone.token.providers.pki:Provider
|
||||
pkiz = keystone.token.providers.pkiz:Provider
|
||||
|
||||
keystone.trust =
|
||||
sql = keystone.trust.backends.sql:Trust
|
||||
|
|
Loading…
Reference in New Issue